package main import ( "bufio" "bytes" "fmt" "io" "os" "path" "strconv" "strings" "unicode" ) const ( numbergenerics = "~int| ~uint32 | ~uint64 | ~uintptr" ) var ( typemap = map[string]string{ "char": "byte", "char*": "*byte", "char *": "*byte", "const char*": "*byte", "const char *": "*byte", "char**": "**byte", "const char**": "**byte", "char***": "***byte", "const char***": "***byte", "void*": "unsafe.Pointer", "void *": "unsafe.Pointer", "const void*": "unsafe.Pointer", "void**": "*unsafe.Pointer", "void **": "*unsafe.Pointer", "const void**": "*unsafe.Pointer", "void***": "**unsafe.Pointer", "void ***": "**unsafe.Pointer", "const void***": "**unsafe.Pointer", "size_t": "uintptr", "size_t*": "*uintptr", "size_t *": "*uintptr", "int": "int32", "unsigned int": "uint32", "float": "float32", "double": "float64", "float*": "*float32", "double*": "*float64", } unsafeExcludeRegions = map[string]struct{}{ "core_bfloat16conversions": {}, "core_globaloffset": {}, "core_linkonceodr": {}, "core_subgroups": {}, "tols_metricRuntimeEnableDisable": {}, } zecallExcludeRegions = map[string]struct{}{ "core_bandwidth": {}, "core_bfloat16conversions": {}, "core_CacheLineSize": {}, "core_callbacks": {}, "core_common": {}, "core_counterbasedeventpool": {}, "core_deviceipversion": {}, "core_deviceLUID": {}, "core_deviceusablememproperties": {}, "core_driverDDIHandles": {}, "core_EUCount": {}, "core_externalMemMap": {}, "core_floatAtomics": {}, "core_imageFormatSupport": {}, "core_imageviewplanar": {}, "core_kernelMaxGroupSizeProperties": {}, "core_linkonceodr": {}, "core_memoryCompressionHints": {}, "core_memoryProperties": {}, "core_powersavinghint": {}, "core_program": {}, "core_raytracing": {}, "core_relaxedAllocLimits": {}, "core_SRGB": {}, "core_subAllocationsProperties": {}, "core_subgroups": {}, "sysm_common": {}, "sysm_eccState": {}, "sysm_memoryBwCounterValidBits": {}, "sysm_memPageOfflineState": {}, "sysm_powerDomainProperties": {}, "tols_common": {}, "tols_metricExportMemory": {}, } unionSizes = map[string]int{ "zet_value_t": 8, "zet_debug_event_info_t": 32, "zet_value_info_exp_t": 16, } ) 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 fileheadersb := strings.Builder{} region := "" fsz := int64(0) 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) k := fmt.Sprint(name, "_", region) f, err := os.Create(path.Join("gozel", fmt.Sprint(k, ".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 cmd/gen. DO NOT EDIT.\n\n") f.WriteString(fileheadersb.String()) f.WriteString("\n") f.WriteString("package gozel\n\n") noimport := true sb := strings.Builder{} sb.WriteString("import (") if _, ok := unsafeExcludeRegions[k]; !ok { sb.WriteString("\n\t\"unsafe\"\n") noimport = false } if _, ok := zecallExcludeRegions[k]; !ok { sb.WriteString("\n\t\"github.com/fumiama/gozel/internal/zecall\"\n") noimport = false } sb.WriteString(")\n\n") if !noimport { f.WriteString(sb.String()) } regionfile = f stat, err := f.Stat() if err != nil { panic(fmt.Sprintf("%s L%d: cannot stat region file %s, err: %v", name, ln, region, err)) } fsz = stat.Size() // block barrier case strings.HasPrefix(t, "///////////////////////////////////////////////////////////////////////////////"): fmt.Println(" [scan] enter", region, "block") ln = scanBlocks(name, scan, regionfile, ln) fmt.Println(" [scan] leave", region, "block") // pragma end case strings.HasPrefix(t, "#pragma endregion"): nm := regionfile.Name() stat, err := regionfile.Stat() if err != nil { panic(fmt.Sprintf("%s L%d: cannot stat region file %s, err: %v", name, ln, region, err)) } sz := stat.Size() fmt.Println(infh(name), "close region", nm) _ = regionfile.Close() if fsz == sz { fmt.Println("[warn] delete unchanged region file", nm) _ = os.Remove(nm) } regionfile = nil // skip outer # case strings.HasPrefix(t, "#") || t == "" || strings.HasPrefix(t, "// ") || strings.Contains(t, `extern "C"`): fmt.Println(" [scan] skip", t) continue default: panic(fmt.Sprintf("%s L%d: unexpected line %s", name, ln, t)) } } } func checkSymbolName( ln int, name, sname, goname string, sb *strings.Builder, f *os.File, eq func() *symbol) bool { if _, ok := symtab[sname]; ok { panic(fmt.Sprintf("%s L%d: func #define %s has been defined", name, ln, sname)) } enumsname := strings.TrimSuffix(sname, "_t") + "s_t" if _, ok := symtab[enumsname]; ok { fmt.Println("[warn] redirect name", sname, "to", enumsname) return true } 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() return false } func scanBlocks( name string, scan *bufio.Scanner, f *os.File, ln int, ) int { sb := strings.Builder{} ppskip2nextblk := false ppifdepth := 0 isparsing := func() bool { return ppifdepth > 0 } for scan.Scan() { ln++ t := scan.Text() switch { // block end case t == "": if isparsing() { continue } if sb.Len() != 0 { fmt.Printf("[warn] %s L%d: non-0 sb at block end: %s\n", name, ln, &sb) } return ln case ppskip2nextblk: 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 ppskip2nextblk = 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 } ppifdepth++ case strings.HasPrefix(t, "#endif"): ppifdepth-- if ppifdepth < 0 { panic(fmt.Sprintf("%s L%d: unexpected unpaired #endif", name, ln)) } case strings.HasPrefix(t, "#define "): argn, argv, ok := strings.Cut(t[8:], " ") if !ok { panic(fmt.Sprintf("%s L%d: unexpected short #define line %s", name, ln, t)) } if !strings.Contains(argn, "(") { // is const define sname := strings.TrimSpace(argn) val := symtab.apply(strings.TrimSpace(argv)) checkSymbolName(ln, name, sname, sname, &sb, f, func() *symbol { return newSymbolConst(sname, val, symbolSubTypeDefine) }) 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(ln, name, sname, sname, &sb, f, func() *symbol { return newSymbolFunc(sname, args, eval, symbolSubTypeDefine) }) f.WriteString("func ") f.WriteString(sname) f.WriteString("[T ") f.WriteString(numbergenerics) f.WriteString("](") 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 "): ln = scanTypedef(name, scan, f, ln, t, &sb) case strings.HasPrefix(t, "ZE_APIEXPORT "): if !strings.HasSuffix(t, " ZE_APICALL") { panic(fmt.Sprintf("%s L%d: unexpected func line %s", name, ln, t)) } ln = scanFunc(name, scan, f, ln, t, &sb) case strings.HasPrefix(t, "static const ") && strings.HasSuffix(t, "= {"): t = strings.TrimSpace(t[13 : len(t)-3]) i := strings.LastIndex(t, " ") if i <= 0 { panic(fmt.Sprintf("%s L%d: unexpected short var %s", name, ln, t)) } typ := symtab.apply(strings.TrimSpace(t[:i])) rnam := []rune(strings.TrimSpace(t[i+1:])) rnam[0] = unicode.ToUpper(rnam[0]) nam := string(rnam) f.WriteString(strings.Replace(sb.String(), "/ @brief", " "+nam, 1)) sb.Reset() f.WriteString("var ") f.WriteString(nam) f.WriteString(" = ") f.WriteString(typ) f.WriteString("{") for { f.WriteString("\n") s, isfin := scanln(name, scan, &ln) if isfin { break } s = strings.TrimSpace(s) f.WriteString("\t") if strings.HasPrefix(s, "0,") && strings.Contains(s, "///< p") { f.WriteString("nil,") f.WriteString(s[2:]) } else { f.WriteString(s) } } f.WriteString("}\n\n") default: panic(fmt.Sprintf("%s L%d: unexpected line %s", name, ln, t)) } } return ln } func scanTypedef( name string, scan *bufio.Scanner, f *os.File, ln int, firstln string, sb *strings.Builder, ) int { s, newln := get1sentence(firstln, scan, ln) if newln < 0 { panic(fmt.Sprintf("%s L%d: unexpected sentence end from", name, ln)) } ln = newln if strings.Contains(s, "\n") { // multi-line typedef lines := strings.Split(s, "\n") if strings.Contains(lines[0], " (*") || strings.Contains(lines[0], "ZE_APICALL") { // is func ptr typedef _, remains, ok := strings.Cut(lines[0], " (*") if !ok { _, remains, ok = strings.Cut(lines[0], "ZE_APICALL") if !ok { panic(fmt.Sprintf("%s L%d: unexpected func typdef line %s", name, ln, firstln)) } } fnname, _, _ := strings.Cut(strings.TrimPrefix(strings.TrimSpace(remains), "*"), "_t") fnname = strings.TrimSpace(fnname) if fnname == "" { panic(fmt.Sprintf("%s L%d: unexpected func typdef line %s", name, ln, firstln)) } goname := us2camel(fnname) fnname += "_t" checkSymbolName(ln, name, fnname, goname, sb, f, func() *symbol { return newSymbolConst(fnname, goname, symbolSubTypeFuncPtr) }) f.WriteString("// gozel warn: please use C function pointer loaded from C library!\n") f.WriteString("type ") f.WriteString(goname) f.WriteString(" uintptr\n\n") return ln } if len(lines) < 4 { panic(fmt.Sprintf("%s L%d: unexpected short multi typdef line %s", name, ln, firstln)) } if lines[1] != "{" { panic(fmt.Sprintf("%s L%d: unexpected non-{ multi typdef line %s", name, ln, firstln)) } switch { case strings.Contains(lines[0], " struct "): fsb := bytes.NewBuffer(make([]byte, 0, 256)) for i, stat := range lines[2:] { if strings.HasPrefix(stat, "}") { lines = lines[2+i:] break } fsb.WriteString("\n") if stat == "" { continue } stat = strings.TrimSpace(stat) vname := "" c := "" switch { case strings.HasPrefix(stat, "///< "): fsb.Truncate(fsb.Len() - 1) fsb.WriteString(stat[4:]) case strings.HasPrefix(stat, "char ") || strings.HasPrefix(stat, "void* ") || strings.HasPrefix(stat, "const void* ") || strings.HasPrefix(stat, "int ") || strings.HasPrefix(stat, "const void** ") || strings.HasPrefix(stat, "const char* ") || strings.HasPrefix(stat, "const char** ") || strings.HasPrefix(stat, "float ") || strings.HasPrefix(stat, "double ") || strings.HasPrefix(stat, "void** ") || strings.HasPrefix(stat, "const void*** ") || strings.HasPrefix(stat, "void*** ") || strings.HasPrefix(stat, "const char*** ") || strings.HasPrefix(stat, "char** ") || strings.HasPrefix(stat, "char*** "): remains, sz := "", "" ok := false remains, c, ok = strings.Cut(stat, ";") if !ok { panic(fmt.Sprintf("%s L%d: unsupported non-end line %s", name, ln, stat)) } c = strings.TrimPrefix(strings.TrimSpace(c), "//") remains = strings.TrimSpace(remains) i := strings.LastIndex(remains, " ") vname = remains[i+1:] tn := strings.TrimSpace(remains[:i]) tname, ok := typemap[tn] if !ok { panic(fmt.Sprintf("%s L%d: unsupported type %s", name, ln, tname)) } vname, sz, ok = strings.Cut(vname, "[") vname = us2camel(strings.TrimSpace(vname)) fsb.WriteString("\t") if ok { // is array fsb.WriteString(vname) fsb.WriteString(" [") fsb.WriteString(sz) fsb.WriteString(tname) } else { fsb.WriteString(vname) fsb.WriteString(" ") fsb.WriteString(tname) } case strings.Contains(stat, "_t "): remains, sz := "", "" ok := false remains, c, ok = strings.Cut(stat, ";") if !ok { panic(fmt.Sprintf("%s L%d: unsupported non-end line %s", name, ln, stat)) } c = strings.TrimPrefix(strings.TrimSpace(c), "//") tname, remains, ok := strings.Cut(remains, "_t ") if !ok { panic(fmt.Sprintf("%s L%d: unexpected statement %s", name, ln, stat)) } tname = strings.TrimSpace(strings.ReplaceAll(tname, "const ", "")) k := tname + "_t" if symtab.contains(k) { tname = symtab[k].replace(k) } else if convname, ok := typemap[k]; ok { tname = convname } vname, sz, ok = strings.Cut(remains, "[") vname = us2camel(strings.TrimSpace(vname)) fsb.WriteString("\t") if ok { // is array fsb.WriteString(vname) fsb.WriteString(" [") fsb.WriteString(sz) fsb.WriteString(tname) } else { fsb.WriteString(vname) fsb.WriteString(" ") fsb.WriteString(tname) } case strings.Contains(stat, "_t* "): remains, sz := "", "" ok := false remains, c, ok = strings.Cut(stat, ";") if !ok { panic(fmt.Sprintf("%s L%d: unsupported non-end line %s", name, ln, stat)) } c = strings.TrimPrefix(strings.TrimSpace(c), "//") tname, remains, ok := strings.Cut(remains, "_t* ") if !ok { panic(fmt.Sprintf("%s L%d: unexpected statement %s", name, ln, stat)) } tname = strings.TrimSpace(strings.ReplaceAll(tname, "const ", "")) k := tname + "_t" if symtab.contains(k) { tname = symtab[k].replace(k) } else if convname, ok := typemap[k]; ok { tname = convname } vname, sz, ok = strings.Cut(remains, "[") vname = us2camel(strings.TrimSpace(vname)) fsb.WriteString("\t") if ok { // is array fsb.WriteString(vname) fsb.WriteString(" [") fsb.WriteString(sz) fsb.WriteString("*") fsb.WriteString(tname) } else { fsb.WriteString(vname) fsb.WriteString(" *") fsb.WriteString(tname) } case strings.Contains(stat, "_t** "): remains, sz := "", "" ok := false remains, c, ok = strings.Cut(stat, ";") if !ok { panic(fmt.Sprintf("%s L%d: unsupported non-end line %s", name, ln, stat)) } c = strings.TrimPrefix(strings.TrimSpace(c), "//") tname, remains, ok := strings.Cut(remains, "_t** ") if !ok { panic(fmt.Sprintf("%s L%d: unexpected statement %s", name, ln, stat)) } tname = strings.TrimSpace(strings.ReplaceAll(tname, "const ", "")) k := tname + "_t" if symtab.contains(k) { tname = symtab[k].replace(k) } else if convname, ok := typemap[k]; ok { tname = convname } vname, sz, ok = strings.Cut(remains, "[") vname = us2camel(strings.TrimSpace(vname)) fsb.WriteString("\t") if ok { // is array fsb.WriteString(vname) fsb.WriteString(" [") fsb.WriteString(sz) fsb.WriteString("**") fsb.WriteString(tname) } else { fsb.WriteString(vname) fsb.WriteString(" **") fsb.WriteString(tname) } default: panic(fmt.Sprintf("%s L%d: unexpected statement %s", name, ln, stat)) } if c != "" { fsb.WriteString("\t// ") fsb.WriteString(strings.Replace(c, "/<", vname, 1)) } } if len(lines) != 1 { panic(fmt.Sprintf("%s L%d: unexpected len > 1 last lines %s", name, ln, strings.Join(lines, "\n"))) } if !strings.HasPrefix(lines[0], "}") { panic(fmt.Sprintf("%s L%d: unexpected last line %s", name, ln, lines[0])) } sname := strings.TrimSuffix(strings.TrimSpace(lines[0][1:]), ";") val := us2camel(strings.TrimSuffix(sname, "_t")) checkSymbolName(ln, name, sname, val, sb, f, func() *symbol { return newSymbolConst(sname, val, symbolSubTypeLargeStruct) }) f.WriteString("type ") f.WriteString(val) f.WriteString(" struct {") _, _ = io.Copy(f, fsb) f.WriteString("\n}\n\n") return ln case strings.Contains(lines[0], " enum "): fsb := strings.Builder{} iscontinouscomment := false for i, stat := range lines[2:] { if strings.HasPrefix(stat, "}") { lines = lines[2+i:] break } fsb.WriteString("\n") if stat == "" { continue } stat = strings.TrimSpace(stat) if strings.HasPrefix(stat, "//") { if !iscontinouscomment { fsb.WriteString("\n") } fsb.WriteString("\t") fsb.WriteString(stat) iscontinouscomment = true continue } if iscontinouscomment { fsb.WriteString("\n") } iscontinouscomment = false constval, comment, ok := strings.Cut(stat, "//") if !ok { panic(fmt.Sprintf("%s L%d: unexpected enum line %s", name, ln, stat)) } cname, _, _ := strings.Cut(constval, "=") fsb.WriteString("\t") fsb.WriteString(strings.TrimSuffix(strings.TrimSpace(constval), ",")) fsb.WriteString("\t// ") fsb.WriteString(strings.Replace(comment, "/<", strings.TrimSpace(cname), 1)) } if len(lines) != 1 { panic(fmt.Sprintf("%s L%d: unexpected len > 1 last lines %s", name, ln, strings.Join(lines, "\n"))) } if !strings.HasPrefix(lines[0], "}") { panic(fmt.Sprintf("%s L%d: unexpected last line %s", name, ln, lines[0])) } sname := strings.TrimSuffix(strings.TrimSpace(lines[0][1:]), ";") val := us2camel(strings.TrimSuffix(sname, "_t")) redirect := checkSymbolName(ln, name, sname, val, sb, f, func() *symbol { return newSymbolConst(sname, val, symbolSubTypeEnum) }) replaces := "" if !redirect { f.WriteString("type ") f.WriteString(val) f.WriteString(" uint32\nconst (") replaces = " " + val + " =" } else { _, _ = f.Seek(-1, io.SeekCurrent) f.WriteString("const (") replaces = " " + val + "s =" } vars := strings.ReplaceAll(fsb.String(), " =", replaces) if strings.Contains(vars, "(") { vars = symtab.apply(vars) } f.WriteString(vars) f.WriteString("\n)\n\n") return ln // tricky: fallthrough union to the single line though it is not } } // single-line typedef, empty struct or type alias, replace with "type" statement typs := trimEmptyStringArray(strings.Split(s[8:], " ")) if len(typs) == 0 { panic(fmt.Sprintf("%s L%d: unexpected single typdef line %s", name, ln, firstln)) } if strings.TrimSpace(typs[0]) == "struct" { if len(typs) != 3 || !strings.Contains(typs[1], "handle_t") || !strings.Contains(typs[2], "*") { if symtab.contains(strings.TrimSuffix(typs[2], ";")) { fmt.Printf("[warn] %s L%d: skip duplicated single typdef %s\n", name, ln, strings.Join(typs, "_____")) } else { fmt.Printf("[warn] %s L%d: skip future expected single typdef %s\n", name, ln, strings.Join(typs, "_____")) } return ln } typs = typs[1:] typs[0] = "uintptr" typs[1] = strings.TrimPrefix(strings.TrimSpace(typs[1]), "*") } else if strings.TrimSpace(typs[0]) == "union" { origtyp := strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(typs[len(typs)-1]), ";")) sz, ok := unionSizes[origtyp] if !ok { panic(fmt.Sprintf("%s L%d: unknown union size of %s", name, ln, origtyp)) } typs = []string{"[" + strconv.Itoa(sz) + "]byte", origtyp} } if len(typs) != 2 { panic(fmt.Sprintf("%s L%d: unexpected typdef line %s", name, ln, firstln)) } sname := strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(typs[1]), ";")) val := us2camel(strings.TrimSuffix(sname, "_t")) origtyp := strings.TrimSuffix(symtab.apply(strings.TrimSpace(typs[0])), "_t") checkSymbolName(ln, name, sname, val, sb, f, func() *symbol { return newSymbolConst(sname, val, symbolSubTypeEmptyStruct) }) f.WriteString("type ") f.WriteString(val) f.WriteString(" ") f.WriteString(origtyp) f.WriteString("\n\n") return ln } func scanFunc( name string, scan *bufio.Scanner, f *os.File, ln int, firstln string, sb *strings.Builder, ) int { //TODO: register func rettyp := strings.TrimSpace(firstln[13 : len(firstln)-11]) rettyp = strings.TrimSuffix(symtab.apply(strings.TrimSpace(rettyp)), "_t") fnname, isfin := scanln(name, scan, &ln) if isfin { panic(fmt.Sprintf("%s L%d: unexpected early end func name line %s", name, ln, fnname)) } if !strings.HasSuffix(fnname, "(") { panic(fmt.Sprintf("%s L%d: unexpected malformed func name line %s", name, ln, fnname)) } origfnname := strings.TrimSpace(fnname[:len(fnname)-1]) fnname = origfnname rf := []rune(fnname) rf[0] = unicode.ToUpper(rf[0]) fnname = string(rf) if sb.Len() == 0 { panic(fmt.Sprintf("%s L%d: unexpected non-comment for func %s", name, ln, fnname)) } brief := " " + fnname f.WriteString(strings.Replace(sb.String(), "/ @brief", brief, 1)) sb.Reset() f.WriteString("func ") f.WriteString(fnname) f.WriteString("(") argsb := strings.Builder{} for { argln, isfin := scanln(name, scan, &ln) if isfin { break } argln = strings.TrimSpace(argln) if strings.HasPrefix(argln, "///< ") { f.WriteString(argln[4:]) continue } if argln == "void" { continue } argtypnam, argcomment, ok := strings.Cut(argln, "//") if !ok { panic(fmt.Sprintf("%s L%d: unexpected non-comment func arg line %s", name, ln, argln)) } argtypnam = strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(argtypnam), ",")) argcomment = strings.TrimSpace(argcomment) i := strings.LastIndex(argtypnam, " ") if i < 0 { panic(fmt.Sprintf("%s L%d: unexpected short func arg line %s", name, ln, argln)) } argnam := strings.TrimSpace(argtypnam[i+1:]) if argnam == "type" { // go keywords argnam = "typ" } argsb.WriteString(", uintptr(") argtyp := strings.TrimSpace(strings.ReplaceAll(argtypnam[:i], "const ", "")) isp := strings.HasSuffix(argtyp, "*") // is pointer pmark := "*" if strings.HasSuffix(argtyp, "**") { // is pointer's pointer pmark = "**" } convtyp, ok := typemap[argtyp] if ok { argtyp = convtyp } if isp { if !ok { argtyp = pmark + strings.TrimSpace(argtyp[:len(argtyp)-len(pmark)]) } argsb.WriteString("unsafe.Pointer(") } else { sym, ok := symtab[argtyp] if ok && sym.sstype == symbolSubTypeLargeStruct && !strings.HasPrefix(argnam, "p") { isp = true argtyp = pmark + argtyp argcomment += " (gozel hack: converted to a hidden pointer from a struct value)" argsb.WriteString("unsafe.Pointer(") } } argsb.WriteString(argnam) argsb.WriteString(")") if isp { argsb.WriteString(")") } f.WriteString("\n\t") f.WriteString(argnam) f.WriteString(" ") f.WriteString(strings.TrimSuffix(symtab.apply(argtyp), "_t")) f.WriteString(",") f.WriteString("\t// ") f.WriteString(strings.Replace(argcomment, "/<", argnam, 1)) } f.WriteString("\n) (") f.WriteString(rettyp) f.WriteString(", error) {\n\treturn zecall.Call[") f.WriteString(rettyp) f.WriteString("](\"") f.WriteString(origfnname) f.WriteString("\"") f.WriteString(argsb.String()) f.WriteString(")\n}\n\n") addAPI(origfnname) return ln }