diff --git a/chore/_xtool/llcppsigfetch/llcppsigfetch.go b/chore/_xtool/llcppsigfetch/llcppsigfetch.go index 30190a18..61b12cf8 100644 --- a/chore/_xtool/llcppsigfetch/llcppsigfetch.go +++ b/chore/_xtool/llcppsigfetch/llcppsigfetch.go @@ -16,6 +16,169 @@ package main +import ( + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/config" +) + func main() { - // TODO(xsw): implement llcppsigfetch tool + if len(os.Args) == 1 { + // run with default config file + runFromConfig() + return + } + + if os.Args[1] == "--extract" { + runExtract() + } else if os.Args[1] == "--help" || os.Args[1] == "-h" { + printUsage() + } else { + runFromConfig() + } +} + +func printUsage() { + fmt.Println("Usage:") + fmt.Println(" llcppsigfetch []") + fmt.Println(" OR") + fmt.Println(" llcppsigfetch --extract [args...]") + fmt.Println("") + fmt.Println("Options:") + fmt.Println(" []: Path to the configuration file (use '-' for stdin)") + fmt.Println(" If not provided, uses default 'llcppg.cfg'") + fmt.Println("") + fmt.Println(" --extract: Extract information from a single file") + 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("") + fmt.Println("Note: The two usage modes are mutually exclusive. Use either [] OR --extract, not both.") +} + +func runFromConfig() { + 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(conf.Cplusplus) + err = context.ProcessFiles(files) + check(err) + + outputInfo(context) +} + +func runExtract() { + if len(os.Args) < 3 { + fmt.Println("Error: Insufficient arguments for --extract") + printUsage() + os.Exit(1) + } + + cfg := &parse.Config{ + File: os.Args[2], + Args: []string{}, + IsCpp: true, + Temp: false, + } + + 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) + check(err) + _, err = converter.Convert() + check(err) + result := converter.MarshalOutputASTFiles() + cstr := result.Print() + c.Printf(cstr) + cjson.FreeCStr(cstr) + result.Delete() + converter.Dispose() +} + +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) { + info := context.Output() + str := info.Print() + defer cjson.FreeCStr(str) + 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 new file mode 100644 index 00000000..310adc6c --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -0,0 +1,955 @@ +package parse + +import ( + "errors" + "fmt" + "os" + "strings" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/c/clang" + "github.com/goplus/llgo/chore/llcppg/ast" + "github.com/goplus/llgo/chore/llcppg/token" +) + +type FileEntry struct { + Path string + Doc *ast.File +} + +type Converter struct { + Files []*FileEntry + FileOrder []string // todo(zzy): more efficient struct + curLoc ast.Location + index *clang.Index + unit *clang.TranslationUnit + + typeDecls map[string]ast.Decl // cursorUsr -> ast.Decl + + // anonyTypeMap stores mappings for unexpected named declarations in typedefs + // that actually represent anonymous types. + // + // Key: The USR (Unified Symbol Resolution) of the declaration cursor. + // Value: The generated name for the anonymous type. + // + // This map is necessary due to a limitation in libclang where anonymous + // structs, unions, or enums within typedefs are incorrectly reported as + // named declarations. We use this map to keep track of these cases and + // generate appropriate names for them. + // + // Additionally, for all nodes referencing these anonymous types, their + // name references are updated to use the corresponding anonyname from + // this map. This ensures consistent naming across the entire AST for + // these anonymous types. + // + // Example: + // typedef struct { int x; } MyStruct; + anonyTypeMap map[string]bool // cursorUsr +} + +var tagMap = map[string]ast.Tag{ + "struct": ast.Struct, + "union": ast.Union, + "enum": ast.Enum, + "class": ast.Class, +} + +type Config struct { + File string + Temp bool + Args []string + IsCpp bool +} + +func NewConverter(config *Config) (*Converter, error) { + index, unit, err := CreateTranslationUnit(config) + if err != nil { + return nil, err + } + + return &Converter{ + Files: make([]*FileEntry, 0), + index: index, + unit: unit, + anonyTypeMap: make(map[string]bool), + typeDecls: make(map[string]ast.Decl), + }, nil +} + +func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) { + // 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(allArgs)) + for i, arg := range allArgs { + cArgs[i] = c.AllocaCStr(arg) + } + + index := clang.CreateIndex(0, 0) + + var unit *clang.TranslationUnit + + if config.Temp { + content := c.AllocaCStr(config.File) + tempFile := &clang.UnsavedFile{ + Filename: c.Str("temp.h"), + Contents: content, + Length: c.Ulong(c.Strlen(content)), + } + + unit = index.ParseTranslationUnit( + tempFile.Filename, + unsafe.SliceData(cArgs), c.Int(len(cArgs)), + tempFile, 1, + clang.DetailedPreprocessingRecord, + ) + + } else { + cFile := c.AllocaCStr(config.File) + unit = index.ParseTranslationUnit( + cFile, + unsafe.SliceData(cArgs), c.Int(len(cArgs)), + nil, 0, + clang.DetailedPreprocessingRecord, + ) + } + + if unit == nil { + return nil, nil, errors.New("failed to parse translation unit") + } + + return index, unit, nil +} + +func (ct *Converter) Dispose() { + ct.index.Dispose() + ct.unit.Dispose() +} + +func (ct *Converter) GetTokens(cursor clang.Cursor) []*ast.Token { + ran := cursor.Extent() + var numTokens c.Uint + var tokens *clang.Token + ct.unit.Tokenize(ran, &tokens, &numTokens) + defer ct.unit.DisposeTokens(tokens, numTokens) + + tokensSlice := unsafe.Slice(tokens, int(numTokens)) + + result := make([]*ast.Token, 0, int(numTokens)) + for _, tok := range tokensSlice { + tokStr := ct.unit.Token(tok) + result = append(result, &ast.Token{ + Token: toToken(tok), + Lit: c.GoString(tokStr.CStr()), + }) + tokStr.Dispose() + } + return result +} + +func (ct *Converter) UpdateLoc(cursor clang.Cursor) { + loc := cursor.Location() + var file clang.File + loc.SpellingLocation(&file, nil, nil, nil) + filename := file.FileName() + defer filename.Dispose() + + if filename.CStr() == nil { + //todo(zzy): For some built-in macros, there is no file. + ct.curLoc = ast.Location{File: ""} + return + } + + filePath := c.GoString(filename.CStr()) + ct.curLoc = ast.Location{File: filePath} +} + +func (ct *Converter) GetCurFile() *ast.File { + if ct.curLoc.File == "" { + return nil + } + // todo(zzy): more efficient + for i, entry := range ct.Files { + if entry.Path == ct.curLoc.File { + return ct.Files[i].Doc + } + } + newDoc := &ast.File{} + ct.Files = append(ct.Files, &FileEntry{Path: ct.curLoc.File, Doc: newDoc}) + return newDoc +} + +func (ct *Converter) SetAnonyType(cursor clang.Cursor) { + usr := cursor.USR() + usrStr := c.GoString(usr.CStr()) + defer usr.Dispose() + ct.anonyTypeMap[usrStr] = true +} + +func (ct *Converter) GetAnonyType(cursor clang.Cursor) (bool, bool) { + usr := cursor.USR() + usrStr := c.GoString(usr.CStr()) + defer usr.Dispose() + isAnony, ok := ct.anonyTypeMap[usrStr] + return isAnony, ok +} + +func (ct *Converter) SetTypeDecl(cursor clang.Cursor, decl ast.Decl) { + usr := cursor.USR() + usrStr := c.GoString(usr.CStr()) + ct.typeDecls[usrStr] = decl + usr.Dispose() +} + +func (ct *Converter) GetTypeDecl(cursor clang.Cursor) (ast.Decl, bool) { + usr := cursor.USR() + usrStr := c.GoString(usr.CStr()) + decl, ok := ct.typeDecls[usrStr] + usr.Dispose() + return decl, ok +} + +func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase { + base := ast.DeclBase{ + Loc: &ct.curLoc, + Parent: ct.BuildScopingExpr(cursor.SemanticParent()), + } + commentGroup, isDoc := ct.ParseCommentGroup(cursor) + if isDoc { + base.Doc = commentGroup + } + return base +} + +// extracts and parses comments associated with a given Clang cursor, +// distinguishing between documentation comments and line comments. +// It uses libclang to parse only Doxygen-style comments. + +// Reference for Doxygen documentation blocks: https://www.doxygen.nl/manual/docblocks.html + +// The function determines whether a comment is a documentation comment or a line comment by +// comparing the range of the comment node with the range of the declaration node in the AST. + +// Note: In cases where both documentation comments and line comments conceptually exist, +// only the line comment will be preserved. +func (ct *Converter) ParseCommentGroup(cursor clang.Cursor) (comentGroup *ast.CommentGroup, isDoc bool) { + rawComment := cursor.RawCommentText() + defer rawComment.Dispose() + commentGroup := &ast.CommentGroup{} + if rawComment.CStr() != nil { + commentRange := cursor.CommentRange() + cursorRange := cursor.Extent() + isDoc := getOffset(commentRange.RangeStart()) < getOffset(cursorRange.RangeStart()) + commentGroup = ct.ParseComment(c.GoString(rawComment.CStr())) + if len(commentGroup.List) > 0 { + return commentGroup, isDoc + } + } + return nil, false +} + +func (ct *Converter) ParseComment(rawComment string) *ast.CommentGroup { + lines := strings.Split(rawComment, "\n") + commentGroup := &ast.CommentGroup{} + for _, line := range lines { + commentGroup.List = append(commentGroup.List, &ast.Comment{Text: line}) + } + return commentGroup +} + +// visit top decls (struct,class,function,enum & macro,include) +func visitTop(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + ct := (*Converter)(clientData) + ct.UpdateLoc(cursor) + + curFile := ct.GetCurFile() + if curFile == nil { + return clang.ChildVisit_Continue + } + + switch cursor.Kind { + case clang.CursorInclusionDirective: + include := ct.ProcessInclude(cursor) + curFile.Includes = append(curFile.Includes, include) + case clang.CursorMacroDefinition: + macro := ct.ProcessMacro(cursor) + curFile.Macros = append(curFile.Macros, macro) + case clang.CursorEnumDecl: + enum := ct.ProcessEnumDecl(cursor) + curFile.Decls = append(curFile.Decls, enum) + case clang.CursorClassDecl: + classDecl := ct.ProcessClassDecl(cursor) + curFile.Decls = append(curFile.Decls, classDecl) + case clang.CursorStructDecl: + structDecl := ct.ProcessStructDecl(cursor) + curFile.Decls = append(curFile.Decls, structDecl) + case clang.CursorUnionDecl: + unionDecl := ct.ProcessUnionDecl(cursor) + curFile.Decls = append(curFile.Decls, unionDecl) + case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor: + // Handle functions and class methods (including out-of-class method) + // Example: void MyClass::myMethod() { ... } out-of-class method + curFile.Decls = append(curFile.Decls, ct.ProcessFuncDecl(cursor)) + case clang.CursorTypedefDecl: + curFile.Decls = append(curFile.Decls, ct.ProcessTypeDefDecl(cursor)) + case clang.CursorNamespace: + clang.VisitChildren(cursor, visitTop, c.Pointer(ct)) + } + return clang.ChildVisit_Continue +} + +func (ct *Converter) Convert() ([]*FileEntry, error) { + cursor := ct.unit.Cursor() + // visit top decls (struct,class,function & macro,include) + clang.VisitChildren(cursor, visitTop, c.Pointer(ct)) + return ct.Files, nil +} + +func (ct *Converter) ProcessType(t clang.Type) ast.Expr { + if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin { + return ct.ProcessBuiltinType(t) + } + + if t.Kind == clang.TypeElaborated { + return ct.ProcessElaboratedType(t) + } + + var expr ast.Expr + switch t.Kind { + case clang.TypePointer: + expr = &ast.PointerType{X: ct.ProcessType(t.PointeeType())} + case clang.TypeLValueReference: + expr = &ast.LvalueRefType{X: ct.ProcessType(t.NonReferenceType())} + case clang.TypeRValueReference: + expr = &ast.RvalueRefType{X: ct.ProcessType(t.NonReferenceType())} + case clang.TypeFunctionProto, clang.TypeFunctionNoProto: + // treating TypeFunctionNoProto as a general function without parameters + // function type will only collect return type, params will be collected in ProcessFuncDecl + expr = ct.ProcessFunctionType(t) + case clang.TypeConstantArray, clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray: + if t.Kind == clang.TypeConstantArray { + len := (*c.Char)(c.Malloc(unsafe.Sizeof(c.Char(0)) * 20)) + c.Sprintf(len, c.Str("%lld"), t.ArraySize()) + defer c.Free(unsafe.Pointer(len)) + expr = &ast.ArrayType{ + Elt: ct.ProcessType(t.ArrayElementType()), + Len: &ast.BasicLit{Kind: ast.IntLit, Value: c.GoString(len)}, + } + } else if t.Kind == clang.TypeIncompleteArray { + // incomplete array havent len expr + expr = &ast.ArrayType{ + Elt: ct.ProcessType(t.ArrayElementType()), + } + } + } + return expr +} + +// For function types, we can only obtain the parameter types, but not the parameter names. +// This is because we cannot reverse-lookup the corresponding declaration node from a function type. +// Note: For function declarations, parameter names are collected in the ProcessFuncDecl method. +func (ct *Converter) ProcessFunctionType(t clang.Type) *ast.FuncType { + // Note: Attempting to get the type declaration for a function type will result in CursorNoDeclFound + // cursor := t.TypeDeclaration() + // This would return CursorNoDeclFound + + ret := ct.ProcessType(t.ResultType()) + params := &ast.FieldList{} + numArgs := t.NumArgTypes() + for i := 0; i < int(numArgs); i++ { + argType := t.ArgType(c.Uint(i)) + params.List = append(params.List, &ast.Field{ + Type: ct.ProcessType(argType), + }) + } + if t.IsFunctionTypeVariadic() != 0 { + params.List = append(params.List, &ast.Field{ + Type: &ast.Variadic{}, + }) + } + + return &ast.FuncType{ + Ret: ret, + Params: params, + } +} + +func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl { + name := cursor.String() + defer name.Dispose() + + typ := ct.ProcessUnderlyingType(cursor) + + decl := &ast.TypedefDecl{ + DeclBase: ct.CreateDeclBase(cursor), + Name: &ast.Ident{Name: c.GoString(name.CStr())}, + Type: typ, + } + + ct.SetTypeDecl(cursor, decl) + return decl +} + +func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr { + underlyingTyp := cursor.TypedefDeclUnderlyingType() + if underlyingTyp.Kind != clang.TypeElaborated { + return ct.ProcessType(underlyingTyp) + } + + referTypeCursor := underlyingTyp.TypeDeclaration() + + // If the type decl for the reference already exists in anonyTypeMap + // then the refer has been processed in ProcessElaboratedType + if _, ok := ct.GetAnonyType(referTypeCursor); !ok && isCursorChildOf(referTypeCursor, cursor) { + // Handle unexpected named structures generated from anonymous RecordTypes in Typedefs + // In this case, libclang incorrectly reports an anonymous struct as a named struct + sourceCode := ct.GetTokens(referTypeCursor) + if isAnonymousStructure(sourceCode) { + ct.SetAnonyType(referTypeCursor) + typ, isValidType := ct.GetTypeDecl(referTypeCursor) + if isValidType { + // There will be no anonymous classes,here will execute enum,union,struct + // according to a normal anonymous decl + switch declType := typ.(type) { + case *ast.EnumTypeDecl: + declType.Name = nil + case *ast.TypeDecl: + if declType.Type.Tag != ast.Class { + declType.Name = nil + } else { + // Unreachable: There should be no anonymous classes in this context + fmt.Fprintln(os.Stderr, "unexpect typedef anonymous class %s", declType.Name.Name) + } + } + } else { + // Unreachable:When referencing an anonymous node, its collection must have been completed beforehand + fmt.Fprintln(os.Stderr, "anonymous node not collected before reference") + } + } + } + + return ct.ProcessElaboratedType(underlyingTyp) +} + +// converts functions, methods, constructors, destructors (including out-of-class decl) to ast.FuncDecl nodes. +func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { + name := cursor.String() + mangledName := cursor.Mangling() + defer name.Dispose() + defer mangledName.Dispose() + + // function type will only collect return type + // ProcessType can't get the field names,will collect in follows + funcType, ok := ct.ProcessType(cursor.Type()).(*ast.FuncType) + if !ok { + fmt.Println("failed to process function type") + return nil + } + params := ct.ProcessFieldList(cursor) + funcType.Params = params + + mangledNameStr := c.GoString(mangledName.CStr()) + if len(mangledNameStr) >= 1 && mangledNameStr[0] == '_' { + mangledNameStr = mangledNameStr[1:] + } + + funcDecl := &ast.FuncDecl{ + DeclBase: ct.CreateDeclBase(cursor), + Name: &ast.Ident{Name: c.GoString(name.CStr())}, + Type: funcType, + MangledName: mangledNameStr, + } + + if cursor.IsFunctionInlined() != 0 { + funcDecl.IsInline = true + } + + if isMethod(cursor) { + ct.ProcessMethodAttributes(cursor, funcDecl) + } else { + if cursor.StorageClass() == clang.SCStatic { + funcDecl.IsStatic = true + } + } + + ct.SetTypeDecl(cursor, funcDecl) + + return funcDecl +} + +// get Methods Attributes +func (ct *Converter) ProcessMethodAttributes(cursor clang.Cursor, fn *ast.FuncDecl) { + if parent := cursor.SemanticParent(); parent.Equal(cursor.LexicalParent()) != 1 { + fn.DeclBase.Parent = ct.BuildScopingExpr(cursor.SemanticParent()) + } + + switch cursor.Kind { + case clang.CursorDestructor: + fn.IsDestructor = true + case clang.CursorConstructor: + fn.IsConstructor = true + if cursor.IsExplicit() != 0 { + fn.IsExplicit = true + } + } + + if cursor.IsStatic() != 0 { + fn.IsStatic = true + } + if cursor.IsVirtual() != 0 || cursor.IsPureVirtual() != 0 { + fn.IsVirtual = true + } + if cursor.IsConst() != 0 { + fn.IsConst = true + } + + var numOverridden c.Uint + var overridden *clang.Cursor + cursor.OverriddenCursors(&overridden, &numOverridden) + if numOverridden > 0 { + fn.IsOverride = true + } + overridden.DisposeOverriddenCursors() +} + +type visitEnumContext struct { + enum *[]*ast.EnumItem + converter *Converter +} + +func visitEnum(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + ctx := (*visitEnumContext)(clientData) + if cursor.Kind == clang.CursorEnumConstantDecl { + name := cursor.String() + val := (*c.Char)(c.Malloc(unsafe.Sizeof(c.Char(0)) * 20)) + c.Sprintf(val, c.Str("%lld"), cursor.EnumConstantDeclValue()) + defer c.Free(unsafe.Pointer(val)) + defer name.Dispose() + enum := &ast.EnumItem{ + Name: &ast.Ident{Name: c.GoString(name.CStr())}, + Value: &ast.BasicLit{ + Kind: ast.IntLit, + Value: c.GoString(val), + }, + } + *ctx.enum = append(*ctx.enum, enum) + } + return clang.ChildVisit_Continue +} + +func (ct *Converter) ProcessEnumType(cursor clang.Cursor) *ast.EnumType { + items := make([]*ast.EnumItem, 0) + ctx := &visitEnumContext{ + enum: &items, + converter: ct, + } + clang.VisitChildren(cursor, visitEnum, c.Pointer(ctx)) + return &ast.EnumType{ + Items: items, + } +} + +func (ct *Converter) ProcessEnumDecl(cursor clang.Cursor) *ast.EnumTypeDecl { + name := cursor.String() + defer name.Dispose() + + decl := &ast.EnumTypeDecl{ + DeclBase: ct.CreateDeclBase(cursor), + Name: &ast.Ident{Name: c.GoString(name.CStr())}, + Type: ct.ProcessEnumType(cursor), + } + ct.SetTypeDecl(cursor, decl) + return decl +} + +// current only collect macro which defined in file +func (ct *Converter) ProcessMacro(cursor clang.Cursor) *ast.Macro { + name := cursor.String() + defer name.Dispose() + + macro := &ast.Macro{ + Name: c.GoString(name.CStr()), + Tokens: ct.GetTokens(cursor), + } + return macro +} + +func (ct *Converter) ProcessInclude(cursor clang.Cursor) *ast.Include { + name := cursor.String() + defer name.Dispose() + return &ast.Include{Path: c.GoString(name.CStr())} +} + +type visitFieldContext struct { + params *ast.FieldList + converter *Converter +} + +func (p *visitFieldContext) createBaseField(cursor clang.Cursor) *ast.Field { + field := &ast.Field{ + Type: p.converter.ProcessType(cursor.Type()), + } + fieldName := cursor.String() + defer fieldName.Dispose() + + commentGroup, isDoc := p.converter.ParseCommentGroup(cursor) + if commentGroup != nil { + if isDoc { + field.Doc = commentGroup + } else { + field.Comment = commentGroup + } + } + if name := fieldName.CStr(); name != nil { + field.Names = []*ast.Ident{{Name: c.GoString(name)}} + } + return field +} +func visitFieldList(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + ctx := (*visitFieldContext)(clientData) + + switch cursor.Kind { + case clang.CursorParmDecl, clang.CursorFieldDecl: + // In C language, parameter lists do not have similar parameter grouping in Go. + // func foo(a, b int) + + // For follows struct, it will also parse to two FieldDecl + // struct A { + // int a, b; + // }; + field := ctx.createBaseField(cursor) + if cursor.Kind == clang.CursorFieldDecl { + field.Access = ast.AccessSpecifier(cursor.CXXAccessSpecifier()) + } + + ctx.params.List = append(ctx.params.List, field) + + case clang.CursorVarDecl: + if cursor.StorageClass() == clang.SCStatic { + // static member variable + field := ctx.createBaseField(cursor) + field.Access = ast.AccessSpecifier(cursor.CXXAccessSpecifier()) + field.IsStatic = true + ctx.params.List = append(ctx.params.List, field) + } + } + + return clang.ChildVisit_Continue +} + +// For Record Type(struct,union ...) & Func 's FieldList +func (ct *Converter) ProcessFieldList(cursor clang.Cursor) *ast.FieldList { + params := &ast.FieldList{} + ctx := &visitFieldContext{ + params: params, + converter: ct, + } + clang.VisitChildren(cursor, visitFieldList, c.Pointer(ctx)) + if (cursor.Kind == clang.CursorFunctionDecl || isMethod(cursor)) && cursor.IsVariadic() != 0 { + params.List = append(params.List, &ast.Field{ + Type: &ast.Variadic{}, + }) + } + return params +} + +type visitMethodsContext struct { + methods *[]*ast.FuncDecl + converter *Converter +} + +func visitMethods(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + ctx := (*visitMethodsContext)(clientData) + if isMethod(cursor) && cursor.CXXAccessSpecifier() == clang.CXXPublic { + method := ctx.converter.ProcessFuncDecl(cursor) + if method != nil { + *ctx.methods = append(*ctx.methods, method) + } + } + return clang.ChildVisit_Continue +} + +// Note:Public Method is considered +func (ct *Converter) ProcessMethods(cursor clang.Cursor) []*ast.FuncDecl { + methods := make([]*ast.FuncDecl, 0) + ctx := &visitMethodsContext{ + methods: &methods, + converter: ct, + } + clang.VisitChildren(cursor, visitMethods, c.Pointer(ctx)) + return methods +} + +func (ct *Converter) ProcessRecordDecl(cursor clang.Cursor) *ast.TypeDecl { + anony := cursor.IsAnonymousRecordDecl() + var name *ast.Ident + if anony == 0 { + cursorName := cursor.String() + defer cursorName.Dispose() + name = &ast.Ident{Name: c.GoString(cursorName.CStr())} + } + + decl := &ast.TypeDecl{ + DeclBase: ct.CreateDeclBase(cursor), + Name: name, + Type: ct.ProcessRecordType(cursor), + } + ct.SetTypeDecl(cursor, decl) + + return decl +} + +func (ct *Converter) ProcessStructDecl(cursor clang.Cursor) *ast.TypeDecl { + return ct.ProcessRecordDecl(cursor) +} + +func (ct *Converter) ProcessUnionDecl(cursor clang.Cursor) *ast.TypeDecl { + return ct.ProcessRecordDecl(cursor) +} + +func (ct *Converter) ProcessClassDecl(cursor clang.Cursor) *ast.TypeDecl { + // Pushing class scope before processing its type and popping after + base := ct.CreateDeclBase(cursor) + typ := ct.ProcessRecordType(cursor) + + decl := &ast.TypeDecl{ + DeclBase: base, + Name: &ast.Ident{Name: c.GoString(cursor.String().CStr())}, + Type: typ, + } + ct.SetTypeDecl(cursor, decl) + + return decl +} + +func (ct *Converter) ProcessRecordType(cursor clang.Cursor) *ast.RecordType { + return &ast.RecordType{ + Tag: toTag(cursor.Kind), + Fields: ct.ProcessFieldList(cursor), + Methods: ct.ProcessMethods(cursor), + } +} + +// process ElaboratedType Reference +// +// 1. Named elaborated type references: +// - Examples: struct MyStruct, union MyUnion, class MyClass, enum MyEnum +// - Handling: Constructed as TagExpr or ScopingExpr references +// +// 2. Anonymous elaborated type references: +// - Examples: struct { int x; int y; }, union { int a; float b; } +// - Handling: Retrieve their corresponding concrete types +func (ct *Converter) ProcessElaboratedType(t clang.Type) ast.Expr { + name := t.String() + defer name.Dispose() + + decl := t.TypeDeclaration() + isAnony, ok := ct.GetAnonyType(decl) + + if decl.IsAnonymous() != 0 || isAnony && ok { + // anonymous type refer (except anonymous RecordType&EnumType in TypedefDecl) + if decl.Kind == clang.CursorEnumDecl { + return ct.ProcessEnumType(decl) + } + return ct.ProcessRecordType(decl) + } + + typeName := c.GoString(name.CStr()) + + // for elaborated type, it could have a tag description + // like struct A, union B, class C, enum D + parts := strings.SplitN(typeName, " ", 2) + if len(parts) == 2 { + if tagValue, ok := tagMap[parts[0]]; ok { + return &ast.TagExpr{ + Tag: tagValue, + Name: ct.BuildScopingExpr(decl), + } + } + } + + return ct.BuildScopingExpr(decl) +} + +func (ct *Converter) ProcessBuiltinType(t clang.Type) *ast.BuiltinType { + kind := ast.Void + var flags ast.TypeFlag + + switch t.Kind { + case clang.TypeVoid: + kind = ast.Void + case clang.TypeBool: + kind = ast.Bool + case clang.TypeCharU, clang.TypeUChar, clang.TypeCharS, clang.TypeSChar: + kind = ast.Char + case clang.TypeChar16: + kind = ast.Char16 + case clang.TypeChar32: + kind = ast.Char32 + case clang.TypeWChar: + kind = ast.WChar + case clang.TypeShort, clang.TypeUShort: + kind = ast.Int + flags |= ast.Short + case clang.TypeInt, clang.TypeUInt: + kind = ast.Int + case clang.TypeLong, clang.TypeULong: + kind = ast.Int + flags |= ast.Long + case clang.TypeLongLong, clang.TypeULongLong: + kind = ast.Int + flags |= ast.LongLong + case clang.TypeInt128, clang.TypeUInt128: + kind = ast.Int128 + case clang.TypeFloat: + kind = ast.Float + case clang.TypeHalf, clang.TypeFloat16: + kind = ast.Float16 + case clang.TypeDouble: + kind = ast.Float + flags |= ast.Double + case clang.TypeLongDouble: + kind = ast.Float + flags |= ast.Long | ast.Double + case clang.TypeFloat128: + kind = ast.Float128 + case clang.TypeComplex: + kind = ast.Complex + complexKind := t.ElementType().Kind + if complexKind == clang.TypeLongDouble { + flags |= ast.Long | ast.Double + } else if complexKind == clang.TypeDouble { + flags |= ast.Double + } + // float complfex flag is not set + default: + // like IBM128,NullPtr,Accum + kindStr := t.Kind.String() + defer kindStr.Dispose() + fmt.Fprintln(os.Stderr, "todo: unknown builtin type:", c.GoString(kindStr.CStr())) + } + + if IsExplicitSigned(t) { + flags |= ast.Signed + } else if IsExplicitUnsigned(t) { + flags |= ast.Unsigned + } + + return &ast.BuiltinType{ + Kind: kind, + Flags: flags, + } +} + +// Constructs a complete scoping expression by traversing the semantic parents, starting from the given clang.Cursor +// For anonymous decl of typedef references, use their anonymous name +func (ct *Converter) BuildScopingExpr(cursor clang.Cursor) ast.Expr { + parts := ct.BuildScopingParts(cursor) + return buildScopingFromParts(parts) +} + +func (ct *Converter) BuildScopingParts(cursor clang.Cursor) []string { + var parts []string + // Traverse up the semantic parents + for cursor.IsNull() != 1 && cursor.Kind != clang.CursorTranslationUnit { + name := cursor.String() + qualified := c.GoString(name.CStr()) + parts = append([]string{qualified}, parts...) + cursor = cursor.SemanticParent() + name.Dispose() + } + return parts +} + +func (ct *Converter) MarshalASTFiles() *cjson.JSON { + return MarshalASTFiles(ct.Files) +} + +func (ct *Converter) MarshalOutputASTFiles() *cjson.JSON { + return MarshalOutputASTFiles(ct.Files) +} + +func IsExplicitSigned(t clang.Type) bool { + return t.Kind == clang.TypeCharS || t.Kind == clang.TypeSChar +} + +func IsExplicitUnsigned(t clang.Type) bool { + return t.Kind == clang.TypeCharU || t.Kind == clang.TypeUChar || + t.Kind == clang.TypeUShort || t.Kind == clang.TypeUInt || + t.Kind == clang.TypeULong || t.Kind == clang.TypeULongLong || + t.Kind == clang.TypeUInt128 +} + +func toTag(kind clang.CursorKind) ast.Tag { + switch kind { + case clang.CursorStructDecl: + return ast.Struct + case clang.CursorUnionDecl: + return ast.Union + case clang.CursorClassDecl: + return ast.Class + default: + panic(fmt.Sprintf("Unexpected cursor kind in toTag: %v", kind)) + } +} + +func toToken(tok clang.Token) token.Token { + if tok.Kind() < clang.Punctuation || tok.Kind() > clang.Comment { + return token.ILLEGAL + } else { + return token.Token(tok.Kind() + 1) + } +} +func isMethod(cursor clang.Cursor) bool { + return cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor +} + +func buildScopingFromParts(parts []string) ast.Expr { + if len(parts) == 0 { + return nil + } + + var expr ast.Expr = &ast.Ident{Name: parts[0]} + for _, part := range parts[1:] { + expr = &ast.ScopingExpr{ + Parent: expr, + X: &ast.Ident{Name: part}, + } + } + return expr +} + +// isCursorChildOf checks if the child cursor is contained within the parent cursor. +// This function is necessary because libclang doesn't correctly report the lexical +// or semantic parent for anonymous structs inside typedefs. By comparing source ranges, +// we can determine if one cursor is nested inside another. +func isCursorChildOf(child, parent clang.Cursor) bool { + return isRangeChildOf(child.Extent(), parent.Extent()) +} + +func isRangeChildOf(childRange, parentRange clang.SourceRange) bool { + return getOffset(childRange.RangeStart()) >= getOffset(parentRange.RangeStart()) && + getOffset(childRange.RangeEnd()) <= getOffset(parentRange.RangeEnd()) +} + +func getOffset(location clang.SourceLocation) c.Uint { + var offset c.Uint + location.SpellingLocation(nil, nil, nil, &offset) + return offset +} + +// checks if the source code represents an actual anonymous structure +func isAnonymousStructure(sourceCode []*ast.Token) bool { + _, isValidTag := tagMap[sourceCode[0].Lit] + return sourceCode[0].Token == token.KEYWORD && + isValidTag && + sourceCode[1].Token == token.PUNCT && + sourceCode[1].Lit == "{" +} 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..a72e16b0 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/cvt.go @@ -0,0 +1,94 @@ +package cvttest + +import ( + "fmt" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/c/clang" + "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse" +) + +func RunTest(testName string, testCases []string) { + for i, content := range testCases { + converter, err := parse.NewConverter(&parse.Config{ + File: content, + Temp: true, + IsCpp: true, + }) + if err != nil { + panic(err) + } + + _, err = converter.Convert() + if err != nil { + panic(err) + } + + result := converter.MarshalASTFiles() + str := result.Print() + c.Printf(c.Str("%s Case %d:\n%s\n\n"), c.AllocaCStr(testName), c.Int(i+1), str) + + cjson.FreeCStr(str) + result.Delete() + converter.Dispose() + } +} + +type GetTypeOptions struct { + TypeCode string // e.g. "char*", "char**" + + // ExpectTypeKind specifies the expected type kind (optional) + // Use clang.Type_Invalid to accept any type (default behavior) + // *For complex types (when is included), specifying this is crucial + // to filter out the correct type, as there will be multiple VarDecl fields present + ExpectTypeKind clang.TypeKind + + // Args contains additional compilation arguments passed to Clang (optional) + // 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 +// Need to dispose the index and unit after using +// e.g. index.Dispose(), unit.Dispose() +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, + IsCpp: option.IsCpp, + }) + if err != nil { + panic(err) + } + cursor := unit.Cursor() + visitType := &typeVisitData{typ: &clang.Type{}, expectTypeKind: option.ExpectTypeKind} + + clang.VisitChildren(cursor, typeVisit, unsafe.Pointer(visitType)) + return *visitType.typ, index, unit +} + +type typeVisitData struct { + typ *clang.Type + expectTypeKind clang.TypeKind +} + +func typeVisit(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + visitData := (*typeVisitData)(clientData) + if cursor.Kind == clang.CursorVarDecl && (visitData.expectTypeKind == clang.TypeInvalid || cursor.Type().Kind == visitData.expectTypeKind) { + *visitData.typ = cursor.Type() + return clang.ChildVisit_Break + } + return clang.ChildVisit_Continue +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go new file mode 100644 index 00000000..fd2d3847 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go @@ -0,0 +1,53 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestClassDecl() +} + +func TestClassDecl() { + testCases := []string{ + `class A { + public: + int a; + int b; + };`, + `class A { + public: + static int a; + int b; + float foo(int a,double b); + private: + static void bar(); + protected: + void bar2(); + };`, + `class A { + public: + A(); + explicit A(); + ~A(); + static inline void foo(); + };`, + `class Base { + public: + Base(); + virtual ~Base(); + virtual void foo(); + }; + class Derived : public Base { + public: + Derived(); + ~Derived() override; + void foo() override; + }; + `, + `namespace A{ + class Foo{} + } + void A::Foo::bar(); + `, + } + test.RunTest("TestClassDecl", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect new file mode 100644 index 00000000..c75368df --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect @@ -0,0 +1,713 @@ +#stdout +TestClassDecl Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestClassDecl Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": true, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN1A3fooEid", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 8, + "Flags": 16 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 8, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestClassDecl Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": null + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "MangledName": "_ZN1AC1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "MangledName": "_ZN1AC1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": true, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "~A" + }, + "MangledName": "_ZN1AD1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": true, + "IsVirtual": false, + "IsOverride": false + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN1A3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": true, + "IsStatic": true, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestClassDecl Case 4: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Base" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": null + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "Base" + }, + "Name": { + "_Type": "Ident", + "Name": "Base" + }, + "MangledName": "_ZN4BaseC1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "Base" + }, + "Name": { + "_Type": "Ident", + "Name": "~Base" + }, + "MangledName": "_ZN4BaseD1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": true, + "IsVirtual": true, + "IsOverride": false + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "Base" + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN4Base3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": true, + "IsOverride": false + }] + } + }, { + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Derived" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": null + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "Derived" + }, + "Name": { + "_Type": "Ident", + "Name": "Derived" + }, + "MangledName": "_ZN7DerivedC1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "Derived" + }, + "Name": { + "_Type": "Ident", + "Name": "~Derived" + }, + "MangledName": "_ZN7DerivedD1Ev", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": true, + "IsVirtual": true, + "IsOverride": true + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "Derived" + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN7Derived3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": true, + "IsOverride": true + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestClassDecl Case 5: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": null + }, + "Methods": [] + } + }, { + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "Foo" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Name": { + "_Type": "Ident", + "Name": "bar" + }, + "MangledName": "_ZN1A3Foo3barEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/comment_test/comment.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/comment_test/comment.go new file mode 100644 index 00000000..0747e142 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/comment_test/comment.go @@ -0,0 +1,78 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestDoc() +} + +func TestDoc() { + testCases := []string{ + ` +// not read doc 1 +void foo();`, + ` +/* not read doc 2 */ +void foo();`, + ` +/// doc +void foo();`, + ` +/** doc */ +void foo();`, + ` +/*! doc */ +void foo();`, + ` +/// doc 1 +/// doc 2 +void foo();`, + ` +/*! doc 1 */ +/*! doc 2 */ +void foo();`, + ` +/** doc 1 */ +/** doc 1 */ +void foo();`, + ` +/** + * doc 1 + * doc 2 + */ +void foo();`, + ` + struct Foo { + /// doc + int x; + int y; ///< comment + /** + * field doc (parse ignore with comment in same cursor) + */ + int z; /*!< comment */ + }; + `, + ` +class Doc +{ + public: + /** + * static field doc + */ + static int x; + static int y; /*!< static field comment */ + /** + * field doc + */ + int a; + int b; ///< field comment + /** + * method doc + */ + void Foo(); + protected: + int value; /*!< protected field comment */ +};`, + } + test.RunTest("TestDoc", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/comment_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/comment_test/llgo.expect new file mode 100644 index 00000000..0a08f88d --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/comment_test/llgo.expect @@ -0,0 +1,742 @@ +#stdout +TestDoc Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/// doc" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 4: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/** doc */" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 5: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/*! doc */" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 6: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/// doc 1" + }, { + "_Type": "Comment", + "Text": "/// doc 2" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 7: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/*! doc 1 */" + }, { + "_Type": "Comment", + "Text": "/*! doc 2 */" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 8: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/** doc 1 */" + }, { + "_Type": "Comment", + "Text": "/** doc 1 */" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 9: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/**" + }, { + "_Type": "Comment", + "Text": " * doc 1" + }, { + "_Type": "Comment", + "Text": " * doc 2" + }, { + "_Type": "Comment", + "Text": " */" + }] + }, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 10: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/// doc" + }] + }, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "///< comment" + }] + }, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "y" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/*!< comment */" + }] + }, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "z" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestDoc Case 11: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Doc" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/** " + }, { + "_Type": "Comment", + "Text": " * static field doc" + }, { + "_Type": "Comment", + "Text": " */" + }] + }, + "Comment": null, + "IsStatic": true, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/*!< static field comment */" + }] + }, + "IsStatic": true, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "y" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/** " + }, { + "_Type": "Comment", + "Text": " * field doc" + }, { + "_Type": "Comment", + "Text": " */" + }] + }, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "///< field comment" + }] + }, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/*!< protected field comment */" + }] + }, + "IsStatic": false, + "Access": 2, + "Names": [{ + "_Type": "Ident", + "Name": "value" + }] + }] + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": { + "_Type": "CommentGroup", + "List": [{ + "_Type": "Comment", + "Text": "/** " + }, { + "_Type": "Comment", + "Text": " * method doc" + }, { + "_Type": "Comment", + "Text": " */" + }] + }, + "Parent": { + "_Type": "Ident", + "Name": "Doc" + }, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "MangledName": "_ZN3Doc3FooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }] + } + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/enum_test/enum.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/enum_test/enum.go new file mode 100644 index 00000000..8ed4cba7 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/enum_test/enum.go @@ -0,0 +1,28 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestEnumDecl() +} + +func TestEnumDecl() { + testCases := []string{ + `enum Foo { + a, + b, + c, + };`, + `enum Foo { + a = 1, + b = 2, + c = 4, + };`, + `enum Foo { + a = 1, + b, + c, + };`, + } + test.RunTest("TestEnumDecl", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/enum_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/enum_test/llgo.expect new file mode 100644 index 00000000..b82d9957 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/enum_test/llgo.expect @@ -0,0 +1,182 @@ +#stdout +TestEnumDecl Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "EnumTypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "EnumType", + "Items": [{ + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "a" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "0" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "b" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "1" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "c" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "2" + } + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestEnumDecl Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "EnumTypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "EnumType", + "Items": [{ + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "a" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "1" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "b" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "2" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "c" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "4" + } + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestEnumDecl Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "EnumTypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "EnumType", + "Items": [{ + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "a" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "1" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "b" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "2" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "c" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "3" + } + }] + } + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/func_test/func.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/func_test/func.go new file mode 100644 index 00000000..f2e18e17 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/func_test/func.go @@ -0,0 +1,18 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestFuncDecl() +} + +func TestFuncDecl() { + testCases := []string{ + `void foo();`, + `void foo(int a);`, + `void foo(int a,...);`, + `float* foo(int a,double b);`, + `static inline int add(int a, int b);`, + } + test.RunTest("TestFuncDecl", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/func_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/func_test/llgo.expect new file mode 100644 index 00000000..383660fb --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/func_test/llgo.expect @@ -0,0 +1,323 @@ +#stdout +TestFuncDecl Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestFuncDecl Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3fooi", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestFuncDecl Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3fooiz", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "Variadic" + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestFuncDecl Case 4: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3fooid", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 8, + "Flags": 16 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Ret": { + "_Type": "PointerType", + "X": { + "_Type": "BuiltinType", + "Kind": 8, + "Flags": 0 + } + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestFuncDecl Case 5: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "add" + }, + "MangledName": "_ZL3addii", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + }, + "IsInline": true, + "IsStatic": true, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/scope_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/scope_test/llgo.expect new file mode 100644 index 00000000..66093d7f --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/scope_test/llgo.expect @@ -0,0 +1,291 @@ +#stdout +TestScope Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_Z3foov", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestScope Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "a" + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN1a3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestScope Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "b" + }, + "Parent": { + "_Type": "Ident", + "Name": "a" + } + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN1a1b3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + +TestScope Case 4: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "a" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": null + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "a" + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN1a3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestScope Case 5: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "a" + }, + "Name": { + "_Type": "Ident", + "Name": "b" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": null + }, + "Methods": [{ + "_Type": "FuncDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "b" + }, + "Parent": { + "_Type": "Ident", + "Name": "a" + } + }, + "Name": { + "_Type": "Ident", + "Name": "foo" + }, + "MangledName": "_ZN1a1b3fooEv", + "Type": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": null + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }] + } + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/scope_test/scope.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/scope_test/scope.go new file mode 100644 index 00000000..29332bfb --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/scope_test/scope.go @@ -0,0 +1,32 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestScope() +} + +func TestScope() { + testCases := []string{ + `void foo();`, + `namespace a { + void foo(); + }`, + `namespace a { + namespace b { + void foo(); + } + }`, + `class a { + public: + void foo(); + };`, + `namespace a { + class b { + public: + void foo(); + }; + }`, + } + test.RunTest("TestScope", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/struct_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/struct_test/llgo.expect new file mode 100644 index 00000000..3440c6e3 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/struct_test/llgo.expect @@ -0,0 +1,375 @@ +#stdout +TestStructDecl Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": null, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestStructDecl Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestStructDecl Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestStructDecl Case 4: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + } + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "Foo" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestStructDecl Case 5: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Person" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "age" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "year" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "day" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "month" + }] + }] + }, + "Methods": [] + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "birthday" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/struct_test/struct.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/struct_test/struct.go new file mode 100644 index 00000000..39d40d8c --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/struct_test/struct.go @@ -0,0 +1,35 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestStructDecl() +} + +func TestStructDecl() { + testCases := []string{ + `struct { + int a; + };`, + `struct A { + int a; + int b; + };`, + `struct A { + int a, b; + };`, + `struct A { + int a; + int (*Foo)(int, int); + };`, + `struct Person { + int age; + struct { + int year; + int day; + int month; + } birthday; + };`, + } + test.RunTest("TestStructDecl", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect new file mode 100644 index 00000000..43bb1f8e --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect @@ -0,0 +1,1179 @@ +#stdout +TestTypeDefDecl Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "INT" + }, + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "INT" + }, + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "STANDARD_INT" + }, + "Type": { + "_Type": "Ident", + "Name": "INT" + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "INT" + }, + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "IntPtr" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "IntArr" + }, + "Type": { + "_Type": "ArrayType", + "Elt": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Len": null + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 4: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }, { + "_Type": "Field", + "Type": { + "_Type": "Variadic" + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + } + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 5: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + } + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "Bar" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }, { + "_Type": "Field", + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "BuiltinType", + "Kind": 0, + "Flags": 0 + } + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + } + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 6: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Type": { + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 3, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "MyClass" + }, + "Type": { + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "Foo" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Tag": 3 + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "MyClassPtr" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "Foo" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Tag": 3 + } + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "Ident", + "Name": "A" + }, + "Name": { + "_Type": "Ident", + "Name": "MyClassArray" + }, + "Type": { + "_Type": "ArrayType", + "Elt": { + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "Foo" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Tag": 3 + }, + "Len": null + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 7: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": null, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "MyStruct" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 8: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": null, + "Type": { + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "MyUnion" + }, + "Type": { + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 9: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "EnumTypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": null, + "Type": { + "_Type": "EnumType", + "Items": [{ + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "RED" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "0" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "GREEN" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "1" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "BLUE" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "2" + } + }] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "MyEnum" + }, + "Type": { + "_Type": "EnumType", + "Items": [{ + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "RED" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "0" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "GREEN" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "1" + } + }, { + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "BLUE" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "2" + } + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 10: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": null, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "MyStruct" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "MyStruct2" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "StructPtr" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "StructArr" + }, + "Type": { + "_Type": "ArrayType", + "Elt": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + }, + "Len": null + } + }], + "includes": [], + "macros": [] + } +} + +TestTypeDefDecl Case 11: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Name": null, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Name": { + "_Type": "Ident", + "Name": "MyStruct" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Name": { + "_Type": "Ident", + "Name": "MyStruct2" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Name": { + "_Type": "Ident", + "Name": "StructPtr" + }, + "Type": { + "_Type": "PointerType", + "X": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + } + } + }, { + "_Type": "TypedefDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + }, + "Name": { + "_Type": "Ident", + "Name": "StructArr" + }, + "Type": { + "_Type": "ArrayType", + "Elt": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] + }, + "Len": null + } + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/typedef.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/typedef.go new file mode 100644 index 00000000..623b4dde --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/typedef.go @@ -0,0 +1,53 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestTypeDefDecl() +} + +func TestTypeDefDecl() { + testCases := []string{ + `typedef int INT;`, + + `typedef int INT; + typedef INT STANDARD_INT;`, + + `typedef int INT,*IntPtr,IntArr[];`, + + `typedef int (*Foo)(int, int, ...);`, + + `typedef int (*Foo)(int, int),(*Bar)(void*,void*);`, + + `namespace A { + typedef class Foo{ + int x; + } MyClass,*MyClassPtr,MyClassArray[]; + }`, + + `typedef struct { + int x; + } MyStruct`, + `typedef union { + int x; + } MyUnion`, + `typedef enum { + RED, + GREEN, + BLUE + } MyEnum`, + + `typedef struct { + int x; + } MyStruct,MyStruct2,*StructPtr, StructArr[];`, + + `namespace A{ + namespace B{ + typedef struct { + int x; + } MyStruct,MyStruct2,*StructPtr, StructArr[]; + } + }`, + } + test.RunTest("TestTypeDefDecl", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/union_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/union_test/llgo.expect new file mode 100644 index 00000000..7be1d152 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/union_test/llgo.expect @@ -0,0 +1,234 @@ +#stdout +TestUnionDecl Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": null, + "Type": { + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestUnionDecl Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "A" + }, + "Type": { + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "a" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "b" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + +TestUnionDecl Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "OuterUnion" + }, + "Type": { + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "i" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 8, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "f" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "c" + }] + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 32 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "s" + }] + }] + }, + "Methods": [] + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "inner" + }] + }] + }, + "Methods": [] + } + }], + "includes": [], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/union_test/union.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/union_test/union.go new file mode 100644 index 00000000..5e8c18b5 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/union_test/union.go @@ -0,0 +1,29 @@ +package main + +import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + +func main() { + TestUnionDecl() +} + +func TestUnionDecl() { + testCases := []string{ + `union { + int a; + int b; + };`, + `union A { + int a; + int b; + };`, + `union OuterUnion { + int i; + float f; + union { + char c; + short s; + } inner; + };`, + } + test.RunTest("TestUnionDecl", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect new file mode 100644 index 00000000..ac0d4605 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect @@ -0,0 +1,124 @@ +#stdout +TestDefine Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [], + "includes": [], + "macros": [{ + "_Type": "Macro", + "Name": "DEBUG", + "Tokens": [{ + "_Type": "Token", + "Token": 3, + "Lit": "DEBUG" + }] + }] + } +} + +TestDefine Case 2: +{ + "temp.h": { + "_Type": "File", + "decls": [], + "includes": [], + "macros": [{ + "_Type": "Macro", + "Name": "OK", + "Tokens": [{ + "_Type": "Token", + "Token": 3, + "Lit": "OK" + }, { + "_Type": "Token", + "Token": 4, + "Lit": "1" + }] + }] + } +} + +TestDefine Case 3: +{ + "temp.h": { + "_Type": "File", + "decls": [], + "includes": [], + "macros": [{ + "_Type": "Macro", + "Name": "SQUARE", + "Tokens": [{ + "_Type": "Token", + "Token": 3, + "Lit": "SQUARE" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "(" + }, { + "_Type": "Token", + "Token": 3, + "Lit": "x" + }, { + "_Type": "Token", + "Token": 1, + "Lit": ")" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "(" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "(" + }, { + "_Type": "Token", + "Token": 3, + "Lit": "x" + }, { + "_Type": "Token", + "Token": 1, + "Lit": ")" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "*" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "(" + }, { + "_Type": "Token", + "Token": 3, + "Lit": "x" + }, { + "_Type": "Token", + "Token": 1, + "Lit": ")" + }, { + "_Type": "Token", + "Token": 1, + "Lit": ")" + }] + }] + } +} + +TestInclude Case 1: +{ + "temp.h": { + "_Type": "File", + "decls": [], + "includes": [{ + "_Type": "Include", + "Path": "foo.h" + }], + "macros": [] + } +} + + +#stderr + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go new file mode 100644 index 00000000..df41579b --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go @@ -0,0 +1,27 @@ +package main + +import ( + test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" +) + +func main() { + TestDefine() + TestInclude() +} + +func TestDefine() { + testCases := []string{ + `#define DEBUG`, + `#define OK 1`, + `#define SQUARE(x) ((x) * (x))`, + } + test.RunTest("TestDefine", testCases) +} + +func TestInclude() { + testCases := []string{ + `#include "foo.h"`, + // `#include `, // Standard libraries are mostly platform-dependent + } + test.RunTest("TestInclude", testCases) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/llgo.expect new file mode 100644 index 00000000..d7e93459 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/llgo.expect @@ -0,0 +1,350 @@ +#stdout +Void:flags:0 kind:0 +Bool:flags:0 kind:1 +Char_S:flags:1 kind:2 +Char_U:flags:2 kind:2 +Char16:flags:0 kind:3 +Char32:flags:0 kind:4 +WChar:flags:0 kind:5 +Short:flags:32 kind:6 +UShort:flags:34 kind:6 +Int:flags:0 kind:6 +UInt:flags:2 kind:6 +Long:flags:4 kind:6 +ULong:flags:6 kind:6 +LongLong:flags:8 kind:6 +ULongLong:flags:10 kind:6 +Int128:flags:0 kind:7 +UInt128:flags:2 kind:7 +Float:flags:0 kind:8 +Half:flags:0 kind:9 +Float16:flags:0 kind:9 +Double:flags:16 kind:8 +LongDouble:flags:20 kind:8 +Float128:flags:0 kind:10 +Complex:flags:0 kind:11 +Complex:flags:16 kind:11 +Complex:flags:20 kind:11 +Unknown:flags:0 kind:0 +Type: char *: +{ + "_Type": "PointerType", + "X": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + } +} +Type: char ***: +{ + "_Type": "PointerType", + "X": { + "_Type": "PointerType", + "X": { + "_Type": "PointerType", + "X": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + } + } + } +} +Type: char[]: +{ + "_Type": "ArrayType", + "Elt": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + }, + "Len": null +} +Type: char[10]: +{ + "_Type": "ArrayType", + "Elt": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + }, + "Len": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "10" + } +} +Type: char[3][4]: +{ + "_Type": "ArrayType", + "Elt": { + "_Type": "ArrayType", + "Elt": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + }, + "Len": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "4" + } + }, + "Len": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "3" + } +} +Type: int &: +{ + "_Type": "LvalueRefType", + "X": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } +} +Type: int &&: +{ + "_Type": "RvalueRefType", + "X": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } +} +Type: Foo: +{ + "_Type": "Ident", + "Name": "Foo" +} +Type: struct Foo: +{ + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Tag": 0 +} +Type: struct (unnamed struct at temp.h:1:1): +{ + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] +} +Type: Foo: +{ + "_Type": "Ident", + "Name": "Foo" +} +Type: union Foo: +{ + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Tag": 1 +} +Type: union (unnamed union at temp.h:1:1): +{ + "_Type": "RecordType", + "Tag": 1, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] +} +Type: Foo: +{ + "_Type": "Ident", + "Name": "Foo" +} +Type: enum Foo: +{ + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Tag": 2 +} +Type: enum (unnamed enum at temp.h:1:1): +{ + "_Type": "EnumType", + "Items": [{ + "_Type": "EnumItem", + "Name": { + "_Type": "Ident", + "Name": "x" + }, + "Value": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "42" + } + }] +} +Type: Foo: +{ + "_Type": "Ident", + "Name": "Foo" +} +Type: class Foo: +{ + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "Foo" + }, + "Tag": 3 +} +Type: class (unnamed class at temp.h:1:1): +{ + "_Type": "RecordType", + "Tag": 3, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 3, + "Names": [{ + "_Type": "Ident", + "Name": "x" + }] + }] + }, + "Methods": [] +} +Type: a::b::c: +{ + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "c" + }, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "b" + }, + "Parent": { + "_Type": "Ident", + "Name": "a" + } + } +} +Type: class a::b::c: +{ + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "c" + }, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "b" + }, + "Parent": { + "_Type": "Ident", + "Name": "a" + } + } + }, + "Tag": 3 +} +Type: int (*)(int, char): +{ + "_Type": "PointerType", + "X": { + "_Type": "FuncType", + "Params": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }, { + "_Type": "Field", + "Type": { + "_Type": "BuiltinType", + "Kind": 2, + "Flags": 1 + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 0, + "Names": null + }] + }, + "Ret": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + } + } +} + +#stderr +todo: unknown builtin type: Ibm128 + +#exit 0 diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go new file mode 100644 index 00000000..03a5771f --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/type_test/type.go @@ -0,0 +1,175 @@ +package main + +import ( + "fmt" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/c/clang" + "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse" + test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + "github.com/goplus/llgo/chore/llcppg/ast" +) + +func main() { + TestBuiltinType() + TestNonBuiltinTypes() +} +func TestBuiltinType() { + tests := []struct { + name string + typ clang.Type + expected ast.BuiltinType + }{ + {"Void", btType(clang.TypeVoid), ast.BuiltinType{Kind: ast.Void}}, + {"Bool", btType(clang.TypeBool), ast.BuiltinType{Kind: ast.Bool}}, + {"Char_S", btType(clang.TypeCharS), ast.BuiltinType{Kind: ast.Char, Flags: ast.Signed}}, + {"Char_U", btType(clang.TypeCharU), ast.BuiltinType{Kind: ast.Char, Flags: ast.Unsigned}}, + {"Char16", btType(clang.TypeChar16), ast.BuiltinType{Kind: ast.Char16}}, + {"Char32", btType(clang.TypeChar32), ast.BuiltinType{Kind: ast.Char32}}, + {"WChar", btType(clang.TypeWChar), ast.BuiltinType{Kind: ast.WChar}}, + {"Short", btType(clang.TypeShort), ast.BuiltinType{Kind: ast.Int, Flags: ast.Short}}, + {"UShort", btType(clang.TypeUShort), ast.BuiltinType{Kind: ast.Int, Flags: ast.Short | ast.Unsigned}}, + {"Int", btType(clang.TypeInt), ast.BuiltinType{Kind: ast.Int}}, + {"UInt", btType(clang.TypeUInt), ast.BuiltinType{Kind: ast.Int, Flags: ast.Unsigned}}, + {"Long", btType(clang.TypeLong), ast.BuiltinType{Kind: ast.Int, Flags: ast.Long}}, + {"ULong", btType(clang.TypeULong), ast.BuiltinType{Kind: ast.Int, Flags: ast.Long | ast.Unsigned}}, + {"LongLong", btType(clang.TypeLongLong), ast.BuiltinType{Kind: ast.Int, Flags: ast.LongLong}}, + {"ULongLong", btType(clang.TypeULongLong), ast.BuiltinType{Kind: ast.Int, Flags: ast.LongLong | ast.Unsigned}}, + {"Int128", btType(clang.TypeInt128), ast.BuiltinType{Kind: ast.Int128}}, + {"UInt128", btType(clang.TypeUInt128), ast.BuiltinType{Kind: ast.Int128, Flags: ast.Unsigned}}, + {"Float", btType(clang.TypeFloat), ast.BuiltinType{Kind: ast.Float}}, + {"Half", btType(clang.TypeHalf), ast.BuiltinType{Kind: ast.Float16}}, + {"Float16", btType(clang.TypeFloat16), ast.BuiltinType{Kind: ast.Float16}}, + {"Double", btType(clang.TypeDouble), ast.BuiltinType{Kind: ast.Float, Flags: ast.Double}}, + {"LongDouble", btType(clang.TypeLongDouble), ast.BuiltinType{Kind: ast.Float, Flags: ast.Long | ast.Double}}, + {"Float128", btType(clang.TypeFloat128), ast.BuiltinType{Kind: ast.Float128}}, + {"Complex", getComplexType(0), ast.BuiltinType{Kind: ast.Complex}}, + {"Complex", getComplexType(ast.Double), ast.BuiltinType{Flags: ast.Double, Kind: ast.Complex}}, + {"Complex", getComplexType(ast.Long | ast.Double), ast.BuiltinType{Flags: ast.Long | ast.Double, Kind: ast.Complex}}, + {"Unknown", btType(clang.TypeIbm128), ast.BuiltinType{Kind: ast.Void}}, + } + + converter := &parse.Converter{} + converter.Convert() + for _, bt := range tests { + res := converter.ProcessBuiltinType(bt.typ) + if res.Kind != bt.expected.Kind { + fmt.Printf("%s Kind mismatch:got %d want %d, \n", bt.name, res.Kind, bt.expected.Kind) + } + if res.Flags != bt.expected.Flags { + fmt.Printf("%s Flags mismatch:got %d,want %d\n", bt.name, res.Flags, bt.expected.Flags) + } + fmt.Printf("%s:flags:%d kind:%d\n", bt.name, res.Flags, res.Kind) + } +} + +func TestNonBuiltinTypes() { + tests := []string{ + "char*", + "char***", + + "char[]", + "char[10]", + "char[3][4]", + + "int&", + "int&&", + + `struct Foo {}; + Foo`, + `struct Foo {}; + struct Foo`, + `struct { + int x; + }`, + + `union Foo {}; + Foo`, + `union Foo {}; + union Foo`, + `union { + int x; + }`, + + `enum Foo {}; + Foo`, + `enum Foo {}; + enum Foo`, + `enum { x = 42 }`, + + `class Foo {}; + Foo`, + `class Foo {}; + class Foo`, + `class { + int x; + }`, + + `namespace a { + namespace b { + class c { + }; + } + } + a::b::c`, + + `namespace a { + namespace b { + class c { + }; + } + } + class a::b::c`, + + `int (*p)(int, char);`, + } + + for _, t := range tests { + typ, index, unit := test.GetType(&test.GetTypeOptions{ + TypeCode: t, + IsCpp: true, + }) + converter := &parse.Converter{} + expr := converter.ProcessType(typ) + json := parse.MarshalASTExpr(expr) + str := json.Print() + typstr := typ.String() + + c.Printf(c.Str("Type: %s:\n"), typstr) + c.Printf(c.Str("%s\n"), str) + + typstr.Dispose() + cjson.FreeCStr(str) + json.Delete() + index.Dispose() + unit.Dispose() + } +} + +func btType(kind clang.TypeKind) clang.Type { + return clang.Type{Kind: kind} +} + +// get complex type from source code parsed +func getComplexType(flag ast.TypeFlag) clang.Type { + var typeStr string + if flag&(ast.Long|ast.Double) == (ast.Long | ast.Double) { + typeStr = "long double" + } else if flag&ast.Double != 0 { + typeStr = "double" + } else { + typeStr = "float" + } + + code := fmt.Sprintf("#include \n%s complex", typeStr) + + // todo(zzy):free index and unit after test + typ, _, _ := test.GetType(&test.GetTypeOptions{ + TypeCode: code, + ExpectTypeKind: clang.TypeComplex, + IsCpp: false, + }) + + return typ +} diff --git a/chore/_xtool/llcppsigfetch/parse/dump.go b/chore/_xtool/llcppsigfetch/parse/dump.go new file mode 100644 index 00000000..2606edbe --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/dump.go @@ -0,0 +1,273 @@ +package parse + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/chore/llcppg/ast" +) + +func MarshalOutputASTFiles(files []*FileEntry) *cjson.JSON { + root := cjson.Array() + for _, entry := range files { + f := cjson.Object() + path := cjson.String(c.AllocaCStr(entry.Path)) + f.SetItem(c.Str("path"), path) + f.SetItem(c.Str("doc"), MarshalASTFile(entry.Doc)) + root.AddItem(f) + } + return root +} + +func MarshalASTFiles(files []*FileEntry) *cjson.JSON { + root := cjson.Object() + for _, entry := range files { + root.SetItem(c.AllocaCStr(entry.Path), MarshalASTFile(entry.Doc)) + } + return root +} + +func MarshalDeclList(list []ast.Decl) *cjson.JSON { + root := cjson.Array() + for _, item := range list { + root.AddItem(MarshalASTDecl(item)) + } + return root +} + +func MarshalFieldList(list []*ast.Field) *cjson.JSON { + if list == nil { + return cjson.Null() + } + root := cjson.Array() + for _, item := range list { + root.AddItem(MarshalASTExpr(item)) + } + return root +} + +func MarshalIncludeList(list []*ast.Include) *cjson.JSON { + root := cjson.Array() + for _, item := range list { + include := cjson.Object() + include.SetItem(c.Str("_Type"), stringField("Include")) + include.SetItem(c.Str("Path"), stringField(item.Path)) + root.AddItem(include) + } + return root +} + +func MarshalMacroList(list []*ast.Macro) *cjson.JSON { + root := cjson.Array() + for _, item := range list { + macro := cjson.Object() + macro.SetItem(c.Str("_Type"), stringField("Macro")) + macro.SetItem(c.Str("Name"), stringField(item.Name)) + macro.SetItem(c.Str("Tokens"), MarshalTokenList(item.Tokens)) + root.AddItem(macro) + } + return root +} + +func MarshalTokenList(list []*ast.Token) *cjson.JSON { + if list == nil { + return cjson.Null() + } + root := cjson.Array() + for _, item := range list { + root.AddItem(MarshalToken(item)) + } + return root +} + +func MarshalIdentList(list []*ast.Ident) *cjson.JSON { + if list == nil { + return cjson.Null() + } + root := cjson.Array() + for _, item := range list { + root.AddItem(MarshalASTExpr(item)) + } + return root +} + +func MarshalASTFile(file *ast.File) *cjson.JSON { + root := cjson.Object() + root.SetItem(c.Str("_Type"), stringField("File")) + root.SetItem(c.Str("decls"), MarshalDeclList(file.Decls)) + root.SetItem(c.Str("includes"), MarshalIncludeList(file.Includes)) + root.SetItem(c.Str("macros"), MarshalMacroList(file.Macros)) + return root +} + +func MarshalToken(tok *ast.Token) *cjson.JSON { + root := cjson.Object() + root.SetItem(c.Str("_Type"), stringField("Token")) + root.SetItem(c.Str("Token"), numberField(uint(tok.Token))) + root.SetItem(c.Str("Lit"), stringField(tok.Lit)) + return root +} + +func MarshalASTDecl(decl ast.Decl) *cjson.JSON { + if decl == nil { + return cjson.Null() + } + root := cjson.Object() + switch d := decl.(type) { + case *ast.EnumTypeDecl: + root.SetItem(c.Str("_Type"), stringField("EnumTypeDecl")) + MarshalASTDeclBase(d.DeclBase, root) + root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) + root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type)) + case *ast.TypedefDecl: + root.SetItem(c.Str("_Type"), stringField("TypedefDecl")) + MarshalASTDeclBase(d.DeclBase, root) + root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) + root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type)) + case *ast.FuncDecl: + root.SetItem(c.Str("_Type"), stringField("FuncDecl")) + MarshalASTDeclBase(d.DeclBase, root) + root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) + root.SetItem(c.Str("MangledName"), stringField(d.MangledName)) + root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type)) + root.SetItem(c.Str("IsInline"), boolField(d.IsInline)) + root.SetItem(c.Str("IsStatic"), boolField(d.IsStatic)) + root.SetItem(c.Str("IsConst"), boolField(d.IsConst)) + root.SetItem(c.Str("IsExplicit"), boolField(d.IsExplicit)) + root.SetItem(c.Str("IsConstructor"), boolField(d.IsConstructor)) + root.SetItem(c.Str("IsDestructor"), boolField(d.IsDestructor)) + root.SetItem(c.Str("IsVirtual"), boolField(d.IsVirtual)) + root.SetItem(c.Str("IsOverride"), boolField(d.IsOverride)) + case *ast.TypeDecl: + root.SetItem(c.Str("_Type"), stringField("TypeDecl")) + MarshalASTDeclBase(d.DeclBase, root) + root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) + root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type)) + } + return root +} + +func MarshalASTDeclBase(decl ast.DeclBase, root *cjson.JSON) { + loc := cjson.Object() + loc.SetItem(c.Str("_Type"), stringField("Location")) + loc.SetItem(c.Str("File"), stringField(decl.Loc.File)) + root.SetItem(c.Str("Loc"), loc) + root.SetItem(c.Str("Doc"), MarshalASTExpr(decl.Doc)) + root.SetItem(c.Str("Parent"), MarshalASTExpr(decl.Parent)) +} + +func MarshalASTExpr(t ast.Expr) *cjson.JSON { + if t == nil { + return cjson.Null() + } + + root := cjson.Object() + + switch d := t.(type) { + case *ast.EnumType: + root.SetItem(c.Str("_Type"), stringField("EnumType")) + items := cjson.Array() + for _, e := range d.Items { + items.AddItem(MarshalASTExpr(e)) + } + root.SetItem(c.Str("Items"), items) + case *ast.EnumItem: + root.SetItem(c.Str("_Type"), stringField("EnumItem")) + root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) + root.SetItem(c.Str("Value"), MarshalASTExpr(d.Value)) + case *ast.RecordType: + root.SetItem(c.Str("_Type"), stringField("RecordType")) + root.SetItem(c.Str("Tag"), numberField(uint(d.Tag))) + root.SetItem(c.Str("Fields"), MarshalASTExpr(d.Fields)) + methods := cjson.Array() + for _, m := range d.Methods { + methods.AddItem(MarshalASTDecl(m)) + } + root.SetItem(c.Str("Methods"), methods) + case *ast.FuncType: + root.SetItem(c.Str("_Type"), stringField("FuncType")) + root.SetItem(c.Str("Params"), MarshalASTExpr(d.Params)) + root.SetItem(c.Str("Ret"), MarshalASTExpr(d.Ret)) + case *ast.FieldList: + root.SetItem(c.Str("_Type"), stringField("FieldList")) + root.SetItem(c.Str("List"), MarshalFieldList(d.List)) + case *ast.Field: + root.SetItem(c.Str("_Type"), stringField("Field")) + root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type)) + root.SetItem(c.Str("Doc"), MarshalASTExpr(d.Doc)) + root.SetItem(c.Str("Comment"), MarshalASTExpr(d.Comment)) + root.SetItem(c.Str("IsStatic"), boolField(d.IsStatic)) + root.SetItem(c.Str("Access"), numberField(uint(d.Access))) + root.SetItem(c.Str("Names"), MarshalIdentList(d.Names)) + case *ast.Variadic: + root.SetItem(c.Str("_Type"), stringField("Variadic")) + case *ast.Ident: + root.SetItem(c.Str("_Type"), stringField("Ident")) + if d == nil { + return cjson.Null() + } + root.SetItem(c.Str("Name"), stringField(d.Name)) + case *ast.TagExpr: + root.SetItem(c.Str("_Type"), stringField("TagExpr")) + root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) + root.SetItem(c.Str("Tag"), numberField(uint(d.Tag))) + case *ast.BasicLit: + root.SetItem(c.Str("_Type"), stringField("BasicLit")) + root.SetItem(c.Str("Kind"), numberField(uint(d.Kind))) + root.SetItem(c.Str("Value"), stringField(d.Value)) + case *ast.LvalueRefType: + root.SetItem(c.Str("_Type"), stringField("LvalueRefType")) + root.SetItem(c.Str("X"), MarshalASTExpr(d.X)) + case *ast.RvalueRefType: + root.SetItem(c.Str("_Type"), stringField("RvalueRefType")) + root.SetItem(c.Str("X"), MarshalASTExpr(d.X)) + case *ast.PointerType: + root.SetItem(c.Str("_Type"), stringField("PointerType")) + root.SetItem(c.Str("X"), MarshalASTExpr(d.X)) + case *ast.ArrayType: + root.SetItem(c.Str("_Type"), stringField("ArrayType")) + root.SetItem(c.Str("Elt"), MarshalASTExpr(d.Elt)) + root.SetItem(c.Str("Len"), MarshalASTExpr(d.Len)) + case *ast.BuiltinType: + root.SetItem(c.Str("_Type"), stringField("BuiltinType")) + root.SetItem(c.Str("Kind"), numberField(uint(d.Kind))) + root.SetItem(c.Str("Flags"), numberField(uint(d.Flags))) + case *ast.Comment: + root.SetItem(c.Str("_Type"), stringField("Comment")) + if d == nil { + return cjson.Null() + } + root.SetItem(c.Str("Text"), stringField(d.Text)) + case *ast.CommentGroup: + root.SetItem(c.Str("_Type"), stringField("CommentGroup")) + if d == nil { + return cjson.Null() + } + list := cjson.Array() + for _, c := range d.List { + list.AddItem(MarshalASTExpr(c)) + } + root.SetItem(c.Str("List"), list) + case *ast.ScopingExpr: + root.SetItem(c.Str("_Type"), stringField("ScopingExpr")) + root.SetItem(c.Str("X"), MarshalASTExpr(d.X)) + root.SetItem(c.Str("Parent"), MarshalASTExpr(d.Parent)) + default: + return cjson.Null() + } + return root +} + +func stringField(s string) *cjson.JSON { + return cjson.String(c.AllocaCStr(s)) +} + +func numberField(n uint) *cjson.JSON { + return cjson.Number(float64(n)) +} + +func boolField(b bool) *cjson.JSON { + if b { + return cjson.True() + } + return cjson.False() +} diff --git a/chore/_xtool/llcppsigfetch/parse/parse.go b/chore/_xtool/llcppsigfetch/parse/parse.go new file mode 100644 index 00000000..9a1c3978 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/parse.go @@ -0,0 +1,68 @@ +package parse + +import ( + "errors" + + "github.com/goplus/llgo/c/cjson" +) + +type Context struct { + Files []*FileEntry + IsCpp bool +} + +func NewContext(isCpp bool) *Context { + return &Context{ + Files: make([]*FileEntry, 0), + IsCpp: isCpp, + } +} + +func (p *Context) Output() *cjson.JSON { + return MarshalOutputASTFiles(p.Files) +} + +// 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 { + for _, entry := range p.Files { + if entry.Path == path { + return nil + } + } + parsedFiles, err := p.parseFile(path) + if err != nil { + return errors.New("failed to parse file: " + path) + } + + p.Files = append(p.Files, parsedFiles...) + return nil +} + +func (p *Context) parseFile(path string) ([]*FileEntry, error) { + converter, err := NewConverter(&Config{ + File: path, + Temp: false, + IsCpp: p.IsCpp, + }) + 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 +}