1
0
mirror of https://github.com/fumiama/gozel.git synced 2026-06-05 00:10:24 +08:00
Files
gozel/cmd/gen/symbol.go
2026-03-24 00:49:26 +08:00

143 lines
3.3 KiB
Go

package main
import (
"bytes"
"errors"
"regexp"
"strconv"
"strings"
"unicode"
)
var (
errIsConstReplace = errors.New("is const replace")
errNoSuchSymbol = errors.New("no such sybmol")
)
var symtab = symbolTable{
"ZE_APICALL": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_APICALL", []string{""}},
"ZE_APIEXPORT": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_APIEXPORT", []string{""}},
"ZE_DLLEXPORT": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_DLLEXPORT", []string{""}},
"~(0ULL": &symbol{symbolTypeConst, symbolSubTypeDefine, "~(0ULL", []string{"(^uint64(0)"}},
}
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 symbolSubType uintptr
const (
symbolSubTypeDefine symbolSubType = iota
symbolSubTypeEmptyStruct
symbolSubTypeLargeStruct
symbolSubTypeEnum
symbolSubTypeFuncPtr
)
type symbol struct {
stype symbolType
sstype symbolSubType
name string
fields []string
}
func newSymbolConst(name, val string, sstype symbolSubType) *symbol {
return &symbol{
stype: symbolTypeConst,
sstype: sstype,
name: name,
fields: []string{val},
}
}
func newSymbolFunc(name, paras, evals string, sstype symbolSubType) *symbol {
return &symbol{
stype: symbolTypeFunc,
sstype: sstype,
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:
escapes := regexp.QuoteMeta(s.name)
re := regexp.MustCompile(`(` + escapes + `[^\w_])|(` + escapes + `$)`)
return string(re.ReplaceAllFunc([]byte(txt), func(b []byte) []byte {
last := rune(b[len(b)-1])
if unicode.IsLetter(last) || last == '_' {
return []byte(s.fields[0])
}
buf := bytes.NewBuffer(make([]byte, 0, 128))
buf.WriteString(s.fields[0])
buf.WriteByte(b[len(b)-1])
return buf.Bytes()
}))
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)))
}