mirror of https://github.com/go-python/gopy.git
257 lines
6.6 KiB
Go
257 lines
6.6 KiB
Go
// Copyright 2019 The go-python Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package bind
|
|
|
|
import (
|
|
"fmt"
|
|
"go/types"
|
|
)
|
|
|
|
func (g *pybindGen) genStruct(s Struct) {
|
|
pkgname := s.Package().Name()
|
|
g.pywrap.Printf(`
|
|
# Python type for struct %[1]s.%[2]s
|
|
class %[2]s(GoClass):
|
|
""%[3]q""
|
|
`,
|
|
pkgname,
|
|
s.GoName(),
|
|
s.Doc(),
|
|
)
|
|
g.pywrap.Indent()
|
|
g.genStructInit(s)
|
|
g.genStructMembers(s)
|
|
g.genStructMethods(s)
|
|
g.pywrap.Outdent()
|
|
}
|
|
|
|
func (g *pybindGen) genStructInit(s Struct) {
|
|
// pkg := s.Package()
|
|
pkgname := s.Package().Name()
|
|
qNm := pkgname + "." + s.GoName()
|
|
|
|
numFields := s.Struct().NumFields()
|
|
numPublic := numFields
|
|
for i := 0; i < s.Struct().NumFields(); i++ {
|
|
f := s.Struct().Field(i)
|
|
if !f.Exported() {
|
|
numPublic--
|
|
continue
|
|
}
|
|
}
|
|
|
|
g.pywrap.Printf("def __init__(self, *args, **kwargs):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf(`"""
|
|
handle=A Go-side object is always initialized with an explicit handle=arg
|
|
otherwise parameters can be unnamed in order of field names or named fields
|
|
in which case a new Go object is constructed first
|
|
"""
|
|
`)
|
|
g.pywrap.Printf("if len(kwargs) == 1 and 'handle' in kwargs:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.handle = kwargs['handle']\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("else:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.handle = _%s_CTor()\n", qNm)
|
|
|
|
for i := 0; i < numFields; i++ {
|
|
field := s.Struct().Field(i)
|
|
if !field.Exported() {
|
|
continue
|
|
}
|
|
g.pywrap.Printf("if %[1]d < len(args):\n", i)
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.%s = args[%d]\n", field.Name(), i)
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("if %[1]q in kwargs:\n", field.Name())
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.%[1]s = kwargs[%[1]q]\n", field.Name())
|
|
g.pywrap.Outdent()
|
|
}
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
|
|
for _, m := range s.meths {
|
|
if m.GoName() == "String" {
|
|
g.pywrap.Printf("def __str__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("return self.String()\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
}
|
|
}
|
|
|
|
// go ctor
|
|
ctNm := s.GoName() + "_CTor"
|
|
g.gofile.Printf("\n// --- wrapping struct: %v ---\n", qNm)
|
|
g.gofile.Printf("//export %s\n", ctNm)
|
|
g.gofile.Printf("func %s() CGoHandle {\n", ctNm)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("return handleFmPtr_%[1]s(&%[2]s{})\n", s.GoName(), qNm)
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s', retval('char*'), [])\n", ctNm)
|
|
|
|
}
|
|
|
|
func (g *pybindGen) genStructMembers(s Struct) {
|
|
//pkgname := s.Package().Name()
|
|
typ := s.Struct()
|
|
for i := 0; i < typ.NumFields(); i++ {
|
|
f := typ.Field(i)
|
|
if !f.Exported() {
|
|
continue
|
|
}
|
|
g.genStructMemberGetter(s, i, f)
|
|
g.genStructMemberSetter(s, i, f)
|
|
}
|
|
}
|
|
|
|
func (g *pybindGen) genStructMemberGetter(s Struct, i int, f types.Object) {
|
|
pkgname := s.Package().Name()
|
|
ft := f.Type()
|
|
ret := g.pkg.syms.symtype(ft)
|
|
|
|
cgoFn := fmt.Sprintf("%s_%s_Get", s.GoName(), f.Name())
|
|
|
|
g.pywrap.Printf("@property\n")
|
|
g.pywrap.Printf("def %[1]s(self):\n", f.Name())
|
|
g.pywrap.Indent()
|
|
if ret.hasHandle() {
|
|
g.pywrap.Printf("return %s(handle=_%s.%s(self.handle))\n", ret.nonPointerName(), pkgname, cgoFn)
|
|
} else {
|
|
g.pywrap.Printf("return _%s.%s(self.handle)\n", pkgname, cgoFn)
|
|
}
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
|
|
g.gofile.Printf("//export %s\n", cgoFn)
|
|
g.gofile.Printf("func %s(handle CGoHandle) %s {\n", cgoFn, ret.cgoname)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("op := ptrFmHandle_%s(handle)\nreturn ", s.GoName())
|
|
if ret.go2py != "" {
|
|
if ret.hasHandle() && !ret.isPtrOrIface() {
|
|
g.gofile.Printf("%s(&op.%s)", ret.go2py, f.Name())
|
|
} else {
|
|
g.gofile.Printf("%s(op.%s)", ret.go2py, f.Name())
|
|
}
|
|
} else {
|
|
g.gofile.Printf("op.%s", f.Name())
|
|
}
|
|
g.gofile.Printf("\n")
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s', retval('%s'), [param('char*', 'handle')])\n", cgoFn, ret.cpyname)
|
|
}
|
|
|
|
func (g *pybindGen) genStructMemberSetter(s Struct, i int, f types.Object) {
|
|
pkgname := s.Package().Name()
|
|
ft := f.Type()
|
|
ret := g.pkg.syms.symtype(ft)
|
|
|
|
cgoFn := fmt.Sprintf("%s_%s_Set", s.GoName(), f.Name())
|
|
|
|
g.pywrap.Printf("@%s.setter\n", f.Name())
|
|
g.pywrap.Printf("def %[1]s(self, value):\n", f.Name())
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("if isinstance(value, GoClass):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("_%s.%s(self.handle, value.handle)\n", pkgname, cgoFn)
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("else:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("_%s.%s(self.handle, value)\n", pkgname, cgoFn)
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
|
|
g.gofile.Printf("//export %s\n", cgoFn)
|
|
g.gofile.Printf("func %s(handle CGoHandle, val %s) {\n", cgoFn, ret.cgoname)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("op := ptrFmHandle_%s(handle)\n", s.GoName())
|
|
if ret.go2py != "" {
|
|
if ret.hasHandle() && !ret.isPtrOrIface() {
|
|
g.gofile.Printf("op.%s = *%s(val)", f.Name(), ret.py2go)
|
|
} else {
|
|
g.gofile.Printf("op.%s = %s(val)", f.Name(), ret.py2go)
|
|
}
|
|
} else {
|
|
g.gofile.Printf("op.%s = val", f.Name())
|
|
}
|
|
g.gofile.Printf("\n")
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s', None, [param('char*', 'handle'), param('%s', 'val')])\n", cgoFn, ret.cpyname)
|
|
}
|
|
|
|
func (g *pybindGen) genStructMethods(s Struct) {
|
|
for _, m := range s.meths {
|
|
g.genMethod(s, m)
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Interface
|
|
|
|
func (g *pybindGen) genInterface(ifc Interface) {
|
|
pkgname := ifc.Package().Name()
|
|
g.pywrap.Printf(`
|
|
# Python type for interface %[1]s.%[2]s
|
|
class %[2]s(GoClass):
|
|
""%[3]q""
|
|
`,
|
|
pkgname,
|
|
ifc.GoName(),
|
|
ifc.Doc(),
|
|
)
|
|
g.pywrap.Indent()
|
|
g.genIfaceInit(ifc)
|
|
g.genIfaceMethods(ifc)
|
|
g.pywrap.Outdent()
|
|
}
|
|
|
|
func (g *pybindGen) genIfaceInit(ifc Interface) {
|
|
// pkgname := ifc.Package().Name()
|
|
|
|
g.pywrap.Printf("def __init__(self, *args, **kwargs):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf(`"""
|
|
handle=A Go-side object is always initialized with an explicit handle=arg
|
|
"""
|
|
`)
|
|
g.pywrap.Printf("if len(kwargs) == 1 and 'handle' in kwargs:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.handle = kwargs['handle']\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("else:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.handle = args[0]\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
|
|
for _, m := range ifc.meths {
|
|
if m.GoName() == "String" {
|
|
g.pywrap.Printf("def __str__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("return self.String()\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *pybindGen) genIfaceMethods(ifc Interface) {
|
|
for _, m := range ifc.meths {
|
|
g.genIfcMethod(ifc, m)
|
|
}
|
|
}
|