package main import ( "bufio" "fmt" "os" "path" "strings" ) var infhcache = make(map[string]string, 1024) func infh(name string) string { if s, ok := infhcache[name]; ok { return s } s := " [" + name + "]" infhcache[name] = s return s } func scanHeader(name string, scan *bufio.Scanner) { ln := 0 var regionfile *os.File symtab := symbolTable{ "ZE_APICALL": symbol{symbolTypeConst, "ZE_APICALL", []string{""}}, "ZE_APIEXPORT": symbol{symbolTypeConst, "ZE_APIEXPORT", []string{""}}, "ZE_DLLEXPORT": symbol{symbolTypeConst, "ZE_DLLEXPORT", []string{""}}, } fileheadersb := strings.Builder{} region := "" for scan.Scan() { ln++ t := scan.Text() switch { // file headers case strings.HasPrefix(t, "/*") || strings.HasPrefix(t, " *") || strings.HasPrefix(t, " */"): fileheadersb.WriteString(t) fileheadersb.WriteString("\n") // pragma start case strings.HasPrefix(t, "#pragma region "): region = strings.TrimSpace(t[15:]) if region == "" { panic(fmt.Sprintf("%s L%d: unexpected empty region", name, ln)) } fmt.Println(infh(name), "scanning region", region) _ = os.RemoveAll(name) err := os.MkdirAll(name, 0755) if err != nil { panic(fmt.Sprintf("%s L%d: cannot create region folder %s, err: %v", name, ln, region, err)) } f, err := os.Create(path.Join(name, region+".go")) if err != nil { panic(fmt.Sprintf("%s L%d: cannot create region %s, err: %v", name, ln, region, err)) } f.WriteString("// Code generated by gen. DO NOT EDIT.\n\n") f.WriteString(fileheadersb.String()) f.WriteString("\n") f.WriteString("package ") f.WriteString(name) f.WriteString("\n\n") regionfile = f // block barrier case strings.HasPrefix(t, "///////////////////////////////////////////////////////////////////////////////"): fmt.Println(" [scan] enter", region, "block") ln = scanBlocks(name, scan, regionfile, ln, symtab) fmt.Println(" [scan] leave", region, "block") // pragma end case strings.HasPrefix(t, "#pragma endregion"): fmt.Println(infh(name), "close region", regionfile.Name()) _ = regionfile.Close() regionfile = nil // skip outer # case strings.HasPrefix(t, "#") || t == "" || strings.HasPrefix(t, "// ") || strings.HasPrefix(t, "extern "): fmt.Println(" [scan] skip", t) continue default: panic(fmt.Sprintf("%s L%d: unexpected line %s", name, ln, t)) } } } func checkSymbolName( symtab symbolTable, ln int, name, sname, goname string, sb *strings.Builder, f *os.File, eq func() symbol) { if _, ok := symtab[sname]; ok { panic(fmt.Sprintf("%s L%d: func #define %s has been defined", name, ln, sname)) } symtab[sname] = eq() if sb.Len() == 0 { panic(fmt.Sprintf("%s L%d: unexpected non-comment for symbol %s", name, ln, sname)) } brief := " " + goname if goname != sname { brief = fmt.Sprint(brief, " (", sname, ")") } f.WriteString(strings.Replace(sb.String(), "/ @brief", brief, 1)) sb.Reset() } func scanBlocks( name string, scan *bufio.Scanner, f *os.File, ln int, symtab symbolTable, ) int { sb := strings.Builder{} skip2nextblk := false //TODO: check logic ifdepth := 0 isparsing := func() bool { //TODO: more condition return ifdepth > 0 } for scan.Scan() { ln++ t := scan.Text() switch { // block end case t == "": if isparsing() { continue } if sb.Len() != 0 { panic(fmt.Sprintf("%s L%d: unexpected non-0 sb at block end: %s", name, ln, &sb)) } return ln case skip2nextblk: continue // is definition's comment case strings.HasPrefix(t, "/// "): sb.WriteString(t) sb.WriteString("\n") case strings.HasPrefix(t, "#if"): if len(t) <= 8 { panic(fmt.Sprintf("%s L%d: unexpected short #if", name, ln)) } if t[3] == ' ' { // is platform related judgement skip2nextblk = true continue } if t[:8] != "#ifndef " { panic(fmt.Sprintf("%s L%d: unexpected #if type %s", name, ln, t)) } sname := strings.TrimSpace(t[8:]) _, ok := symtab[sname] if ok { ln = skip2endif(scan, ln) continue } ifdepth++ case strings.HasPrefix(t, "#endif"): ifdepth-- if ifdepth < 0 { panic(fmt.Sprintf("%s L%d: unexpected unpaired #endif", name, ln)) } case strings.HasPrefix(t, "#define "): if !strings.Contains(t, "(") { // is const define argseval := trimEmptyStringArray(strings.Split(t[8:], " ")) if len(argseval) != 2 { panic(fmt.Sprintf("%s L%d: unexpected const #define line %s", name, ln, t)) } sname := strings.TrimSpace(argseval[0]) val := strings.TrimSpace(argseval[1]) checkSymbolName(symtab, ln, name, sname, sname, &sb, f, func() symbol { return newSymbolConst(sname, val) }) f.WriteString("const ") f.WriteString(sname) f.WriteString(" = ") f.WriteString(val) f.WriteString("\n\n") continue } sname, argseval, ok := strings.Cut(t[8:], "(") if !ok { panic(fmt.Sprintf("%s L%d: unexpected #define line %s", name, ln, t)) } args, n, err := getInsideRoundBrakets(argseval) if err != nil { panic(fmt.Sprintf("%s L%d: unexpected args bracket err: %v", name, ln, err)) } sname = strings.TrimSpace(sname) args = strings.TrimSpace(args) eval := strings.TrimSpace(argseval[n+1:]) checkSymbolName(symtab, ln, name, sname, sname, &sb, f, func() symbol { return newSymbolFunc(sname, args, eval) }) f.WriteString("func ") f.WriteString(sname) f.WriteString("[T ~int | ~uint64 | ~uintptr](") f.WriteString(strings.Join(strings.Split(args, ","), " T,")) f.WriteString(" T) T {\n\treturn ") f.WriteString(eval) f.WriteString("\n}\n\n") case strings.HasPrefix(t, "typedef "): s, newln := get1sentence(t, scan, ln) if newln < 0 { panic(fmt.Sprintf("%s L%d: unexpected sentence end from", name, ln)) } ln = newln typs := trimEmptyStringArray(strings.Split(s[8:], " ")) if len(typs) == 0 { panic(fmt.Sprintf("%s L%d: unexpected typdef line %s", name, ln, t)) } if strings.TrimSpace(typs[0]) == "struct" { if len(typs) != 3 || !strings.Contains(typs[1], "handle_t") || !strings.Contains(typs[2], "*") { panic(fmt.Sprintf("%s L%d: unexpected typdef line %s", name, ln, t)) } typs = typs[1:] typs[0] = "uintptr" typs[1] = strings.TrimPrefix(strings.TrimSpace(typs[1]), "*") } if len(typs) != 2 { panic(fmt.Sprintf("%s L%d: unexpected typdef line %s", name, ln, t)) } sname := strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(typs[1]), ";")) val := us2camel(strings.TrimSuffix(sname, "_t")) origtyp := strings.TrimSuffix(strings.TrimSpace(typs[0]), "_t") checkSymbolName(symtab, ln, name, sname, val, &sb, f, func() symbol { return newSymbolConst(sname, val) }) f.WriteString("type ") f.WriteString(val) f.WriteString(" ") f.WriteString(origtyp) f.WriteString("\n\n") } } return ln }