gopy/bind/gen_type.go

220 lines
6.1 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
// extTypes = these are types external to any targeted packages
// pyWrapOnly = only generate python wrapper code, not go code
func (g *pyGen) genType(sym *symbol, extTypes, pyWrapOnly bool) {
if !sym.isType() {
return
}
if sym.isBasic() && !sym.isNamed() {
return
}
if sym.isNamedBasic() {
// TODO: could have methods!
return
}
// TODO: not handling yet:
if sym.isSignature() {
return
}
if !pyWrapOnly {
switch {
case sym.isPointer() || sym.isInterface():
g.genTypeHandlePtr(sym)
case sym.isSlice() || sym.isMap() || sym.isArray():
g.genTypeHandleImplPtr(sym)
default:
g.genTypeHandle(sym)
}
}
if extTypes {
if sym.isSlice() || sym.isArray() {
g.genSlice(sym, extTypes, pyWrapOnly, nil)
} else if sym.isMap() {
g.genMap(sym, extTypes, pyWrapOnly, nil)
} else if sym.isInterface() || sym.isStruct() {
if pyWrapOnly {
g.genExtClass(sym)
}
}
} else {
if g.pkg == goPackage || !sym.isNamed() { // only named types are generated separately
if sym.isSlice() {
g.genSlice(sym, extTypes, pyWrapOnly, nil)
} else if sym.isMap() {
g.genMap(sym, extTypes, pyWrapOnly, nil)
}
}
if sym.isArray() {
g.genSlice(sym, extTypes, pyWrapOnly, nil)
}
}
}
func (g *pyGen) genTypeHandlePtr(sym *symbol) {
if sym.goname == "interface{}" {
return
}
gonm := sym.goname
g.gofile.Printf("\n// Converters for pointer handles for type: %s\n", gonm)
g.gofile.Printf("func %s(h CGoHandle) %s {\n", sym.py2go, gonm)
g.gofile.Indent()
g.gofile.Printf("p := gopyh.VarFromHandle((gopyh.CGoHandle)(h), %[1]q)\n", gonm)
g.gofile.Printf("if p == nil {\n")
g.gofile.Indent()
g.gofile.Printf("return nil\n")
g.gofile.Outdent()
g.gofile.Printf("}\n")
if sym.isStruct() {
g.gofile.Printf("return gopyh.Embed(p, reflect.TypeOf(%s{})).(%s)\n", nonPtrName(gonm), gonm)
} else {
g.gofile.Printf("return p.(%s)\n", gonm)
}
g.gofile.Outdent()
g.gofile.Printf("}\n")
g.gofile.Printf("func %s(p interface{})%s CGoHandle {\n", sym.go2py, sym.go2pyParenEx)
g.gofile.Indent()
g.gofile.Printf("return CGoHandle(gopyh.Register(\"%s\", p))\n", gonm)
g.gofile.Outdent()
g.gofile.Printf("}\n")
}
// implicit pointer types: slice, map, array
func (g *pyGen) genTypeHandleImplPtr(sym *symbol) {
gonm := sym.goname
ptrnm := gonm
nptrnm := gonm
if ptrnm[0] != '*' {
ptrnm = "*" + ptrnm
} else {
nptrnm = gonm[1:]
}
g.gofile.Printf("\n// Converters for implicit pointer handles for type: %s\n", gonm)
g.gofile.Printf("func ptrFromHandle_%s(h CGoHandle) %s {\n", sym.id, ptrnm)
g.gofile.Indent()
g.gofile.Printf("p := gopyh.VarFromHandle((gopyh.CGoHandle)(h), %[1]q)\n", gonm)
g.gofile.Printf("if p == nil {\n")
g.gofile.Indent()
g.gofile.Printf("return nil\n")
g.gofile.Outdent()
g.gofile.Printf("}\n")
g.gofile.Printf("return p.(%s)\n", ptrnm)
g.gofile.Outdent()
g.gofile.Printf("}\n")
g.gofile.Printf("func deptrFromHandle_%s(h CGoHandle) %s {\n", sym.id, nptrnm)
g.gofile.Indent()
g.gofile.Printf("p := ptrFromHandle_%s(h)\n", sym.id)
if !sym.isArray() {
g.gofile.Printf("if p == nil {\n")
g.gofile.Indent()
g.gofile.Printf("return nil\n")
g.gofile.Outdent()
g.gofile.Printf("}\n")
}
g.gofile.Printf("return *p\n")
g.gofile.Outdent()
g.gofile.Printf("}\n")
g.gofile.Printf("func %s(p interface{})%s CGoHandle {\n", sym.go2py, sym.go2pyParenEx)
g.gofile.Indent()
g.gofile.Printf("return CGoHandle(gopyh.Register(\"%s\", p))\n", gonm)
g.gofile.Outdent()
g.gofile.Printf("}\n")
}
func nonPtrName(nm string) string {
if nm[0] == '*' {
return nm[1:]
}
return nm
}
func (g *pyGen) genTypeHandle(sym *symbol) {
gonm := sym.goname
ptrnm := gonm
if ptrnm[0] != '*' {
ptrnm = "*" + ptrnm
}
py2go := nonPtrName(sym.py2go)
g.gofile.Printf("\n// Converters for non-pointer handles for type: %s\n", gonm)
g.gofile.Printf("func %s(h CGoHandle) %s {\n", py2go, ptrnm)
g.gofile.Indent()
g.gofile.Printf("p := gopyh.VarFromHandle((gopyh.CGoHandle)(h), %[1]q)\n", gonm)
g.gofile.Printf("if p == nil {\n")
g.gofile.Indent()
g.gofile.Printf("return nil\n")
g.gofile.Outdent()
g.gofile.Printf("}\n")
if sym.isStruct() {
g.gofile.Printf("return gopyh.Embed(p, reflect.TypeOf(%s{})).(%s)\n", nonPtrName(gonm), ptrnm)
} else {
g.gofile.Printf("return p.(%s)\n", ptrnm)
}
g.gofile.Outdent()
g.gofile.Printf("}\n")
g.gofile.Printf("func %s(p interface{})%s CGoHandle {\n", sym.go2py, sym.go2pyParenEx)
g.gofile.Indent()
g.gofile.Printf("return CGoHandle(gopyh.Register(\"%s\", p))\n", gonm)
g.gofile.Outdent()
g.gofile.Printf("}\n")
}
// genExtClass generates minimal python wrappers for external classes (struct, interface, etc)
func (g *pyGen) genExtClass(sym *symbol) {
pkgname := sym.gopkg.Name()
// note: all external wrapper classes are defined in base go.py module, so we exclude go.
g.pywrap.Printf(`
# Python type for %[4]s
class %[2]s(GoClass):
""%[3]q""
`,
pkgname,
sym.id,
sym.doc,
sym.goname,
)
g.pywrap.Indent()
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.Printf("_%s.IncRef(self.handle)\n", g.pypkgname)
g.pywrap.Outdent()
g.pywrap.Printf("elif len(args) == 1 and isinstance(args[0], GoClass):\n")
g.pywrap.Indent()
g.pywrap.Printf("self.handle = args[0].handle\n")
g.pywrap.Printf("_%s.IncRef(self.handle)\n", g.pypkgname)
g.pywrap.Outdent()
g.pywrap.Printf("elif len(args) == 1 and isinstance(args[0], int):\n")
g.pywrap.Indent()
g.pywrap.Printf("self.handle = args[0]\n")
g.pywrap.Printf("_%s.IncRef(self.handle)\n", g.pypkgname)
g.pywrap.Outdent()
g.pywrap.Printf("else:\n")
g.pywrap.Indent()
g.pywrap.Printf("self.handle = 0\n")
g.pywrap.Outdent()
g.pywrap.Outdent()
g.pywrap.Printf("def __del__(self):\n")
g.pywrap.Indent()
g.pywrap.Printf("_%s.DecRef(self.handle)\n", g.pypkgname)
g.pywrap.Outdent()
g.pywrap.Printf("\n")
g.pywrap.Outdent()
}