From e8f52bd2f015aeb74d6175bcf47bfafa29cf3a35 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 19 May 2025 21:40:35 +0800 Subject: [PATCH 1/3] cl/convert:NodeConvert --- cmd/gogensig/gogensig.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cmd/gogensig/gogensig.go b/cmd/gogensig/gogensig.go index 62b5941f..43f2ea20 100644 --- a/cmd/gogensig/gogensig.go +++ b/cmd/gogensig/gogensig.go @@ -88,6 +88,7 @@ func main() { } return item.GoName, nil }, + NodeConv: &NodeConverter{}, Pkg: convertPkg.File, FileMap: convertPkg.FileMap, TypeMap: conf.TypeMap, @@ -111,6 +112,21 @@ func main() { check(err) } +type NodeConverter struct { +} + +func (c *NodeConverter) ConvDecl(decl ast.Decl) (goName, goFile string, err error) { + return "", "", nil +} + +func (c *NodeConverter) ConvEnumItem(decl *ast.EnumTypeDecl, item *ast.EnumItem) (goName, goFile string, err error) { + return "", "", nil +} + +func (c *NodeConverter) ConvMacro(macro *ast.Macro) (goName, goFile string, err error) { + return "", "", nil +} + // Write all files in the package to the output directory func writePkg(pkg *gogen.Package, outDir string) error { var errs errors.List From f887c1b9169cfac7dab276890583e14c23d40aa0 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 19 May 2025 22:41:45 +0800 Subject: [PATCH 2/3] cl/convert:name generate & file generate for macro --- cl/convert.go | 18 +++ cl/internal/convert/convert.go | 22 ++- cl/internal/convert/convert_test.go | 15 +- cl/internal/convert/package.go | 76 +++++++--- cl/internal/convert/package_bulitin_test.go | 2 +- cl/internal/convert/package_test.go | 10 +- cmd/gogensig/gogensig.go | 29 ++-- cmd/gogensig/node/node.go | 158 ++++++++++++++++++++ 8 files changed, 283 insertions(+), 47 deletions(-) create mode 100644 cmd/gogensig/node/node.go diff --git a/cl/convert.go b/cl/convert.go index 20c7a525..dfe552a9 100644 --- a/cl/convert.go +++ b/cl/convert.go @@ -20,6 +20,22 @@ func ModInit(deps []string, outputDir string, modulePath string) error { type NodeConverter = convert.NodeConverter +type ProcessSymbol = convert.ProcessSymbol + +func NewProcessSymbol() *ProcessSymbol { + return convert.NewProcessSymbol() +} + +type NameMethod = convert.NameMethod + +type Node = convert.Node + +func NewNode(name string, kind NodeKind) Node { + return convert.NewNode(name, kind) +} + +type NodeKind = convert.NodeKind + type ConvConfig struct { OutputDir string PkgPath string @@ -28,6 +44,7 @@ type ConvConfig struct { FileMap map[string]*llconfig.FileInfo ConvSym func(name *ast.Object, mangleName string) (goName string, err error) NodeConv NodeConverter + Symbols *convert.ProcessSymbol // CfgFile string // llcppg.cfg TypeMap map[string]string // llcppg.pub @@ -46,6 +63,7 @@ func Convert(config *ConvConfig) (pkg Package, err error) { FileMap: config.FileMap, ConvSym: config.ConvSym, NodeConv: config.NodeConv, + Symbols: config.Symbols, TypeMap: config.TypeMap, Deps: config.Deps, diff --git a/cl/internal/convert/convert.go b/cl/internal/convert/convert.go index 2b6a9c47..b132308e 100644 --- a/cl/internal/convert/convert.go +++ b/cl/internal/convert/convert.go @@ -41,6 +41,7 @@ type Config struct { FileMap map[string]*llconfig.FileInfo ConvSym func(name *ast.Object, mangleName string) (goName string, err error) NodeConv NodeConverter + Symbols *ProcessSymbol // CfgFile string // llcppg.cfg TypeMap map[string]string // llcppg.pub @@ -94,6 +95,7 @@ func NewConverter(config *Config) (*Converter, error) { Name: config.PkgName, OutputDir: config.OutputDir, ConvSym: config.ConvSym, + Symbols: config.Symbols, LibCommand: config.Libs, TrimPrefixes: config.TrimPrefixes, KeepUnderScore: config.KeepUnderScore, @@ -123,9 +125,25 @@ func (p *Converter) Process() { } } + processNode := func(goFile string, process func() error) { + p.GenPkg.SetGoFile(goFile) + if err := process(); err != nil { + log.Panicln(err) + } + } + for _, macro := range p.Pkg.Macros { - processDecl(macro.Loc.File, func() error { - return p.GenPkg.NewMacro(macro) + goName, goFile, err := p.Conf.NodeConv.ConvMacro(macro) + // todo(zzy):goName to New Macro + if err != nil { + if errors.Is(err, ErrSkip) { + continue + } + // todo(zzy):refine error handing + log.Panicln(err) + } + processNode(goFile, func() error { + return p.GenPkg.NewMacro(macro, goName) }) } diff --git a/cl/internal/convert/convert_test.go b/cl/internal/convert/convert_test.go index 9c7c8dd7..eb8b0056 100644 --- a/cl/internal/convert/convert_test.go +++ b/cl/internal/convert/convert_test.go @@ -13,6 +13,7 @@ import ( "github.com/goplus/llcppg/cl/internal/cltest" "github.com/goplus/llcppg/cl/internal/convert" "github.com/goplus/llcppg/cmd/gogensig/config" + "github.com/goplus/llcppg/cmd/gogensig/node" "github.com/goplus/llcppg/cmd/gogensig/unmarshal" llcppg "github.com/goplus/llcppg/config" "github.com/goplus/llgo/xtool/env" @@ -220,6 +221,8 @@ func testFrom(t *testing.T, dir string, gen bool, validateFunc func(t *testing.T t.Fatal(err) } + symbols := convert.NewProcessSymbol() + cvt, err := convert.NewConverter(&convert.Config{ PkgPath: ".", PkgName: cfg.Name, @@ -227,12 +230,22 @@ func testFrom(t *testing.T, dir string, gen bool, validateFunc func(t *testing.T OutputDir: outputDir, Pkg: convertPkg.File, FileMap: convertPkg.FileMap, - + NodeConv: node.NewNodeConverter( + &node.NodeConverterConfig{ + PkgName: cfg.Name, + // symbol table + FileMap: convertPkg.FileMap, + TypeMap: cfg.TypeMap, + TrimPrefixes: cfg.TrimPrefixes, + Symbols: symbols, + }, + ), TypeMap: cfg.TypeMap, Deps: cfg.Deps, TrimPrefixes: cfg.TrimPrefixes, Libs: cfg.Libs, KeepUnderScore: cfg.KeepUnderScore, + Symbols: symbols, }) if err != nil { t.Fatal(err) diff --git a/cl/internal/convert/package.go b/cl/internal/convert/package.go index 3dc6a3e5..4bc8a3a3 100644 --- a/cl/internal/convert/package.go +++ b/cl/internal/convert/package.go @@ -52,6 +52,7 @@ type PackageConfig struct { Name string // current package name OutputDir string ConvSym func(name *ast.Object, mangleName string) (goName string, err error) + Symbols *ProcessSymbol GenConf *gogen.Config TrimPrefixes []string LibCommand string // use to gen link command like $(pkg-config --libs xxx) @@ -67,12 +68,18 @@ func NewPackage(config *PackageConfig) (*Package, error) { EnableTypesalias: true, } } + var symbols *ProcessSymbol + if config.Symbols == nil { + symbols = NewProcessSymbol() + } else { + symbols = config.Symbols + } p := &Package{ p: gogen.NewPackage(config.PkgPath, config.Name, config.GenConf), conf: config, incompleteTypes: NewIncompleteTypes(), locMap: NewThirdTypeLoc(), - symbols: NewProcessSymbol(), + symbols: symbols, } // default have load llgo/c @@ -678,41 +685,45 @@ func (p *Package) createEnumItems(items []*ast.EnumItem, enumType types.Type) er return nil } -func (p *Package) NewMacro(macro *ast.Macro) error { - if !p.curFile.InCurPkg() { - return nil - } - +func (p *Package) NewMacro(macro *ast.Macro, goName string) error { // simple const macro define (#define NAME value) if len(macro.Tokens) == 2 && macro.Tokens[1].Token == ctoken.LITERAL { value := macro.Tokens[1].Lit defs := p.NewConstGroup() - node := Node{name: macro.Name, kind: Macro} - name, _, exist, err := p.RegisterNode(node, p.constName, p.lookupPub) - if err != nil { - return fmt.Errorf("NewMacro: %s fail: %w", macro.Name, err) - } - if exist { - if debugLog { - log.Printf("NewMacro: %s is processed\n", macro.Name) - } - return nil + + obj := p.lookupPub("", goName) + if obj != nil { + return fmt.Errorf("NewMacro: %s is already defined", macro.Name) } + + // node := Node{name: macro.Name, kind: Macro} + + // todo(zzy): remove this,current only to register name to ProcessSymbol,to keep other logic correct + // _, _, exist, err := p.RegisterNode(node, p.constName, p.lookupPub) + // if err != nil { + // return fmt.Errorf("NewMacro: %s fail: %w", macro.Name, err) + // } + // if exist { + // if debugLog { + // log.Printf("NewMacro: %s is processed\n", macro.Name) + // } + // return nil + // } if debugLog { - log.Printf("NewMacro: %s = %s\n", name, value) + log.Printf("NewMacro: %s = %s\n", goName, value) } if str, err := litToString(value); err == nil { - defs.New(str, nil, name) + defs.New(str, nil, goName) } else if _, err := litToUint(value); err == nil { defs.New(&goast.BasicLit{ Kind: token.INT, Value: value, - }, nil, name) + }, nil, goName) } else if _, err := litToFloat(value, 64); err == nil { defs.New(&goast.BasicLit{ Kind: token.FLOAT, Value: value, - }, nil, name) + }, nil, goName) } } return nil @@ -722,6 +733,13 @@ func (p *Package) NewConstGroup() *ConstGroup { return NewConstGroup(p.p, p.p.Types.Scope()) } +func (p *Package) SetGoFile(fileName string) error { + _, err := p.p.SetCurFile(fileName, true) + // todo(zzy):avoid mark every time + p.p.Unsafe().MarkForceUsed(p.p) + return err +} + type ConstGroup struct { defs *gogen.ConstDefs } @@ -959,10 +977,10 @@ func (it *IncompleteTypes) IterateIncomplete(fn func(*Incomplete) error) error { return nil } -type nodeKind int +type NodeKind int const ( - FuncDecl nodeKind = iota + 1 + FuncDecl NodeKind = iota + 1 TypeDecl TypedefDecl EnumTypeDecl @@ -972,7 +990,19 @@ const ( type Node struct { name string - kind nodeKind + kind NodeKind +} + +func NewNode(name string, kind NodeKind) Node { + return Node{name: name, kind: kind} +} + +func (n Node) Name() string { + return n.name +} + +func (n Node) Kind() NodeKind { + return n.kind } type ProcessSymbol struct { diff --git a/cl/internal/convert/package_bulitin_test.go b/cl/internal/convert/package_bulitin_test.go index 6af627be..cecb463e 100644 --- a/cl/internal/convert/package_bulitin_test.go +++ b/cl/internal/convert/package_bulitin_test.go @@ -105,7 +105,7 @@ func TestRedefPubName(t *testing.T) { Loc: &ast.Location{File: "temp.h"}, Name: "Bar", Tokens: []*ast.Token{{Token: ctoken.IDENT, Lit: "Bar"}, {Token: ctoken.LITERAL, Lit: "1"}}, - }) + }, "Bar") if err == nil { t.Fatal("expect a error") } diff --git a/cl/internal/convert/package_test.go b/cl/internal/convert/package_test.go index a5fefd97..21efdc3c 100644 --- a/cl/internal/convert/package_test.go +++ b/cl/internal/convert/package_test.go @@ -1165,14 +1165,16 @@ func TestRedef(t *testing.T) { Name: "MACRO_FOO", Tokens: []*ast.Token{{Token: token.IDENT, Lit: "MACRO_FOO"}, {Token: token.LITERAL, Lit: "1"}}, } - err = pkg.NewMacro(macro) + err = pkg.NewMacro(macro, macro.Name) if err != nil { t.Fatal("unexpect redefine err") } - err = pkg.NewMacro(macro) - if err != nil { - t.Fatal("unexpect redefine err") + // NOTE(zzy):in upper layer logic to avoid reprocess node after refactor. + // So here we expect a redefine error. + err = pkg.NewMacro(macro, macro.Name) + if err == nil { + t.Fatal("expect a redefine error") } var buf bytes.Buffer diff --git a/cmd/gogensig/gogensig.go b/cmd/gogensig/gogensig.go index 43f2ea20..5b0348f1 100644 --- a/cmd/gogensig/gogensig.go +++ b/cmd/gogensig/gogensig.go @@ -27,6 +27,7 @@ import ( "github.com/goplus/llcppg/ast" "github.com/goplus/llcppg/cl" "github.com/goplus/llcppg/cmd/gogensig/config" + "github.com/goplus/llcppg/cmd/gogensig/node" "github.com/goplus/llcppg/cmd/gogensig/unmarshal" llcppg "github.com/goplus/llcppg/config" "github.com/qiniu/x/errors" @@ -79,6 +80,8 @@ func main() { symbTable, err := config.NewSymbolTable(symbFile) check(err) + symbols := cl.NewProcessSymbol() + pkg, err := cl.Convert(&cl.ConvConfig{ PkgName: conf.Name, ConvSym: func(name *ast.Object, mangleName string) (goName string, err error) { @@ -88,7 +91,16 @@ func main() { } return item.GoName, nil }, - NodeConv: &NodeConverter{}, + NodeConv: node.NewNodeConverter( + &node.NodeConverterConfig{ + PkgName: conf.Name, + SymbTable: symbTable, + FileMap: convertPkg.FileMap, + TypeMap: conf.TypeMap, + TrimPrefixes: conf.TrimPrefixes, + Symbols: symbols, + }, + ), Pkg: convertPkg.File, FileMap: convertPkg.FileMap, TypeMap: conf.TypeMap, @@ -112,21 +124,6 @@ func main() { check(err) } -type NodeConverter struct { -} - -func (c *NodeConverter) ConvDecl(decl ast.Decl) (goName, goFile string, err error) { - return "", "", nil -} - -func (c *NodeConverter) ConvEnumItem(decl *ast.EnumTypeDecl, item *ast.EnumItem) (goName, goFile string, err error) { - return "", "", nil -} - -func (c *NodeConverter) ConvMacro(macro *ast.Macro) (goName, goFile string, err error) { - return "", "", nil -} - // Write all files in the package to the output directory func writePkg(pkg *gogen.Package, outDir string) error { var errs errors.List diff --git a/cmd/gogensig/node/node.go b/cmd/gogensig/node/node.go new file mode 100644 index 00000000..c0f5679f --- /dev/null +++ b/cmd/gogensig/node/node.go @@ -0,0 +1,158 @@ +package node + +import ( + "fmt" + "strings" + + "github.com/goplus/llcppg/_xtool/llcppsymg/tool/name" + "github.com/goplus/llcppg/ast" + "github.com/goplus/llcppg/cl" + "github.com/goplus/llcppg/cmd/gogensig/config" + llconfig "github.com/goplus/llcppg/config" +) + +// todo(zzy):a temp abstract,for cl/convert test & gogensig + +type NodeConverter struct { + symbols *cl.ProcessSymbol + conf *NodeConverterConfig +} + +type NodeConverterConfig struct { + PkgName string + SymbTable *config.SymbolTable + FileMap map[string]*llconfig.FileInfo + TrimPrefixes []string + TypeMap map[string]string + + // todo(zzy):remove this field + Symbols *cl.ProcessSymbol +} + +func NewNodeConverter(cfg *NodeConverterConfig) *NodeConverter { + var symbols *cl.ProcessSymbol + if cfg.Symbols == nil { + symbols = cl.NewProcessSymbol() + } else { + symbols = cfg.Symbols + } + return &NodeConverter{ + symbols: symbols, + conf: cfg, + } +} + +func (c *NodeConverter) ConvDecl(decl ast.Decl) (goName, goFile string, err error) { + return "", "", nil +} + +func (c *NodeConverter) ConvEnumItem(decl *ast.EnumTypeDecl, item *ast.EnumItem) (goName, goFile string, err error) { + return "", "", nil +} + +func (p *NodeConverter) ConvMacro(macro *ast.Macro) (goName, goFile string, err error) { + node := cl.NewNode(macro.Name, Macro) + goName, goFile, err = p.Register(macro.Loc, node, p.constName) + if err != nil { + return + } + return +} + +func (p *NodeConverter) Register(loc *ast.Location, node cl.Node, nameMethod NameMethod) (goName string, goFile string, err error) { + goFile, err = p.goFile(loc.File) + if err != nil { + return + } + pubName, exist := p.symbols.Lookup(node) + if exist { + return pubName, goFile, nil + } + goName, _ = p.GetUniqueName(node, nameMethod) + return goName, goFile, nil +} + +type NameMethod func(name string) string + +func (p *NodeConverter) goFile(file string) (string, error) { + info, ok := p.conf.FileMap[file] + if !ok { + var availableFiles []string + for f := range p.conf.FileMap { + availableFiles = append(availableFiles, f) + } + return "", fmt.Errorf("file %q not found in FileMap. Available files:\n%s", + file, strings.Join(availableFiles, "\n")) + } + switch info.FileType { + case llconfig.Inter: + return name.HeaderFileToGo(file), nil + case llconfig.Impl: + return p.conf.PkgName + "_autogen.go", nil + default: + return "", cl.ErrSkip + } +} + +// GetUniqueName generates a unique public name for a given node using the provided name transformation method. +// It ensures the generated name doesn't conflict with existing names by adding a numeric suffix if needed. +// +// Parameters: +// - node: The node containing the original name to be transformed +// - nameMethod: Function used to transform the original name (e.g., declName, constName) +// +// Returns: +// - pubName: The generated unique public name +// - changed: Whether the generated name differs from the original name +func (p *NodeConverter) GetUniqueName(node cl.Node, nameMethod NameMethod) (pubName string, changed bool) { + pubName = nameMethod(node.Name()) + uniquePubName := p.symbols.Register(node, pubName) + return uniquePubName, uniquePubName != node.Name() +} + +// which is define in llcppg.cfg/typeMap +func (p *NodeConverter) definedName(name string) (string, bool) { + definedName, ok := p.conf.TypeMap[name] + if ok { + if definedName == "" { + return name, true + } + return definedName, true + } + return name, false +} + +// transformName handles identifier name conversion following these rules: +// 1. First checks if the name exists in predefined mapping (in typeMap of llcppg.cfg) +// 2. If not in predefined mapping, applies the transform function +// 3. Before applying the transform function, removes specified prefixes (obtained via trimPrefixes) +// +// Parameters: +// - name: Original C/C++ identifier name +// - transform: Name transformation function (like names.PubName or names.ExportName) +// +// Returns: +// - Transformed identifier name +func (p *NodeConverter) transformName(cname string, transform NameMethod) string { + if definedName, ok := p.definedName(cname); ok { + return definedName + } + return transform(name.RemovePrefixedName(cname, p.conf.TrimPrefixes)) +} + +// func (p *NodeConverter) declName(cname string) string { +// return p.transformName(cname, name.PubName) +// } + +func (p *NodeConverter) constName(cname string) string { + return p.transformName(cname, name.ExportName) +} + +const ( + FuncDecl cl.NodeKind = iota + 1 + TypeDecl + TypedefDecl + EnumTypeDecl + EnumItem + Macro +) From 7a6cf8bb46029c4481991ae4d1c25c6b3dde5533 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 20 May 2025 00:13:37 +0800 Subject: [PATCH 3/3] cl/convert:name generate & file generate --- cl/internal/convert/convert.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/cl/internal/convert/convert.go b/cl/internal/convert/convert.go index b132308e..0e271b4a 100644 --- a/cl/internal/convert/convert.go +++ b/cl/internal/convert/convert.go @@ -8,6 +8,7 @@ import ( "github.com/goplus/llcppg/ast" cfg "github.com/goplus/llcppg/cmd/gogensig/config" llconfig "github.com/goplus/llcppg/config" + ctoken "github.com/goplus/llcppg/token" ) var ( @@ -133,18 +134,20 @@ func (p *Converter) Process() { } for _, macro := range p.Pkg.Macros { - goName, goFile, err := p.Conf.NodeConv.ConvMacro(macro) - // todo(zzy):goName to New Macro - if err != nil { - if errors.Is(err, ErrSkip) { - continue + if len(macro.Tokens) == 2 && macro.Tokens[1].Token == ctoken.LITERAL { + goName, goFile, err := p.Conf.NodeConv.ConvMacro(macro) + // todo(zzy):goName to New Macro + if err != nil { + if errors.Is(err, ErrSkip) { + continue + } + // todo(zzy):refine error handing + log.Panicln(err) } - // todo(zzy):refine error handing - log.Panicln(err) + processNode(goFile, func() error { + return p.GenPkg.NewMacro(macro, goName) + }) } - processNode(goFile, func() error { - return p.GenPkg.NewMacro(macro, goName) - }) } for _, decl := range p.Pkg.Decls {