From 07519732a1f38604f34536c961f2ab55e4c00797 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 6 Sep 2024 11:44:56 +0800 Subject: [PATCH] llcppsigfetch:based on language configuration analysis --- chore/_xtool/llcppsigfetch/llcppsigfetch.go | 59 ++++++++++++++----- chore/_xtool/llcppsigfetch/parse/cvt.go | 20 ++++--- .../llcppsigfetch/parse/cvt_test/cvt.go | 23 +++++--- .../parse/cvt_test/type_test/type.go | 3 +- chore/_xtool/llcppsigfetch/parse/parse.go | 9 ++- 5 files changed, 82 insertions(+), 32 deletions(-) diff --git a/chore/_xtool/llcppsigfetch/llcppsigfetch.go b/chore/_xtool/llcppsigfetch/llcppsigfetch.go index 898cb9fc..944ce300 100644 --- a/chore/_xtool/llcppsigfetch/llcppsigfetch.go +++ b/chore/_xtool/llcppsigfetch/llcppsigfetch.go @@ -21,6 +21,7 @@ import ( "io" "os" "path/filepath" + "strconv" "strings" "github.com/goplus/llgo/c" @@ -56,10 +57,14 @@ func printUsage() { fmt.Println(" If not provided, uses default 'llcppg.cfg'") fmt.Println("") fmt.Println(" --extract: Extract information from a single file") - fmt.Println(" : When is false: the path to the file to process") - fmt.Println(" When is true: the content of the file to process") - fmt.Println(" : 'true' if contains file content, 'false' if it's a file path") - fmt.Println(" [args]: Optional additional arguments (default: -x c++ -std=c++11)") + fmt.Println(" : Path to the file to process, or file content if -temp=true") + fmt.Println(" -temp=: Optional. Set to 'true' if contains file content,") + fmt.Println(" 'false' (default) if it's a file path") + fmt.Println(" -cpp=: Optional. Set to 'true' if the language is C++ (default: true)") + fmt.Println(" If not present, is a file path") + fmt.Println(" [args]: Optional additional arguments") + fmt.Println(" Default for C++: -x c++") + fmt.Println(" Default for C: -x c") fmt.Println("") fmt.Println(" --help, -h: Show this help message") fmt.Println("") @@ -91,7 +96,7 @@ func runFromConfig() { files := getHeaderFiles(conf.CFlags, conf.Include) - context := parse.NewContext() + context := parse.NewContext(conf.Cplusplus) err = context.ProcessFiles(files) check(err) @@ -99,21 +104,33 @@ func runFromConfig() { } func runExtract() { - if len(os.Args) < 4 { + if len(os.Args) < 3 { + fmt.Println("Error: Insufficient arguments for --extract") printUsage() os.Exit(1) } cfg := &parse.Config{ - File: os.Args[2], - Temp: os.Args[3] == "true", - Args: os.Args[4:], + File: os.Args[2], + Args: []string{}, + IsCpp: true, + Temp: false, } - if !cfg.Temp { - absPath, err := filepath.Abs(cfg.File) - check(err) - cfg.File = absPath - println(cfg.File) + + for i := 3; i < len(os.Args); i++ { + arg := os.Args[i] + switch { + case strings.HasPrefix(arg, "-temp="): + cfg.Temp = parseBoolArg(arg, "temp", false) + os.Args = append(os.Args[:i], os.Args[i+1:]...) + i-- + case strings.HasPrefix(arg, "-cpp="): + cfg.IsCpp = parseBoolArg(arg, "cpp", true) + os.Args = append(os.Args[:i], os.Args[i+1:]...) + i-- + default: + cfg.Args = append(cfg.Args, arg) + } } converter, err := parse.NewConverter(cfg) @@ -151,3 +168,17 @@ func outputInfo(context *parse.Context) { defer info.Delete() c.Printf(str) } + +func parseBoolArg(arg, name string, defaultValue bool) bool { + parts := strings.SplitN(arg, "=", 2) + if len(parts) != 2 { + fmt.Printf("Warning: Invalid -%s= argument, defaulting to %v\n", name, defaultValue) + return defaultValue + } + value, err := strconv.ParseBool(parts[1]) + if err != nil { + fmt.Printf("Warning: Invalid -%s= value '%s', defaulting to %v\n", name, parts[1], defaultValue) + return defaultValue + } + return value +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt.go index 3fc04865..e2ca9344 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -51,9 +51,10 @@ var tagMap = map[string]ast.Tag{ } type Config struct { - File string - Temp bool - Args []string + File string + Temp bool + Args []string + IsCpp bool } func NewConverter(config *Config) (*Converter, error) { @@ -72,12 +73,16 @@ func NewConverter(config *Config) (*Converter, error) { } func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) { - if config.Args == nil || len(config.Args) == 0 { - config.Args = []string{"-x", "c++", "-std=c++11"} + // default use the c/c++ standard of clang; c:gnu17 c++:gnu++17 + // https://clang.llvm.org/docs/CommandGuide/clang.html + defaultArgs := []string{"-x", "c"} + if config.IsCpp { + defaultArgs = []string{"-x", "c++"} } + allArgs := append(defaultArgs, config.Args...) - cArgs := make([]*c.Char, len(config.Args)) - for i, arg := range config.Args { + cArgs := make([]*c.Char, len(allArgs)) + for i, arg := range allArgs { cArgs[i] = c.AllocaCStr(arg) } @@ -418,6 +423,7 @@ func (ct *Converter) GenerateAnonymousName(cursor clang.Cursor) string { } // converts functions, methods, constructors, destructors (including out-of-class decl) to ast.FuncDecl nodes. +// todo(zzy): manglename (c++) func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { name := cursor.String() defer name.Dispose() diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go index f879a181..a72e16b0 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go @@ -13,8 +13,9 @@ import ( func RunTest(testName string, testCases []string) { for i, content := range testCases { converter, err := parse.NewConverter(&parse.Config{ - File: content, - Temp: true, + File: content, + Temp: true, + IsCpp: true, }) if err != nil { panic(err) @@ -45,9 +46,16 @@ type GetTypeOptions struct { ExpectTypeKind clang.TypeKind // Args contains additional compilation arguments passed to Clang (optional) - // Default is []string{"-x", "c++", "-std=c++11"} - // *For complex C types, C language args Must be specified, e.g., []string{"-x", "c", "-std=c99"} + // These are appended after the default language-specific arguments + // Example: []string{"-std=c++11"} Args []string + + // IsCpp indicates whether the code should be treated as C++ (true) or C (false) + // This affects the default language arguments passed to Clang: + // - For C++: []string{"-x", "c++"} + // - For C: []string{"-x", "c"} + // *For complex C types, C Must be specified + IsCpp bool } // GetType returns the clang.Type of the given type code @@ -56,9 +64,10 @@ type GetTypeOptions struct { func GetType(option *GetTypeOptions) (clang.Type, *clang.Index, *clang.TranslationUnit) { code := fmt.Sprintf("%s placeholder;", option.TypeCode) index, unit, err := parse.CreateTranslationUnit(&parse.Config{ - File: code, - Temp: true, - Args: option.Args, + File: code, + Temp: true, + Args: option.Args, + IsCpp: option.IsCpp, }) if err != nil { panic(err) diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go index 3d33814e..03a5771f 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go @@ -128,6 +128,7 @@ func TestNonBuiltinTypes() { for _, t := range tests { typ, index, unit := test.GetType(&test.GetTypeOptions{ TypeCode: t, + IsCpp: true, }) converter := &parse.Converter{} expr := converter.ProcessType(typ) @@ -167,7 +168,7 @@ func getComplexType(flag ast.TypeFlag) clang.Type { typ, _, _ := test.GetType(&test.GetTypeOptions{ TypeCode: code, ExpectTypeKind: clang.TypeComplex, - Args: []string{"-x", "c", "-std=c99"}, + IsCpp: false, }) return typ diff --git a/chore/_xtool/llcppsigfetch/parse/parse.go b/chore/_xtool/llcppsigfetch/parse/parse.go index ee42da75..b86281e1 100644 --- a/chore/_xtool/llcppsigfetch/parse/parse.go +++ b/chore/_xtool/llcppsigfetch/parse/parse.go @@ -10,11 +10,13 @@ import ( type Context struct { Files map[string]*ast.File + IsCpp bool } -func NewContext() *Context { +func NewContext(isCpp bool) *Context { return &Context{ Files: make(map[string]*ast.File), + IsCpp: isCpp, } } @@ -60,8 +62,9 @@ func (p *Context) processFile(path string) error { func (p *Context) parseFile(path string) (map[string]*ast.File, error) { converter, err := NewConverter(&Config{ - File: path, - Temp: false, + File: path, + Temp: false, + IsCpp: p.IsCpp, }) if err != nil { return nil, errors.New("failed to create converter " + path)