diff --git a/_xtool/pydump/pydump.go b/_xtool/pydump/pydump.go index 7b8be43..01c5113 100644 --- a/_xtool/pydump/pydump.go +++ b/_xtool/pydump/pydump.go @@ -20,6 +20,24 @@ var pyFuncTypes = map[string]bool{ "_ArrayFunctionDispatcher": true, } +var pyBasicDataTypes = map[string]struct{}{ + "int": {}, + "float": {}, + "complex": {}, + "bool": {}, + "str": {}, + "list": {}, + "tuple": {}, + "range": {}, + "set": {}, + "frozenset": {}, + "dict": {}, + "bytes": {}, + "bytearray": {}, + "memoryview": {}, + "NoneType": {}, +} + func extractSignatureFromDoc(doc, funcName string) string { lines := strings.SplitN(doc, "\n\n", 2) if len(lines) == 0 { @@ -98,8 +116,14 @@ func pydump(moduleName string) (*symbol.Module, error) { if pyFuncTypes[sym.Type] { sym.Sig = getSignature(val, sym) modInstance.Functions = append(modInstance.Functions, sym) + continue + } + // variables + if _, ok := pyBasicDataTypes[sym.Type]; ok { + modInstance.Variables = append(modInstance.Variables, sym) + continue } - // TODO: variables, classes, etc. + // TODO: classes, etc. } return modInstance, nil } diff --git a/symbol/symbol.go b/symbol/symbol.go index e0e5d2b..a6caebc 100644 --- a/symbol/symbol.go +++ b/symbol/symbol.go @@ -10,5 +10,6 @@ type Symbol struct { type Module struct { Name string `json:"name"` // python module name Functions []*Symbol `json:"functions"` // package functions - // TODO: variables, classes, etc. + Variables []*Symbol `json:"variables"` // package variables + // TODO: classes, etc. } diff --git a/tool/pygen/genvar.go b/tool/pygen/genvar.go new file mode 100644 index 0000000..5bda54e --- /dev/null +++ b/tool/pygen/genvar.go @@ -0,0 +1,38 @@ +package pygen + +import ( + "go/ast" + "go/token" + "github.com/goplus/gogen" + "github.com/goplus/llpyg/symbol" +) + +func (ctx *context) genVars(pkg *gogen.Package, syms []*symbol.Symbol) { + names := make(map[string]struct{}) + for _, sym := range syms { + if sym.Name == "" || sym.Name[0] == '_' { + continue + } + name := ctx.genName(sym.Name, -1) + _, exist := names[name] + // avoid name conflict + for exist { + name = name + "_" + _, exist = names[name] + } + names[name] = struct{}{} + ctx.genVar(pkg, sym, name) + } +} + +// current can not get variable comment, see https://github.com/goplus/llpyg/issues/43 +func (ctx *context) genVar(pkg *gogen.Package, sym *symbol.Symbol, goName string) { + def := pkg.NewVarDefs(pkg.Types.Scope()) + // linkname + docList := make([]*ast.Comment, 0, 2) + goLinkname := "//go:linkname " + goName + " py." + sym.Name + docList = append(docList, &ast.Comment{Text: goLinkname}) + def.SetComments(&ast.CommentGroup{List: docList}) + + def.New(token.NoPos, ctx.objPtr, goName) +} diff --git a/tool/pygen/pygen.go b/tool/pygen/pygen.go index 905398d..a63c61b 100644 --- a/tool/pygen/pygen.go +++ b/tool/pygen/pygen.go @@ -103,7 +103,9 @@ func (ctx *context) genMod(pkg *gogen.Package, mod *symbol.Module) { funcMap[sym.Name] = true ctx.genFunc(pkg, sym) } - // TODO: class, variable, etc. + // variables + ctx.genVars(pkg, mod.Variables) + // TODO: class, etc. } diff --git a/tool/pygen/pygen_test.go b/tool/pygen/pygen_test.go index 2a4d8ec..f38b2b2 100644 --- a/tool/pygen/pygen_test.go +++ b/tool/pygen/pygen_test.go @@ -41,6 +41,21 @@ func TestGenFunc(t *testing.T) { t.Logf("test gen func pass") } +func TestGenVar(t *testing.T) { + prepareEnv("./testdata/var") + mod, err := pydump("demo") + if err != nil { + t.Fatal(err) + } + ctx := createGoPackage(mod) + ctx.genVars(ctx.pkg, mod.Variables) + err = compareWithExpected(t, ctx, "testdata/var/expect.go") + if err != nil { + t.Fatalf("test gen var failed: %v", err) + } + t.Logf("test gen var pass") +} + func compareWithExpected(t *testing.T, ctx *context, expectedPath string) error { outFilePath := "./temp/actual_git.go" dir := filepath.Dir(outFilePath) diff --git a/tool/pygen/testdata/var/demo.py b/tool/pygen/testdata/var/demo.py new file mode 100644 index 0000000..9a050b2 --- /dev/null +++ b/tool/pygen/testdata/var/demo.py @@ -0,0 +1,31 @@ +# Numeric types +int_var = 42 +Int_var = 25 +float_var = 3.14 +complex_var = 3 + 4j + +# Boolean type +bool_var = True + +# String type +str_var = "Hello, World!" + +# Sequence types +list_var = [1, 2, 3] +tuple_var = (1, 2, 3) +range_var = range(10) + +# Mapping type +dict_var = {1: "one", 2: "two", 3: "three"} + +# Set types +set_var = {1, 2, 3} +frozenset_var = frozenset({1, 2, 3}) + +# Binary types +bytes_var = b"hello" +bytearray_var = bytearray(b"hello") +mv_var = memoryview(b"hello") + +# Special type +none_var = None diff --git a/tool/pygen/testdata/var/expect.go b/tool/pygen/testdata/var/expect.go new file mode 100644 index 0000000..2661a56 --- /dev/null +++ b/tool/pygen/testdata/var/expect.go @@ -0,0 +1,56 @@ +package demo + +import ( + "github.com/goplus/lib/py" + _ "unsafe" +) + +const LLGoPackage = "py.demo" + +//go:linkname IntVar py.int_var +var IntVar *py.Object + +//go:linkname IntVar_ py.Int_var +var IntVar_ *py.Object + +//go:linkname FloatVar py.float_var +var FloatVar *py.Object + +//go:linkname ComplexVar py.complex_var +var ComplexVar *py.Object + +//go:linkname BoolVar py.bool_var +var BoolVar *py.Object + +//go:linkname StrVar py.str_var +var StrVar *py.Object + +//go:linkname ListVar py.list_var +var ListVar *py.Object + +//go:linkname TupleVar py.tuple_var +var TupleVar *py.Object + +//go:linkname RangeVar py.range_var +var RangeVar *py.Object + +//go:linkname DictVar py.dict_var +var DictVar *py.Object + +//go:linkname SetVar py.set_var +var SetVar *py.Object + +//go:linkname FrozensetVar py.frozenset_var +var FrozensetVar *py.Object + +//go:linkname BytesVar py.bytes_var +var BytesVar *py.Object + +//go:linkname BytearrayVar py.bytearray_var +var BytearrayVar *py.Object + +//go:linkname MvVar py.mv_var +var MvVar *py.Object + +//go:linkname NoneVar py.none_var +var NoneVar *py.Object