mirror of
https://github.com/fumiama/gozel.git
synced 2026-06-05 00:10:24 +08:00
799 lines
24 KiB
Go
799 lines
24 KiB
Go
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
|
|
}
|