From 2c8a9d1160e7e3af4550afc3fd361605e6a31fe2 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 15 Aug 2024 11:26:34 +0800 Subject: [PATCH] llcppsigfetch:Scope Context --- chore/_xtool/llcppsigfetch/parse/cvt.go | 117 +++++++++------ .../parse/cvt_test/decl_test/decl.go | 34 ++++- .../parse/cvt_test/decl_test/llgo.expect | 141 ++++++++++++++++-- chore/_xtool/llcppsigfetch/parse/dump.go | 3 + 4 files changed, 236 insertions(+), 59 deletions(-) diff --git a/chore/_xtool/llcppsigfetch/parse/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt.go index 00cbbac5..dd9b282e 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -12,12 +12,12 @@ import ( ) type Converter struct { - files map[string]*ast.File - curLoc ast.Location - curFile *ast.File - index *clang.Index - unit *clang.TranslationUnit - // todo(zzy):current namespace expr + files map[string]*ast.File + curLoc ast.Location + curFile *ast.File + index *clang.Index + unit *clang.TranslationUnit + scopeStack []ast.Expr //namespace & class } func NewConverter(file string, temp bool) (*Converter, error) { @@ -68,41 +68,31 @@ func (ct *Converter) Dispose() { ct.unit.Dispose() } -// visit top decls (struct,class,function,enum & marco,include) -func visit(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { - ct := (*Converter)(clientData) - ct.UpdateCurFile(cursor) +func (ct *Converter) PushScope(cursor clang.Cursor) { + name := cursor.String() + defer name.Dispose() + ident := &ast.Ident{Name: c.GoString(name.CStr())} - switch cursor.Kind { - case clang.CursorInclusionDirective: - // todo(zzy) - return clang.ChildVisit_Continue - case clang.CursorMacroDefinition: - // todo(zzy) - return clang.ChildVisit_Continue - case clang.CursorEnumDecl: - // todo(zzy) - return clang.ChildVisit_Continue - case clang.CursorClassDecl: - ct.ProcessClass(cursor) - return clang.ChildVisit_Continue - case clang.CursorStructDecl: - // todo(zzy) - return clang.ChildVisit_Continue - case clang.CursorFunctionDecl: - ct.ProcessFunc(cursor) - return clang.ChildVisit_Continue - default: - // non-top-level decl, continue recursion - return clang.ChildVisit_Recurse + if len(ct.scopeStack) == 0 { + ct.scopeStack = append(ct.scopeStack, ident) + } else { + parent := ct.scopeStack[len(ct.scopeStack)-1] + newContext := &ast.ScopingExpr{Parent: parent, X: ident} + ct.scopeStack = append(ct.scopeStack, newContext) } } -func (ct *Converter) Convert() (map[string]*ast.File, error) { - cursor := ct.unit.Cursor() - // visit top decls (struct,class,function & marco,include) - clang.VisitChildren(cursor, visit, c.Pointer(ct)) - return ct.files, nil +func (ct *Converter) PopScope() { + if len(ct.scopeStack) > 0 { + ct.scopeStack = ct.scopeStack[:len(ct.scopeStack)-1] + } +} + +func (ct *Converter) GetCurScope() ast.Expr { + if len(ct.scopeStack) == 0 { + return nil + } + return ct.scopeStack[len(ct.scopeStack)-1] } func (ct *Converter) UpdateCurFile(cursor clang.Cursor) { @@ -118,6 +108,8 @@ func (ct *Converter) UpdateCurFile(cursor clang.Cursor) { } filePath := c.GoString(filename.CStr()) + ct.curLoc = ast.Location{File: filePath} + if ct.curFile == nil || ct.curFile.Path != filePath { if f, ok := ct.files[filePath]; ok { ct.curFile = f @@ -128,11 +120,53 @@ func (ct *Converter) UpdateCurFile(cursor clang.Cursor) { Includes: make([]*ast.Include, 0), Macros: make([]*ast.Macro, 0), } + ct.files[filePath] = ct.curFile } - ct.files[filePath] = ct.curFile } } +func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase { + return ast.DeclBase{ + Loc: &ct.curLoc, + Parent: ct.GetCurScope(), + } +} + +// visit top decls (struct,class,function,enum & marco,include) +func visit(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { + ct := (*Converter)(clientData) + ct.UpdateCurFile(cursor) + + switch cursor.Kind { + case clang.CursorInclusionDirective: + // todo(zzy) + case clang.CursorMacroDefinition: + // todo(zzy) + case clang.CursorEnumDecl: + // todo(zzy) + case clang.CursorClassDecl: + ct.PushScope(cursor) + ct.ProcessClass(cursor) + ct.PopScope() + case clang.CursorStructDecl: + // todo(zzy) + case clang.CursorFunctionDecl: + ct.ProcessFunc(cursor) + case clang.CursorNamespace: + ct.PushScope(cursor) + clang.VisitChildren(cursor, visit, c.Pointer(ct)) + ct.PopScope() + } + return clang.ChildVisit_Continue +} + +func (ct *Converter) Convert() (map[string]*ast.File, error) { + cursor := ct.unit.Cursor() + // visit top decls (struct,class,function & marco,include) + clang.VisitChildren(cursor, visit, c.Pointer(ct)) + return ct.files, nil +} + func (ct *Converter) ProcessType(t clang.Type) ast.Expr { var expr ast.Expr if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin { @@ -179,12 +213,11 @@ func (ct *Converter) ProcessFunc(cursor clang.Cursor) { params := ct.ProcessFuncParams(cursor) funcType.Params = params fn := &ast.FuncDecl{ - Name: &ast.Ident{Name: c.GoString(name.CStr())}, - Type: funcType, - // todo(zzy):DeclBase use the converter's current namespace expr + DeclBase: ct.CreateDeclBase(cursor), + Name: &ast.Ident{Name: c.GoString(name.CStr())}, + Type: funcType, } ct.curFile.Decls = append(ct.curFile.Decls, fn) - // ct.declMap[cursor] = fn } type visitParamContext struct { diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/decl.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/decl.go index d76bd84f..2391b8dc 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/decl.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/decl.go @@ -7,6 +7,7 @@ import ( func main() { TestFuncDecl() + TestScope() } func TestFuncDecl() { @@ -35,7 +36,38 @@ func TestFuncDecl() { } json := converter.GetFilesJSON() - c.Printf(c.Str("Test Case %d:\n%s\n\n"), c.Int(i+1), json.Print()) + c.Printf(c.Str("TestFuncDecl Case %d:\n%s\n\n"), c.Int(i+1), json.Print()) + + converter.Dispose() + } +} + +func TestScope() { + testCases := []string{ + `void foo();`, + `namespace a { + void foo(); + }`, + `namespace a { + namespace b { + void foo(); + } + }`, + } + + for i, content := range testCases { + converter, err := parse.NewConverter(content, true) + if err != nil { + panic(err) + } + + _, err = converter.Convert() + if err != nil { + panic(err) + } + + json := converter.GetFilesJSON() + c.Printf(c.Str("TestScope Case %d:\n%s\n\n"), c.Int(i+1), json.Print()) converter.Dispose() } diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/llgo.expect index 266d5992..206886c3 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/llgo.expect +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/llgo.expect @@ -1,10 +1,12 @@ #stdout -Test Case 1: +TestFuncDecl Case 1: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -25,12 +27,14 @@ Test Case 1: } } -Test Case 2: +TestFuncDecl Case 2: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -61,12 +65,14 @@ Test Case 2: } } -Test Case 3: +TestFuncDecl Case 3: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -107,12 +113,14 @@ Test Case 3: } } -Test Case 4: +TestFuncDecl Case 4: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -155,12 +163,14 @@ Test Case 4: } } -Test Case 5: +TestFuncDecl Case 5: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -205,12 +215,14 @@ Test Case 5: } } -Test Case 6: +TestFuncDecl Case 6: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -259,12 +271,14 @@ Test Case 6: } } -Test Case 7: +TestFuncDecl Case 7: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -310,12 +324,14 @@ Test Case 7: } } -Test Case 8: +TestFuncDecl Case 8: { "temp.h": { "path": "temp.h", "decls": [{ - "Loc": null, + "Loc": { + "File": "temp.h" + }, "Doc": null, "Parent": null, "Name": { @@ -360,6 +376,99 @@ Test Case 8: } } +TestScope Case 1: +{ + "temp.h": { + "path": "temp.h", + "decls": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "Name": "foo" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + } + }], + "includes": [], + "macros": [] + } +} + +TestScope Case 2: +{ + "temp.h": { + "path": "temp.h", + "decls": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "Name": "a" + }, + "Name": { + "Name": "foo" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + } + }], + "includes": [], + "macros": [] + } +} + +TestScope Case 3: +{ + "temp.h": { + "path": "temp.h", + "decls": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": null, + "Parent": { + "X": { + "Name": "b" + }, + "Parent": { + "Name": "a" + } + }, + "Name": { + "Name": "foo" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + } + }], + "includes": [], + "macros": [] + } +} + #stderr diff --git a/chore/_xtool/llcppsigfetch/parse/dump.go b/chore/_xtool/llcppsigfetch/parse/dump.go index 21616892..c5eeb004 100644 --- a/chore/_xtool/llcppsigfetch/parse/dump.go +++ b/chore/_xtool/llcppsigfetch/parse/dump.go @@ -109,6 +109,9 @@ func (ct *Converter) TypeJSON(t ast.Expr) *cjson.JSON { list.AddItem(ct.TypeJSON(c)) } root.SetItem(c.Str("List"), list) + case *ast.ScopingExpr: + root.SetItem(c.Str("X"), ct.TypeJSON(d.X)) + root.SetItem(c.Str("Parent"), ct.TypeJSON(d.Parent)) default: return cjson.Null() }