mirror of
https://github.com/fumiama/gozel.git
synced 2026-06-10 11:10:23 +08:00
refactor: mv gen into cmd folder
This commit is contained in:
80
cmd/gen/main.go
Normal file
80
cmd/gen/main.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
spec := flag.String("spec", "v1.28.2", "The l0 loader spec version tag starting with v or a local level-zero path for dev.")
|
||||
flag.Parse()
|
||||
|
||||
var specdir fs.FS
|
||||
|
||||
if strings.HasPrefix(*spec, "v") {
|
||||
ver := (*spec)[1:]
|
||||
u := fmt.Sprintf("https://github.com/oneapi-src/level-zero/releases/download/v%s/level-zero-win-sdk-%s.zip", ver, ver)
|
||||
fmt.Println("[main] downloading spec from", u)
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
_ = resp.Body.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
specdir = r
|
||||
} else {
|
||||
fmt.Println("[main] reading local spec from", *spec)
|
||||
specdir = os.DirFS(*spec)
|
||||
}
|
||||
|
||||
fmt.Println("[main] parsing core APIs...")
|
||||
f, err := specdir.Open("include/level_zero/ze_api.h")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
scanHeader("core", bufio.NewScanner(f))
|
||||
_ = f.Close()
|
||||
fmt.Println("[main] finish parsing core")
|
||||
|
||||
fmt.Println("[main] parsing runtime APIs...")
|
||||
f, err = specdir.Open("include/level_zero/zer_api.h")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
scanHeader("rntm", bufio.NewScanner(f))
|
||||
_ = f.Close()
|
||||
fmt.Println("[main] finish parsing runtime")
|
||||
|
||||
fmt.Println("[main] parsing sysman APIs...")
|
||||
f, err = specdir.Open("include/level_zero/zes_api.h")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
scanHeader("sysm", bufio.NewScanner(f))
|
||||
_ = f.Close()
|
||||
fmt.Println("[main] finish parsing sysman")
|
||||
|
||||
fmt.Println("[main] parsing tools APIs...")
|
||||
f, err = specdir.Open("include/level_zero/zet_api.h")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
scanHeader("tols", bufio.NewScanner(f))
|
||||
_ = f.Close()
|
||||
fmt.Println("[main] finish parsing tools")
|
||||
}
|
||||
439
cmd/gen/scan.go
Normal file
439
cmd/gen/scan.go
Normal file
@@ -0,0 +1,439 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
numbergenerics = "~int| ~uint32 | ~uint64 | ~uintptr"
|
||||
)
|
||||
|
||||
var (
|
||||
typemap = map[string]string{
|
||||
"char": "byte",
|
||||
"void*": "unsafe.Pointer",
|
||||
"const void*": "unsafe.Pointer",
|
||||
}
|
||||
)
|
||||
|
||||
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 := ""
|
||||
_ = 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))
|
||||
}
|
||||
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)
|
||||
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\nimport (\n\t\"unsafe\"\n)\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) 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, 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 {
|
||||
fmt.Printf("[warn] %s L%d: non-0 sb at block end: %s\n", 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 ")
|
||||
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 "):
|
||||
s, newln := get1sentence(t, 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 len(lines) < 4 {
|
||||
panic(fmt.Sprintf("%s L%d: unexpected short multi typdef line %s", name, ln, t))
|
||||
}
|
||||
if lines[1] != "{" {
|
||||
panic(fmt.Sprintf("%s L%d: unexpected non-{ multi typdef line %s", name, ln, t))
|
||||
}
|
||||
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, "char ") || strings.HasPrefix(stat, "void* ") ||
|
||||
strings.HasPrefix(stat, "const void*"):
|
||||
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(tname)
|
||||
k := tname + "_t"
|
||||
if symtab.contains(k) {
|
||||
tname = symtab[k].replace(k)
|
||||
}
|
||||
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.HasPrefix(stat, "///< "):
|
||||
fsb.Truncate(fsb.Len() - 1)
|
||||
fsb.WriteString(stat[4:])
|
||||
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(symtab, ln, name, sname, val, &sb, f, func() *symbol {
|
||||
return newSymbolConst(sname, val)
|
||||
})
|
||||
f.WriteString("type ")
|
||||
f.WriteString(val)
|
||||
f.WriteString(" struct {")
|
||||
_, _ = io.Copy(f, fsb)
|
||||
f.WriteString("\n}\n\n")
|
||||
continue
|
||||
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(symtab, ln, name, sname, val, &sb, f, func() *symbol {
|
||||
return newSymbolConst(sname, val)
|
||||
})
|
||||
replaces := ""
|
||||
if !redirect {
|
||||
f.WriteString("type ")
|
||||
f.WriteString(val)
|
||||
f.WriteString(" uintptr\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")
|
||||
continue
|
||||
}
|
||||
}
|
||||
// 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, t))
|
||||
}
|
||||
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, "_____"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
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")
|
||||
default:
|
||||
panic(fmt.Sprintf("%s L%d: unexpected line %s", name, ln, t))
|
||||
}
|
||||
}
|
||||
return ln
|
||||
}
|
||||
108
cmd/gen/symbol.go
Normal file
108
cmd/gen/symbol.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
errIsConstReplace = errors.New("is const replace")
|
||||
errNoSuchSymbol = errors.New("no such sybmol")
|
||||
)
|
||||
|
||||
type symbolTable map[string]*symbol
|
||||
|
||||
func (st symbolTable) apply(t string) string {
|
||||
for _, s := range st {
|
||||
t = s.replace(t)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (st symbolTable) contains(name string) bool {
|
||||
_, ok := st[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
type symbolType uintptr
|
||||
|
||||
const (
|
||||
// symbolTypeConst fields
|
||||
//
|
||||
// 0: const eval
|
||||
symbolTypeConst symbolType = iota
|
||||
// symbolTypeFunc fields
|
||||
//
|
||||
// 0: _para1_name, _para2_name, ...
|
||||
// 1: replaceable eval
|
||||
symbolTypeFunc
|
||||
)
|
||||
|
||||
type symbol struct {
|
||||
stype symbolType
|
||||
name string
|
||||
fields []string
|
||||
}
|
||||
|
||||
func newSymbolConst(name, val string) *symbol {
|
||||
return &symbol{
|
||||
stype: symbolTypeConst,
|
||||
name: name,
|
||||
fields: []string{val},
|
||||
}
|
||||
}
|
||||
|
||||
func newSymbolFunc(name, paras, evals string) *symbol {
|
||||
return &symbol{
|
||||
stype: symbolTypeFunc,
|
||||
name: name,
|
||||
fields: []string{paras, evals},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *symbol) extract1stFunc(txt string) (args []string, a, b int, err error) {
|
||||
if s.stype == symbolTypeConst {
|
||||
return nil, 0, 0, errIsConstReplace
|
||||
}
|
||||
a = strings.Index(txt, s.name)
|
||||
if a < 0 {
|
||||
return nil, 0, 0, errNoSuchSymbol
|
||||
}
|
||||
str, off, err := getInsideRoundBrakets(txt[a:])
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
args = strings.Split(str, ",")
|
||||
for i, arg := range args {
|
||||
args[i] = strings.TrimSpace(arg)
|
||||
}
|
||||
return args, a, a + off, nil
|
||||
}
|
||||
|
||||
func (s *symbol) replace(txt string) string {
|
||||
switch s.stype {
|
||||
case symbolTypeConst:
|
||||
return strings.ReplaceAll(txt, s.name, s.fields[0])
|
||||
case symbolTypeFunc:
|
||||
paras := strings.Split(s.fields[0], ",")
|
||||
txts := []string{}
|
||||
for {
|
||||
args, a, b, err := s.extract1stFunc(txt)
|
||||
if err == errNoSuchSymbol {
|
||||
txts = append(txts, txt)
|
||||
return strings.Join(txts, "")
|
||||
}
|
||||
if len(paras) != len(args) {
|
||||
panic("args " + strings.Join(args, ", ") + " count " + strconv.Itoa(len(args)) + " is different from recorded " + s.fields[0])
|
||||
}
|
||||
n := len(txts)
|
||||
txts = append(txts, []string{txt[:a], "/* ", txt[a:b], ") */(", s.fields[1]}...)
|
||||
for i, p := range paras {
|
||||
txts[n+4] = strings.ReplaceAll(txts[n+4], strings.TrimSpace(p), args[i])
|
||||
}
|
||||
txt = txt[b:]
|
||||
}
|
||||
}
|
||||
panic("unsupported symbol type " + strconv.Itoa(int(s.stype)))
|
||||
}
|
||||
95
cmd/gen/utils.go
Normal file
95
cmd/gen/utils.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func skip2endif(scan *bufio.Scanner, ln int) int {
|
||||
depth := 1
|
||||
for scan.Scan() {
|
||||
ln++
|
||||
t := scan.Text()
|
||||
switch {
|
||||
case strings.HasPrefix(t, "#endif"):
|
||||
depth--
|
||||
case strings.HasPrefix(t, "#if"):
|
||||
depth++
|
||||
default:
|
||||
}
|
||||
if depth <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ln
|
||||
}
|
||||
|
||||
func getInsideRoundBrakets(txt string) (string, int, error) {
|
||||
depth := 0
|
||||
a := 0
|
||||
for i, t := range txt {
|
||||
switch t {
|
||||
case '(':
|
||||
if depth == 0 {
|
||||
a = i + 1
|
||||
}
|
||||
depth++
|
||||
case ')':
|
||||
depth--
|
||||
if depth <= 0 {
|
||||
return txt[a:i], i, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", 0, errors.New("no round brakets pair in " + txt)
|
||||
}
|
||||
|
||||
func get1sentence(firstln string, scan *bufio.Scanner, ln int) (string, int) {
|
||||
if strings.Contains(firstln, ";") {
|
||||
return firstln, ln
|
||||
}
|
||||
bracedepth := 0
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString(firstln)
|
||||
for scan.Scan() {
|
||||
sb.WriteString("\n")
|
||||
t := scan.Text()
|
||||
ln++
|
||||
if strings.Contains(t, "{") {
|
||||
bracedepth++
|
||||
}
|
||||
if strings.Contains(t, "}") {
|
||||
bracedepth--
|
||||
}
|
||||
sb.WriteString(t)
|
||||
if strings.Contains(t, ";") && bracedepth == 0 {
|
||||
return sb.String(), ln
|
||||
}
|
||||
}
|
||||
return "", -1
|
||||
}
|
||||
|
||||
func us2camel(t string) string {
|
||||
sb := strings.Builder{}
|
||||
for s := range strings.SplitSeq(t, "_") {
|
||||
rs := []rune(s)
|
||||
sb.WriteRune(unicode.ToUpper(rs[0]))
|
||||
for _, r := range rs[1:] {
|
||||
sb.WriteRune(unicode.ToLower(r))
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func trimEmptyStringArray(arr []string) []string {
|
||||
news := make([]string, 0, len(arr))
|
||||
for _, s := range arr {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
news = append(news, s)
|
||||
}
|
||||
return news
|
||||
}
|
||||
Reference in New Issue
Block a user