From 33af9e878b83314b955410fdf0b7e9e7f088948a Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 8 Aug 2024 15:59:08 +0800 Subject: [PATCH] llcppsigfech:basic struct llcppsigfetch:basic parse converter llcppsigfetch:converter top decl llcppg:converter test --- chore/_xtool/llcppsigfetch/llcppsigfetch.go | 61 +++++++++++- chore/_xtool/llcppsigfetch/parse/cvt.go | 98 +++++++++++++++++++ .../llcppsigfetch/parse/cvt_test/cvt.go | 24 +++++ chore/_xtool/llcppsigfetch/parse/parse.go | 60 ++++++++++++ 4 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 chore/_xtool/llcppsigfetch/parse/cvt.go create mode 100644 chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go create mode 100644 chore/_xtool/llcppsigfetch/parse/parse.go diff --git a/chore/_xtool/llcppsigfetch/llcppsigfetch.go b/chore/_xtool/llcppsigfetch/llcppsigfetch.go index 30190a18..19746b09 100644 --- a/chore/_xtool/llcppsigfetch/llcppsigfetch.go +++ b/chore/_xtool/llcppsigfetch/llcppsigfetch.go @@ -16,6 +16,65 @@ package main +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/config" +) + func main() { - // TODO(xsw): implement llcppsigfetch tool + cfgFile := "llcppg.cfg" + if len(os.Args) > 1 { + cfgFile = os.Args[1] + } + + var data []byte + var err error + if cfgFile == "-" { + data, err = io.ReadAll(os.Stdin) + } else { + data, err = os.ReadFile(cfgFile) + } + check(err) + + conf, err := config.GetConf(data) + check(err) + defer conf.Delete() + + if err != nil { + fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) + } + + files := getHeaderFiles(conf.CFlags, conf.Include) + + context := parse.NewContext() + err = context.ProcessFiles(files) + check(err) + + outputInfo(context) +} + +func check(err error) { + if err != nil { + panic(err) + } +} + +func getHeaderFiles(cflags string, files []string) []string { + prefix := cflags + prefix = strings.TrimPrefix(prefix, "-I") + var paths []string + for _, f := range files { + paths = append(paths, filepath.Join(prefix, f)) + } + return paths +} + +func outputInfo(context *parse.Context) { + // TODO(zzy): } diff --git a/chore/_xtool/llcppsigfetch/parse/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt.go new file mode 100644 index 00000000..806db4ee --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -0,0 +1,98 @@ +package parse + +import ( + "errors" + "fmt" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/clang" + "github.com/goplus/llgo/chore/llcppg/ast" +) + +type Converter struct { + files map[string]*ast.File + typeMap map[clang.Type]*ast.Expr + declMap map[clang.Cursor]*ast.Decl + curLoc ast.Location + index *clang.Index + unit *clang.TranslationUnit +} + +func NewConverter(filepath string) (*Converter, error) { + args := []*c.Char{ + c.Str("-x"), + c.Str("c++"), + c.Str("-std=c++11"), + } + index := clang.CreateIndex(0, 0) + unit := index.ParseTranslationUnit( + c.AllocaCStr(filepath), + unsafe.SliceData(args), 3, + nil, 0, + clang.DetailedPreprocessingRecord, + ) + if unit == nil { + return nil, errors.New("failed to parse translation unit") + } + + return &Converter{ + typeMap: make(map[clang.Type]*ast.Expr), + declMap: make(map[clang.Cursor]*ast.Decl), + files: make(map[string]*ast.File), + index: index, + unit: unit, + }, nil +} + +func (ct *Converter) Dispose() { + ct.index.Dispose() + ct.unit.Dispose() +} + +// visit top decls (struct,class,function,enum & marco,include) +func visit(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + ct := (*Converter)(clientData) + switch cursor.Kind { + case clang.CursorInclusionDirective: + fmt.Println("todo: Process include") + return clang.ChildVisit_Continue + case clang.CursorMacroDefinition: + fmt.Println("todo: Process macro") + return clang.ChildVisit_Continue + case clang.CursorEnumDecl: + fmt.Println("todo: Process enum") + return clang.ChildVisit_Continue + case clang.CursorClassDecl: + ct.ProcessClass(cursor) + return clang.ChildVisit_Continue + case clang.CursorStructDecl: + fmt.Println("todo: Process struct") + return clang.ChildVisit_Continue + case clang.CursorFunctionDecl: + ct.ProcessFunc(cursor) + return clang.ChildVisit_Continue + default: + // non-top-level decl, continue recursion + return clang.ChildVisit_Recurse + } +} + +func (ct *Converter) ProcessFunc(cursor clang.Cursor) { + println("todo: Process func") +} + +func (ct *Converter) ProcessClass(cursor clang.Cursor) { + println("todo: Process class") +} + +func (ct *Converter) Convert() (map[string]*ast.File, error) { + cursor := ct.unit.Cursor() + // visit top decls (struct,class,function & marco,include) + clang.VisitChildren(cursor, visit, c.Pointer(ct)) + return nil, nil +} + +func (ct *Converter) UpdateLocation(loc ast.Location) { + ct.curLoc = loc +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go new file mode 100644 index 00000000..34358743 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "os" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse" +) + +func main() { + if c.Argc != 2 { + fmt.Fprintln(os.Stderr, "Usage: cvt ") + return + } + sourceFile := *c.Advance(c.Argv, 1) + c.Printf(c.Str("sourceFile: %s\n"), sourceFile) + converter, err := parse.NewConverter(c.GoString(sourceFile)) + if err != nil { + panic(err) + } + defer converter.Dispose() + converter.Convert() +} diff --git a/chore/_xtool/llcppsigfetch/parse/parse.go b/chore/_xtool/llcppsigfetch/parse/parse.go new file mode 100644 index 00000000..a024686c --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/parse.go @@ -0,0 +1,60 @@ +package parse + +import ( + "errors" + + "github.com/goplus/llgo/chore/llcppg/ast" +) + +type Context struct { + Files map[string]*ast.File +} + +func NewContext() *Context { + return &Context{ + Files: make(map[string]*ast.File), + } +} + +// ProcessFiles processes the given files and adds them to the context +func (p *Context) ProcessFiles(files []string) error { + for _, file := range files { + if err := p.processFile(file); err != nil { + return err + } + } + return nil +} + +// parse file and add it to the context,avoid duplicate parsing +func (p *Context) processFile(path string) error { + if _, exists := p.Files[path]; exists { + return nil + } + parsedfiles, err := p.parseFile(path) + if err != nil { + return errors.New("failed to parse file: " + path) + } + + for path, file := range parsedfiles { + if _, exist := p.Files[path]; !exist { + p.Files[path] = file + } + } + return nil +} + +func (p *Context) parseFile(path string) (map[string]*ast.File, error) { + converter, err := NewConverter(path) + if err != nil { + return nil, errors.New("failed to create converter " + path) + } + defer converter.Dispose() + + files, err := converter.Convert() + if err != nil { + return nil, err + } + + return files, nil +}