mirror of https://github.com/go-python/gopy.git
398 lines
12 KiB
Go
398 lines
12 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"
|
|
"strings"
|
|
)
|
|
|
|
// extTypes = these are types external to any targeted packages
|
|
// pyWrapOnly = only generate python wrapper code, not go code
|
|
// mpob = Map object -- for methods
|
|
func (g *pyGen) genMap(slc *symbol, extTypes, pyWrapOnly bool, mpob *Map) {
|
|
if slc.isPointer() {
|
|
return // TODO: not sure what to do..
|
|
}
|
|
_, ok := slc.GoType().Underlying().(*types.Map)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
pkgname := slc.gopkg.Name()
|
|
|
|
// TODO: maybe check for named type here or something?
|
|
pysnm := slc.id
|
|
if !strings.Contains(pysnm, "Map_") {
|
|
pysnm = strings.TrimPrefix(pysnm, pkgname+"_")
|
|
}
|
|
|
|
gocl := "go."
|
|
if g.pkg == goPackage {
|
|
gocl = ""
|
|
}
|
|
|
|
if !extTypes || pyWrapOnly {
|
|
// TODO: inherit from collections.Iterable too?
|
|
g.pywrap.Printf(`
|
|
# Python type for map %[4]s
|
|
class %[2]s(%[5]sGoClass):
|
|
""%[3]q""
|
|
`,
|
|
pkgname,
|
|
pysnm,
|
|
slc.doc,
|
|
slc.goname,
|
|
gocl,
|
|
)
|
|
g.pywrap.Indent()
|
|
}
|
|
|
|
g.genMapInit(slc, extTypes, pyWrapOnly, mpob)
|
|
if mpob != nil {
|
|
g.genMapMethods(mpob)
|
|
}
|
|
if !extTypes || pyWrapOnly {
|
|
g.pywrap.Outdent()
|
|
}
|
|
}
|
|
|
|
func (g *pyGen) genMapInit(slc *symbol, extTypes, pyWrapOnly bool, mpob *Map) {
|
|
pkgname := g.cfg.Name
|
|
slNm := slc.id
|
|
qNm := pkgname + "." + slNm
|
|
typ := slc.GoType().Underlying().(*types.Map)
|
|
esym := current.symtype(typ.Elem())
|
|
ksym := current.symtype(typ.Key())
|
|
|
|
// key slice type and name
|
|
keyslt := types.NewSlice(typ.Key())
|
|
keyslsym := current.symtype(keyslt)
|
|
if keyslsym == nil {
|
|
fmt.Printf("nil key slice type!: %s map: %s\n", current.fullTypeString(keyslt), slc.goname)
|
|
return
|
|
}
|
|
keyslnm := ""
|
|
if g.pkg == nil {
|
|
keyslnm = keyslsym.id
|
|
} else {
|
|
keyslnm = keyslsym.pyPkgId(g.pkg.pkg)
|
|
}
|
|
|
|
gocl := "go."
|
|
if g.pkg == goPackage {
|
|
gocl = ""
|
|
}
|
|
|
|
if !extTypes || pyWrapOnly {
|
|
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 parameter is a python list that we copy from
|
|
"""
|
|
`)
|
|
g.pywrap.Printf("self.index = 0\n")
|
|
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], %sGoClass):\n", gocl)
|
|
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("else:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("self.handle = _%s_CTor()\n", qNm)
|
|
g.pywrap.Printf("_%s.IncRef(self.handle)\n", g.pypkgname)
|
|
g.pywrap.Printf("if len(args) > 0:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("if not isinstance(args[0], _collections_abc.Mapping):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("raise TypeError('%s.__init__ takes a mapping as argument')\n", slNm)
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("for k, v in args[0].items():\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("_%s_set(self.handle, k, v)\n", qNm)
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Outdent()
|
|
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()
|
|
|
|
if mpob != nil && mpob.prots&ProtoStringer != 0 {
|
|
for _, m := range mpob.meths {
|
|
if isStringer(m.obj) {
|
|
g.pywrap.Printf("def __str__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.genStringerCall()
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("\n")
|
|
}
|
|
}
|
|
} else {
|
|
g.pywrap.Printf("def __str__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("s = '%s.%s len: ' + str(len(self)) + ' handle: ' + str(self.handle) + ' {'\n", pkgname, slNm)
|
|
g.pywrap.Printf("if len(self) < 120:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("for k, v in self.items():\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("s += str(k) + '=' + str(v) + ', '\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Println("return s + '}'")
|
|
g.pywrap.Outdent()
|
|
}
|
|
|
|
g.pywrap.Printf("def __repr__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("s = '%s.%s({'\n", pkgname, slNm)
|
|
g.pywrap.Printf("for k, v in self.items():\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("s += str(k) + '=' + str(v) + ', '\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Println("return s + '})'")
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def __len__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("return _%s_len(self.handle)\n", qNm)
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def __getitem__(self, key):\n")
|
|
g.pywrap.Indent()
|
|
if ksym.hasHandle() {
|
|
if esym.hasHandle() {
|
|
g.pywrap.Printf("return %s(handle=_%s_elem(self.handle, key.handle))\n", esym.pyPkgId(slc.gopkg), qNm)
|
|
} else {
|
|
g.pywrap.Printf("return _%s_elem(self.handle, key.handle)\n", qNm)
|
|
}
|
|
} else {
|
|
if esym.hasHandle() {
|
|
g.pywrap.Printf("return %s(handle=_%s_elem(self.handle, key))\n", esym.pyPkgId(slc.gopkg), qNm)
|
|
} else {
|
|
g.pywrap.Printf("return _%s_elem(self.handle, key)\n", qNm)
|
|
}
|
|
}
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def __setitem__(self, key, value):\n")
|
|
g.pywrap.Indent()
|
|
if esym.hasHandle() {
|
|
if ksym.hasHandle() {
|
|
g.pywrap.Printf("_%s_set(self.handle, key.handle, value.handle)\n", qNm)
|
|
} else {
|
|
g.pywrap.Printf("_%s_set(self.handle, key, value.handle)\n", qNm)
|
|
}
|
|
} else {
|
|
if ksym.hasHandle() {
|
|
g.pywrap.Printf("_%s_set(self.handle, key.handle, value)\n", qNm)
|
|
} else {
|
|
g.pywrap.Printf("_%s_set(self.handle, key, value)\n", qNm)
|
|
}
|
|
}
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def __delitem__(self, key):\n")
|
|
g.pywrap.Indent()
|
|
if ksym.hasHandle() {
|
|
g.pywrap.Printf("return _%s_delete(self.handle, key.handle)\n", qNm)
|
|
} else {
|
|
g.pywrap.Printf("return _%s_delete(self.handle, key)\n", qNm)
|
|
}
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def keys(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("return %s(handle=_%s_keys(self.handle))\n", keyslnm, qNm)
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def values(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("vls = []\n")
|
|
g.pywrap.Printf("kys = self.keys()\n")
|
|
g.pywrap.Printf("for k in kys:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("vls.append(self[k])\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("return vls\n")
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def items(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("vls = []\n")
|
|
g.pywrap.Printf("kys = self.keys()\n")
|
|
g.pywrap.Printf("for k in kys:\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("vls.append((k, self[k]))\n")
|
|
g.pywrap.Outdent()
|
|
g.pywrap.Printf("return vls\n")
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def __iter__(self):\n")
|
|
g.pywrap.Indent()
|
|
g.pywrap.Printf("return iter(self.items())\n")
|
|
g.pywrap.Outdent()
|
|
|
|
g.pywrap.Printf("def __contains__(self, key):\n")
|
|
g.pywrap.Indent()
|
|
if ksym.hasHandle() {
|
|
g.pywrap.Printf("return _%s_contains(self.handle, key.handle)\n", qNm)
|
|
} else {
|
|
g.pywrap.Printf("return _%s_contains(self.handle, key)\n", qNm)
|
|
}
|
|
g.pywrap.Outdent()
|
|
|
|
// g.pywrap.Printf("def __next__(self):\n")
|
|
// g.pywrap.Indent()
|
|
// g.pywrap.Printf("if self.index >= len(self):\n")
|
|
// g.pywrap.Indent()
|
|
// g.pywrap.Printf("raise StopIteration\n")
|
|
// g.pywrap.Outdent()
|
|
// g.pywrap.Printf("self.index = self.index + 1\n")
|
|
// g.pywrap.Printf("return _%s_elem(self.handle, self.index)\n", qNm)
|
|
// g.pywrap.Outdent()
|
|
}
|
|
|
|
if !extTypes || !pyWrapOnly {
|
|
// go ctor
|
|
ctNm := slNm + "_CTor"
|
|
g.gofile.Printf("\n// --- wrapping map: %v ---\n", slc.goname)
|
|
g.gofile.Printf("//export %s\n", ctNm)
|
|
g.gofile.Printf("func %s() CGoHandle {\n", ctNm)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("return CGoHandle(handleFromPtr_%[1]s(&%[2]s{}))\n", slNm, slc.goname)
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s', retval('%s'), [])\n", ctNm, PyHandle)
|
|
|
|
// len
|
|
g.gofile.Printf("//export %s_len\n", slNm)
|
|
g.gofile.Printf("func %s_len(handle CGoHandle) int {\n", slNm)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("return len(deptrFromHandle_%s(handle))\n", slNm)
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s_len', retval('int'), [param('%s', 'handle')])\n", slNm, PyHandle)
|
|
|
|
// elem
|
|
g.gofile.Printf("//export %s_elem\n", slNm)
|
|
g.gofile.Printf("func %s_elem(handle CGoHandle, _ky %s) %s {\n", slNm, ksym.cgoname, esym.cgoname)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
|
|
if ksym.py2go != "" {
|
|
g.gofile.Printf("v, ok := s[%s(_ky)%s]\n", ksym.py2go, ksym.py2goParenEx)
|
|
} else {
|
|
g.gofile.Printf("v, ok := s[_ky]\n")
|
|
}
|
|
g.gofile.Printf("if !ok {\n")
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("C.PyErr_SetString(C.PyExc_KeyError, C.CString(\"key not in map\"))\n")
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n")
|
|
if esym.go2py != "" {
|
|
// If the go2py starts with handleFromPtr_, use &v, otherwise just v
|
|
val_str := ""
|
|
if strings.HasPrefix(esym.go2py, "handleFromPtr_") {
|
|
val_str = "&v"
|
|
} else {
|
|
val_str = "v"
|
|
}
|
|
g.gofile.Printf("return %s(%s)%s\n", esym.go2py, val_str, esym.go2pyParenEx)
|
|
} else {
|
|
g.gofile.Printf("return v\n")
|
|
}
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s_elem', retval('%s'), [param('%s', 'handle'), param('%s', '_ky')])\n", slNm, esym.cpyname, PyHandle, ksym.cpyname)
|
|
|
|
// contains
|
|
g.gofile.Printf("//export %s_contains\n", slNm)
|
|
g.gofile.Printf("func %s_contains(handle CGoHandle, _ky %s) C.char {\n", slNm, ksym.cgoname)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
|
|
if ksym.py2go != "" {
|
|
g.gofile.Printf("_, ok := s[%s(_ky)%s]\n", ksym.py2go, ksym.py2goParenEx)
|
|
} else {
|
|
g.gofile.Printf("_, ok := s[_ky]\n")
|
|
}
|
|
g.gofile.Printf("return boolGoToPy(ok)\n")
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s_contains', retval('bool'), [param('%s', 'handle'), param('%s', '_ky')])\n", slNm, PyHandle, ksym.cpyname)
|
|
|
|
// set
|
|
g.gofile.Printf("//export %s_set\n", slNm)
|
|
g.gofile.Printf("func %s_set(handle CGoHandle, _ky %s, _vl %s) {\n", slNm, ksym.cgoname, esym.cgoname)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
|
|
if ksym.py2go != "" {
|
|
g.gofile.Printf("s[%s(_ky)%s] = ", ksym.py2go, ksym.py2goParenEx)
|
|
} else {
|
|
g.gofile.Printf("s[_ky] = ")
|
|
}
|
|
if esym.py2go != "" {
|
|
g.gofile.Printf("%s(_vl)%s\n", esym.py2go, esym.py2goParenEx)
|
|
} else {
|
|
g.gofile.Printf("_vl\n")
|
|
}
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s_set', None, [param('%s', 'handle'), param('%s', 'key'), param('%s', 'value')])\n", slNm, PyHandle, ksym.cpyname, esym.cpyname)
|
|
|
|
// delete
|
|
g.gofile.Printf("//export %s_delete\n", slNm)
|
|
g.gofile.Printf("func %s_delete(handle CGoHandle, _ky %s) {\n", slNm, ksym.cgoname)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
|
|
if ksym.py2go != "" {
|
|
g.gofile.Printf("delete(s, %s(_ky)%s)\n", ksym.py2go, ksym.py2goParenEx)
|
|
} else {
|
|
g.gofile.Printf("delete(s, _ky)\n")
|
|
}
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s_delete', None, [param('%s', 'handle'), param('%s', '_ky')])\n", slNm, PyHandle, ksym.cpyname)
|
|
|
|
// keys
|
|
g.gofile.Printf("//export %s_keys\n", slNm)
|
|
g.gofile.Printf("func %s_keys(handle CGoHandle) CGoHandle {\n", slNm)
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
|
|
g.gofile.Printf("kys := make(%s, 0, len(s))\n", keyslsym.goname)
|
|
g.gofile.Printf("for k := range(s) {\n")
|
|
g.gofile.Indent()
|
|
g.gofile.Printf("kys = append(kys, k)\n")
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n")
|
|
g.gofile.Printf("return %s(&kys)%s\n", keyslsym.go2py, keyslsym.go2pyParenEx)
|
|
g.gofile.Outdent()
|
|
g.gofile.Printf("}\n\n")
|
|
|
|
g.pybuild.Printf("mod.add_function('%s_keys', retval('%s'), [param('%s', 'handle')])\n", slNm, keyslsym.cpyname, PyHandle)
|
|
|
|
}
|
|
}
|
|
|
|
func (g *pyGen) genMapMethods(s *Map) {
|
|
for _, m := range s.meths {
|
|
g.genMethod(s.sym, m)
|
|
}
|
|
}
|