Skip to content

Commit 6d8fa23

Browse files
authored
Merge pull request #230 from rcoreilly/master
for slices with non-pointer struct element types, need to return pointer to element
2 parents ac88620 + 668e31d commit 6d8fa23

File tree

9 files changed

+249
-18
lines changed

9 files changed

+249
-18
lines changed

bind/gen.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ os.chdir(cwd)
250250
# %[2]s
251251
252252
import _%[1]s, collections
253+
from enum import Enum
253254
254255
# to use this code in your end-user python file, import it as follows:
255256
# from %[1]s import %[3]s
@@ -757,6 +758,11 @@ func (g *pyGen) genAll() {
757758
g.genType(sym, false, false) // not exttypes
758759
}
759760

761+
g.pywrap.Printf("\n\n#---- Enums from Go (collections of consts with same type) ---\n")
762+
for _, e := range g.pkg.enums {
763+
g.genEnum(e)
764+
}
765+
760766
g.pywrap.Printf("\n\n#---- Constants from Go: Python can only ask that you please don't change these! ---\n")
761767
for _, c := range g.pkg.consts {
762768
g.genConst(c)

bind/gen_func.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ func (g *pyGen) genMethod(s *symbol, o *Func) {
220220
}
221221

222222
func isIfaceHandle(gdoc string) (bool, string) {
223-
const PythonIface = "\ngopy:interface=handle"
224-
if idx := strings.Index(gdoc, PythonIface); idx > 0 {
223+
const PythonIface = "gopy:interface=handle"
224+
if idx := strings.Index(gdoc, PythonIface); idx >= 0 {
225225
gdoc = gdoc[:idx] + gdoc[idx+len(PythonIface)+1:]
226226
return true, gdoc
227227
}

bind/gen_map.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ otherwise parameter is a python list that we copy from
281281
g.gofile.Printf("//export %s_len\n", slNm)
282282
g.gofile.Printf("func %s_len(handle CGoHandle) int {\n", slNm)
283283
g.gofile.Indent()
284-
g.gofile.Printf("return len(*ptrFromHandle_%s(handle))\n", slNm)
284+
g.gofile.Printf("return len(deptrFromHandle_%s(handle))\n", slNm)
285285
g.gofile.Outdent()
286286
g.gofile.Printf("}\n\n")
287287

@@ -291,7 +291,7 @@ otherwise parameter is a python list that we copy from
291291
g.gofile.Printf("//export %s_elem\n", slNm)
292292
g.gofile.Printf("func %s_elem(handle CGoHandle, _ky %s) %s {\n", slNm, ksym.cgoname, esym.cgoname)
293293
g.gofile.Indent()
294-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
294+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
295295
if ksym.py2go != "" {
296296
g.gofile.Printf("v, ok := s[%s(_ky)%s]\n", ksym.py2go, ksym.py2goParenEx)
297297
} else {
@@ -316,7 +316,7 @@ otherwise parameter is a python list that we copy from
316316
g.gofile.Printf("//export %s_contains\n", slNm)
317317
g.gofile.Printf("func %s_contains(handle CGoHandle, _ky %s) C.char {\n", slNm, ksym.cgoname)
318318
g.gofile.Indent()
319-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
319+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
320320
if ksym.py2go != "" {
321321
g.gofile.Printf("_, ok := s[%s(_ky)%s]\n", ksym.py2go, ksym.py2goParenEx)
322322
} else {
@@ -332,7 +332,7 @@ otherwise parameter is a python list that we copy from
332332
g.gofile.Printf("//export %s_set\n", slNm)
333333
g.gofile.Printf("func %s_set(handle CGoHandle, _ky %s, _vl %s) {\n", slNm, ksym.cgoname, esym.cgoname)
334334
g.gofile.Indent()
335-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
335+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
336336
if ksym.py2go != "" {
337337
g.gofile.Printf("s[%s(_ky)%s] = ", ksym.py2go, ksym.py2goParenEx)
338338
} else {
@@ -352,7 +352,7 @@ otherwise parameter is a python list that we copy from
352352
g.gofile.Printf("//export %s_delete\n", slNm)
353353
g.gofile.Printf("func %s_delete(handle CGoHandle, _ky %s) {\n", slNm, ksym.cgoname)
354354
g.gofile.Indent()
355-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
355+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
356356
if ksym.py2go != "" {
357357
g.gofile.Printf("delete(s, %s(_ky)%s)\n", ksym.py2go, ksym.py2goParenEx)
358358
} else {
@@ -367,7 +367,7 @@ otherwise parameter is a python list that we copy from
367367
g.gofile.Printf("//export %s_keys\n", slNm)
368368
g.gofile.Printf("func %s_keys(handle CGoHandle) CGoHandle {\n", slNm)
369369
g.gofile.Indent()
370-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
370+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
371371
g.gofile.Printf("kys := make(%s, 0, len(s))\n", keyslsym.goname)
372372
g.gofile.Printf("for k := range(s) {\n")
373373
g.gofile.Indent()

bind/gen_slice.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ func (g *pyGen) genSliceInit(slc *symbol, extTypes, pyWrapOnly bool, slob *Slice
7575
gocl = ""
7676
}
7777

78+
pysnm := slc.id
79+
if !strings.Contains(pysnm, "Slice_") {
80+
pysnm = strings.TrimPrefix(pysnm, pkgname+"_")
81+
}
82+
7883
if !extTypes || pyWrapOnly {
7984
g.pywrap.Printf("def __init__(self, *args, **kwargs):\n")
8085
g.pywrap.Indent()
@@ -154,6 +159,22 @@ otherwise parameter is a python list that we copy from
154159
g.pywrap.Indent()
155160
g.pywrap.Printf("if isinstance(key, slice):\n")
156161
g.pywrap.Indent()
162+
if slc.isSlice() {
163+
g.pywrap.Printf("if key.step == None or key.step == 1:\n")
164+
g.pywrap.Indent()
165+
g.pywrap.Printf("st = key.start\n")
166+
g.pywrap.Printf("ed = key.stop\n")
167+
g.pywrap.Printf("if st == None:\n")
168+
g.pywrap.Indent()
169+
g.pywrap.Printf("st = 0\n")
170+
g.pywrap.Outdent()
171+
g.pywrap.Printf("if ed == None:\n")
172+
g.pywrap.Indent()
173+
g.pywrap.Printf("ed = _%s_len(self.handle)\n", qNm)
174+
g.pywrap.Outdent()
175+
g.pywrap.Printf("return %s(handle=_%s_subslice(self.handle, st, ed))\n", pysnm, qNm)
176+
g.pywrap.Outdent()
177+
}
157178
g.pywrap.Printf("return [self[ii] for ii in range(*key.indices(len(self)))]\n")
158179
g.pywrap.Outdent()
159180
g.pywrap.Printf("elif isinstance(key, int):\n")
@@ -270,7 +291,7 @@ otherwise parameter is a python list that we copy from
270291
g.gofile.Printf("//export %s_len\n", slNm)
271292
g.gofile.Printf("func %s_len(handle CGoHandle) int {\n", slNm)
272293
g.gofile.Indent()
273-
g.gofile.Printf("return len(*ptrFromHandle_%s(handle))\n", slNm)
294+
g.gofile.Printf("return len(deptrFromHandle_%s(handle))\n", slNm)
274295
g.gofile.Outdent()
275296
g.gofile.Printf("}\n\n")
276297

@@ -279,9 +300,13 @@ otherwise parameter is a python list that we copy from
279300
g.gofile.Printf("//export %s_elem\n", slNm)
280301
g.gofile.Printf("func %s_elem(handle CGoHandle, _idx int) %s {\n", slNm, esym.cgoname)
281302
g.gofile.Indent()
282-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
303+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
283304
if esym.go2py != "" {
284-
g.gofile.Printf("return %s(s[_idx])%s\n", esym.go2py, esym.go2pyParenEx)
305+
if !esym.isPointer() && esym.isStruct() {
306+
g.gofile.Printf("return %s(&(s[_idx]))%s\n", esym.go2py, esym.go2pyParenEx)
307+
} else {
308+
g.gofile.Printf("return %s(s[_idx])%s\n", esym.go2py, esym.go2pyParenEx)
309+
}
285310
} else {
286311
g.gofile.Printf("return s[_idx]\n")
287312
}
@@ -290,10 +315,23 @@ otherwise parameter is a python list that we copy from
290315

291316
g.pybuild.Printf("mod.add_function('%s_elem', retval('%s'), [param('%s', 'handle'), param('int', 'idx')])\n", slNm, esym.cpyname, PyHandle)
292317

318+
if slc.isSlice() {
319+
g.gofile.Printf("//export %s_subslice\n", slNm)
320+
g.gofile.Printf("func %s_subslice(handle CGoHandle, _st, _ed int) CGoHandle {\n", slNm)
321+
g.gofile.Indent()
322+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
323+
g.gofile.Printf("ss := s[_st:_ed]\n")
324+
g.gofile.Printf("return CGoHandle(handleFromPtr_%s(&ss))\n", slNm)
325+
g.gofile.Outdent()
326+
g.gofile.Printf("}\n\n")
327+
328+
g.pybuild.Printf("mod.add_function('%s_subslice', retval('%s'), [param('%s', 'handle'), param('int', 'st'), param('int', 'ed')])\n", slNm, PyHandle, PyHandle)
329+
}
330+
293331
g.gofile.Printf("//export %s_set\n", slNm)
294332
g.gofile.Printf("func %s_set(handle CGoHandle, _idx int, _vl %s) {\n", slNm, esym.cgoname)
295333
g.gofile.Indent()
296-
g.gofile.Printf("s := *ptrFromHandle_%s(handle)\n", slNm)
334+
g.gofile.Printf("s := deptrFromHandle_%s(handle)\n", slNm)
297335
if esym.py2go != "" {
298336
g.gofile.Printf("s[_idx] = %s(_vl)%s\n", esym.py2go, esym.py2goParenEx)
299337
} else {

bind/gen_type.go

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ func (g *pyGen) genType(sym *symbol, extTypes, pyWrapOnly bool) {
2525
}
2626

2727
if !pyWrapOnly {
28-
if sym.isPointer() || sym.isInterface() {
28+
switch {
29+
case sym.isPointer() || sym.isInterface():
2930
g.genTypeHandlePtr(sym)
30-
} else {
31+
case sym.isSlice() || sym.isMap() || sym.isArray():
32+
g.genTypeHandleImplPtr(sym)
33+
default:
3134
g.genTypeHandle(sym)
3235
}
3336
}
@@ -84,6 +87,48 @@ func (g *pyGen) genTypeHandlePtr(sym *symbol) {
8487
g.gofile.Printf("}\n")
8588
}
8689

90+
// implicit pointer types: slice, map, array
91+
func (g *pyGen) genTypeHandleImplPtr(sym *symbol) {
92+
gonm := sym.gofmt()
93+
ptrnm := gonm
94+
nptrnm := gonm
95+
if ptrnm[0] != '*' {
96+
ptrnm = "*" + ptrnm
97+
} else {
98+
nptrnm = gonm[1:]
99+
}
100+
g.gofile.Printf("\n// Converters for implicit pointer handles for type: %s\n", gonm)
101+
g.gofile.Printf("func ptrFromHandle_%s(h CGoHandle) %s {\n", sym.id, ptrnm)
102+
g.gofile.Indent()
103+
g.gofile.Printf("p := gopyh.VarFromHandle((gopyh.CGoHandle)(h), %[1]q)\n", gonm)
104+
g.gofile.Printf("if p == nil {\n")
105+
g.gofile.Indent()
106+
g.gofile.Printf("return nil\n")
107+
g.gofile.Outdent()
108+
g.gofile.Printf("}\n")
109+
g.gofile.Printf("return p.(%s)\n", ptrnm)
110+
g.gofile.Outdent()
111+
g.gofile.Printf("}\n")
112+
g.gofile.Printf("func deptrFromHandle_%s(h CGoHandle) %s {\n", sym.id, nptrnm)
113+
g.gofile.Indent()
114+
g.gofile.Printf("p := ptrFromHandle_%s(h)\n", sym.id)
115+
if !sym.isArray() {
116+
g.gofile.Printf("if p == nil {\n")
117+
g.gofile.Indent()
118+
g.gofile.Printf("return nil\n")
119+
g.gofile.Outdent()
120+
g.gofile.Printf("}\n")
121+
}
122+
g.gofile.Printf("return *p\n")
123+
g.gofile.Outdent()
124+
g.gofile.Printf("}\n")
125+
g.gofile.Printf("func %s(p interface{})%s CGoHandle {\n", sym.go2py, sym.go2pyParenEx)
126+
g.gofile.Indent()
127+
g.gofile.Printf("return CGoHandle(gopyh.Register(\"%s\", p))\n", gonm)
128+
g.gofile.Outdent()
129+
g.gofile.Printf("}\n")
130+
}
131+
87132
func nonPtrName(nm string) string {
88133
if nm[0] == '*' {
89134
return nm[1:]

bind/gen_varconst.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package bind
66

77
import (
88
"fmt"
9+
"strings"
910
)
1011

1112
func (g *pyGen) genConst(c *Const) {
@@ -110,7 +111,7 @@ func (g *pyGen) genVarSetter(v *Var) {
110111

111112
func (g *pyGen) genConstValue(c *Const) {
112113
// constants go directly into wrapper as-is
113-
val := c.obj.Val().ExactString()
114+
val := c.val
114115
switch val {
115116
case "true":
116117
val = "True"
@@ -119,3 +120,34 @@ func (g *pyGen) genConstValue(c *Const) {
119120
}
120121
g.pywrap.Printf("%s = %s\n", c.GoName(), val)
121122
}
123+
124+
func (g *pyGen) genEnum(e *Enum) {
125+
g.pywrap.Printf("class %s(Enum):\n", e.typ.Obj().Name())
126+
g.pywrap.Indent()
127+
doc := e.Doc()
128+
if doc != "" {
129+
lns := strings.Split(doc, "\n")
130+
g.pywrap.Printf(`"""`)
131+
g.pywrap.Printf("\n")
132+
for _, l := range lns {
133+
g.pywrap.Printf("%s\n", l)
134+
}
135+
g.pywrap.Printf(`"""`)
136+
g.pywrap.Printf("\n")
137+
}
138+
e.SortConsts()
139+
for _, c := range e.items {
140+
g.genConstValue(c)
141+
}
142+
g.pywrap.Outdent()
143+
144+
// Go has each const value globally available within a given package
145+
// so to keep the code consistent, we redundantly generate the consts
146+
// again here. The Enum organization however is critical for organizing
147+
// the values under the type (making them accessible programmatically)
148+
g.pywrap.Printf("\n")
149+
for _, c := range e.items {
150+
g.genConstValue(c)
151+
}
152+
g.pywrap.Printf("\n")
153+
}

bind/package.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"go/types"
1111
"path/filepath"
1212
"reflect"
13+
"strconv"
1314
"strings"
1415
)
1516

@@ -24,6 +25,7 @@ type Package struct {
2425
syms *symtab // note: this is now *always* = symbols.current
2526
objs map[string]Object
2627
consts []*Const
28+
enums []*Enum
2729
vars []*Var
2830
structs []*Struct
2931
ifaces []*Interface
@@ -132,6 +134,7 @@ func (p *Package) getDoc(parent string, o types.Object) string {
132134
if err != nil {
133135
return ""
134136
}
137+
135138
doc := func() string {
136139
if o.Parent() == nil || (o.Parent() != nil && parent != "") {
137140
for _, typ := range p.doc.Types {
@@ -162,6 +165,28 @@ func (p *Package) getDoc(parent string, o types.Object) string {
162165
return ""
163166
}()
164167

168+
// if a function returns a type defined in the package,
169+
// it is organized under that type
170+
if doc == "" && sig.Results().Len() == 1 {
171+
ret := sig.Results().At(0).Type()
172+
if ntyp, ok := ret.(*types.Named); ok {
173+
tn := ntyp.Obj().Name()
174+
doc = func() string {
175+
for _, typ := range p.doc.Types {
176+
if typ.Name != tn {
177+
continue
178+
}
179+
for _, m := range typ.Funcs {
180+
if m.Name == n {
181+
return m.Doc
182+
}
183+
}
184+
}
185+
return ""
186+
}()
187+
}
188+
}
189+
165190
parseFn := func(tup *types.Tuple) []string {
166191
params := []string{}
167192
if tup == nil {
@@ -461,7 +486,34 @@ func (p *Package) process() error {
461486
return err
462487
}
463488

489+
func (p *Package) findEnum(ntyp *types.Named) *Enum {
490+
for _, enm := range p.enums {
491+
if enm.typ == ntyp {
492+
return enm
493+
}
494+
}
495+
return nil
496+
}
497+
464498
func (p *Package) addConst(obj *types.Const) {
499+
if ntyp, ok := obj.Type().(*types.Named); ok {
500+
enm := p.findEnum(ntyp)
501+
if enm != nil {
502+
enm.AddConst(p, obj)
503+
return
504+
} else {
505+
val := obj.Val().String()
506+
_, err := strconv.Atoi(val)
507+
if err == nil {
508+
enm, err := newEnum(p, obj)
509+
if err == nil {
510+
p.enums = append(p.enums, enm)
511+
return
512+
}
513+
}
514+
}
515+
}
516+
465517
nc, err := newConst(p, obj)
466518
if err == nil {
467519
p.consts = append(p.consts, nc)

0 commit comments

Comments
 (0)