From 5e5c975a9cd343e75ee322ab16578f3e193a1d14 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 23 Aug 2024 19:01:48 +0800 Subject: [PATCH] llcppsigfetch:constructor,destructor,static,override,virtual --- chore/_xtool/llcppsigfetch/parse/cvt.go | 35 +- .../cvt_test/decl_test/class_test/class.go | 16 + .../cvt_test/decl_test/class_test/llgo.expect | 352 +++++++++++++++++- .../decl_test/comment_test/llgo.expect | 90 ++++- .../cvt_test/decl_test/func_test/llgo.expect | 30 +- .../cvt_test/decl_test/scope_test/llgo.expect | 50 ++- .../decl_test/struct_test/llgo.expect | 10 +- chore/_xtool/llcppsigfetch/parse/dump.go | 49 ++- 8 files changed, 599 insertions(+), 33 deletions(-) diff --git a/chore/_xtool/llcppsigfetch/parse/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt.go index e83f6f95..12ee6359 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -279,6 +279,7 @@ func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl { func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { name := cursor.String() defer name.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) @@ -286,6 +287,7 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { fmt.Println("failed to process function type") return nil } + params := ct.ProcessFieldList(cursor) funcType.Params = params fn := &ast.FuncDecl{ @@ -293,6 +295,37 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { Name: &ast.Ident{Name: c.GoString(name.CStr())}, Type: funcType, } + + // other info of function&method + if cursor.Kind == clang.CursorDestructor { + fn.IsDestructor = true + } + + if cursor.Kind == clang.CursorConstructor { + fn.IsConstructor = true + if cursor.IsExplicit() != 0 { + fn.IsExplicit = true + } + } + + if cursor.IsStatic() != 0 { + fn.IsStatic = true + } + + // virtual & pure virtual + if cursor.IsVirtual() != 0 || cursor.IsPureVirtual() != 0 { + fn.IsVirtual = true + } + + // todo(zzy):inline & const + + var numOverridden c.Uint + var overridden *clang.Cursor + cursor.OverriddenCursors(&overridden, &numOverridden) + if numOverridden > 0 { + fn.IsOverride = true + } + return fn } @@ -425,7 +458,7 @@ type visitMethodsContext struct { func visitMethods(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { ctx := (*visitMethodsContext)(clientData) - if cursor.Kind == clang.CursorCXXMethod { + if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor { method := ctx.converter.ProcessFuncDecl(cursor) if method != nil { *ctx.methods = append(*ctx.methods, method) 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 index 747688f9..d3765433 100644 --- 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 @@ -17,6 +17,22 @@ func TestClassDecl() { int b; float foo(int a,double b); };`, + `class A { + A(); + explicit A(); + ~A(); + };`, + `class Base { + Base(); + virtual ~Base(); + virtual void foo(); + }; + class Derived : public Base { + Derived(); + ~Derived() override; + void foo() override; + }; + `, } 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 index 9b66edd8..2b893eff 100644 --- 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 @@ -150,7 +150,357 @@ TestClassDecl Case 2: "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": { + "decls": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": null, + "Name": { + "Name": "A" + }, + "Type": { + "Tag": 3, + "Fields": { + "List": [] + }, + "Methods": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "A" + }, + "Name": { + "Name": "A" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "A" + }, + "Name": { + "Name": "A" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": true, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "A" + }, + "Name": { + "Name": "~A" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": true, + "IsVirtual": false, + "IsOverride": false + }] + } + }], + "includes": [], + "macros": [] + } +} + +TestClassDecl Case 4: +{ + "temp.h": { + "decls": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": null, + "Name": { + "Name": "Base" + }, + "Type": { + "Tag": 3, + "Fields": { + "List": [] + }, + "Methods": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "Base" + }, + "Name": { + "Name": "Base" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "Base" + }, + "Name": { + "Name": "~Base" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": true, + "IsVirtual": true, + "IsOverride": false + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "Base" + }, + "Name": { + "Name": "foo" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": true, + "IsOverride": false + }] + } + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": null, + "Name": { + "Name": "Derived" + }, + "Type": { + "Tag": 3, + "Fields": { + "List": [] + }, + "Methods": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "Derived" + }, + "Name": { + "Name": "Derived" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": true, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "Derived" + }, + "Name": { + "Name": "~Derived" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": true, + "IsVirtual": true, + "IsOverride": true + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "Derived" + }, + "Name": { + "Name": "foo" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": true, + "IsOverride": true }] } }], 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 index 57bc9f6a..1ba87aff 100644 --- 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 @@ -21,7 +21,15 @@ TestDoc Case 1: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -50,7 +58,15 @@ TestDoc Case 2: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -81,7 +97,15 @@ TestDoc Case 3: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -112,7 +136,15 @@ TestDoc Case 4: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -143,7 +175,15 @@ TestDoc Case 5: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -176,7 +216,15 @@ TestDoc Case 6: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -209,7 +257,15 @@ TestDoc Case 7: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -242,7 +298,15 @@ TestDoc Case 8: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -279,7 +343,15 @@ TestDoc Case 9: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] 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 index 0e363a10..5b3ceb20 100644 --- 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 @@ -21,7 +21,15 @@ TestFuncDecl Case 1: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -64,7 +72,15 @@ TestFuncDecl Case 2: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -123,7 +139,15 @@ TestFuncDecl Case 3: "Flags": 0 } } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] 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 index 28adaff8..91e06267 100644 --- 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 @@ -21,7 +21,15 @@ TestScope Case 1: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -52,7 +60,15 @@ TestScope Case 2: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -88,7 +104,15 @@ TestScope Case 3: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }], "includes": [], "macros": [] @@ -135,7 +159,15 @@ TestScope Case 4: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }] } }], @@ -191,7 +223,15 @@ TestScope Case 5: "Kind": 0, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }] } }], 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 index 16b90baf..d6020d24 100644 --- 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 @@ -242,7 +242,15 @@ TestStructDecl Case 4: "Kind": 8, "Flags": 0 } - } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false }] } }], diff --git a/chore/_xtool/llcppsigfetch/parse/dump.go b/chore/_xtool/llcppsigfetch/parse/dump.go index 70dddf8e..17b37f1e 100644 --- a/chore/_xtool/llcppsigfetch/parse/dump.go +++ b/chore/_xtool/llcppsigfetch/parse/dump.go @@ -29,7 +29,7 @@ func MarshalASTFile(file *ast.File) *cjson.JSON { includes := cjson.Array() for _, i := range file.Includes { include := cjson.Object() - include.SetItem(c.Str("Path"), cjson.String(c.AllocaCStr(i.Path))) + include.SetItem(c.Str("Path"), stringField(i.Path)) includes.AddItem(include) } root.SetItem(c.Str("includes"), includes) @@ -40,7 +40,7 @@ func MarshalASTFile(file *ast.File) *cjson.JSON { macros := cjson.Array() for _, m := range file.Macros { marco := cjson.Object() - marco.SetItem(c.Str("Name"), cjson.String(c.AllocaCStr(m.Name))) + marco.SetItem(c.Str("Name"), stringField(m.Name)) tokens := cjson.Array() for _, tok := range m.Tokens { tokens.AddItem(Token(tok)) @@ -54,8 +54,8 @@ func MarshalASTFile(file *ast.File) *cjson.JSON { } func Token(tok *ast.Token) *cjson.JSON { root := cjson.Object() - root.SetItem(c.Str("Token"), cjson.Number(float64(tok.Token))) - root.SetItem(c.Str("Lit"), cjson.String(c.AllocaCStr(tok.Lit))) + root.SetItem(c.Str("Token"), numberField(uint(tok.Token))) + root.SetItem(c.Str("Lit"), stringField(tok.Lit)) return root } @@ -77,6 +77,14 @@ func MarshalASTDecl(decl ast.Decl) *cjson.JSON { MarshalASTDeclBase(d.DeclBase, root) root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) 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: MarshalASTDeclBase(d.DeclBase, root) root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) @@ -87,7 +95,7 @@ func MarshalASTDecl(decl ast.Decl) *cjson.JSON { func MarshalASTDeclBase(decl ast.DeclBase, root *cjson.JSON) { loc := cjson.Object() - loc.SetItem(c.Str("File"), cjson.String(c.AllocaCStr(decl.Loc.File))) + loc.SetItem(c.Str("File"), stringField(decl.Loc.File)) root.SetItem(c.Str("Loc"), loc) root.SetItem(c.Str("Doc"), MarshalASTExpr(decl.Doc)) @@ -112,7 +120,7 @@ func MarshalASTExpr(t ast.Expr) *cjson.JSON { root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) root.SetItem(c.Str("Value"), MarshalASTExpr(d.Value)) case *ast.RecordType: - root.SetItem(c.Str("Tag"), cjson.Number(float64(d.Tag))) + 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 { @@ -144,13 +152,13 @@ func MarshalASTExpr(t ast.Expr) *cjson.JSON { if d == nil { return cjson.Null() } - root.SetItem(c.Str("Name"), cjson.String(c.AllocaCStr(d.Name))) + root.SetItem(c.Str("Name"), stringField(d.Name)) case *ast.TagExpr: root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name)) - root.SetItem(c.Str("Tag"), cjson.Number(float64(d.Tag))) + root.SetItem(c.Str("Tag"), numberField(uint(d.Tag))) case *ast.BasicLit: - root.SetItem(c.Str("Kind"), cjson.Number(float64(d.Kind))) - root.SetItem(c.Str("Value"), cjson.String(c.AllocaCStr(d.Value))) + root.SetItem(c.Str("Kind"), numberField(uint(d.Kind))) + root.SetItem(c.Str("Value"), stringField(d.Value)) case *ast.LvalueRefType: root.SetItem(c.Str("X"), MarshalASTExpr(d.X)) case *ast.RvalueRefType: @@ -161,13 +169,13 @@ func MarshalASTExpr(t ast.Expr) *cjson.JSON { root.SetItem(c.Str("Elt"), MarshalASTExpr(d.Elt)) root.SetItem(c.Str("Len"), MarshalASTExpr(d.Len)) case *ast.BuiltinType: - root.SetItem(c.Str("Kind"), cjson.Number(float64(d.Kind))) - root.SetItem(c.Str("Flags"), cjson.Number(float64(d.Flags))) + root.SetItem(c.Str("Kind"), numberField(uint(d.Kind))) + root.SetItem(c.Str("Flags"), numberField(uint(d.Flags))) case *ast.Comment: if d == nil { return cjson.Null() } - root.SetItem(c.Str("Text"), cjson.String(c.AllocaCStr(d.Text))) + root.SetItem(c.Str("Text"), stringField(d.Text)) case *ast.CommentGroup: if d == nil { return cjson.Null() @@ -185,3 +193,18 @@ func MarshalASTExpr(t ast.Expr) *cjson.JSON { } 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() +}