Skip to content

Commit ece09ed

Browse files
One test case of variadic functions now passing. More to clear.
1 parent fcad870 commit ece09ed

File tree

6 files changed

+106
-42
lines changed

6 files changed

+106
-42
lines changed

_examples/variadic/test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2018 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
import variadic, go
5+
6+
varResult = variadic.VariFunc(1,2,3,4,5)
7+
print("Variadic 1+2+3+4+5 = %d" % varResult)
8+
9+
nonvarResult = variadic.NonVariFunc(1, go.Slice_int([2,3,4]),5)
10+
print("NonVariadic 1+[2+3+4]+5 = %d" % nonvarResult)
11+
12+
if isinstance(varResult, int):
13+
print("Type OK")
14+
else:
15+
print("Type Not OK")

_examples/variadic/variadic.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package variadic
2+
3+
func VariFunc(vargs ...int) int{
4+
total := 0
5+
for _, num := range vargs {
6+
total += num
7+
}
8+
return total
9+
}
10+
11+
func NonVariFunc(arg1 int, arg2 []int, arg3 int) int{
12+
total := arg1
13+
for _, num := range arg2 {
14+
total += num
15+
}
16+
total += arg3
17+
18+
return total
19+
}

bind/gen_func.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,22 @@ func (g *pyGen) genFuncSig(sym *symbol, fsym *Func) bool {
8787
return false
8888
}
8989
anm := pySafeArg(arg.Name(), i)
90+
9091
if ifchandle && arg.sym.goname == "interface{}" {
9192
goArgs = append(goArgs, fmt.Sprintf("%s %s", anm, CGoHandle))
9293
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s')", PyHandle, anm))
9394
} else {
9495
goArgs = append(goArgs, fmt.Sprintf("%s %s", anm, sarg.cgoname))
9596
if sarg.cpyname == "PyObject*" {
96-
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s', transfer_ownership=False)", sarg.cpyname, anm))
97+
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s%s', transfer_ownership=False)", sarg.cpyname, anm))
9798
} else {
9899
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s')", sarg.cpyname, anm))
99100
}
100101
}
101-
wpArgs = append(wpArgs, anm)
102+
103+
if i!=nargs-1 || !fsym.isVariadic {
104+
wpArgs = append(wpArgs, anm)
105+
}
102106
}
103107

104108
// support for optional arg to run in a separate go routine -- only if no return val
@@ -108,6 +112,11 @@ func (g *pyGen) genFuncSig(sym *symbol, fsym *Func) bool {
108112
wpArgs = append(wpArgs, "goRun=False")
109113
}
110114

115+
// To support variadic args, we add *args at the end.
116+
if fsym.isVariadic {
117+
wpArgs = append(wpArgs, "*args")
118+
}
119+
111120
// When building the pybindgen builder code, we start with
112121
// a function that adds function calls with exception checking.
113122
// But given specific return types, we may want to add more
@@ -276,25 +285,6 @@ if __err != nil {
276285
g.gofile.Printf("var __err error\n")
277286
}
278287

279-
// pywrap output
280-
mnm := fsym.ID()
281-
if isMethod {
282-
mnm = sym.id + "_" + fsym.GoName()
283-
}
284-
rvHasHandle := false
285-
if nres > 0 {
286-
ret := res[0]
287-
if !rvIsErr && ret.sym.hasHandle() {
288-
rvHasHandle = true
289-
cvnm := ret.sym.pyPkgId(g.pkg.pkg)
290-
g.pywrap.Printf("return %s(handle=_%s.%s(", cvnm, pkgname, mnm)
291-
} else {
292-
g.pywrap.Printf("return _%s.%s(", pkgname, mnm)
293-
}
294-
} else {
295-
g.pywrap.Printf("_%s.%s(", pkgname, mnm)
296-
}
297-
298288
callArgs := []string{}
299289
wrapArgs := []string{}
300290
if isMethod {
@@ -313,6 +303,9 @@ if __err != nil {
313303
default:
314304
na = anm
315305
}
306+
if i == len(args) - 1 && fsym.isVariadic {
307+
na = na + "..."
308+
}
316309
callArgs = append(callArgs, na)
317310
switch {
318311
case arg.sym.goname == "interface{}":
@@ -326,6 +319,30 @@ if __err != nil {
326319
default:
327320
wrapArgs = append(wrapArgs, anm)
328321
}
322+
323+
// To support variadic args, we add *args at the end.
324+
if fsym.isVariadic && i == len(args)-1 {
325+
g.pywrap.Printf("%s = go.Slice_int(args)\n", anm)
326+
}
327+
}
328+
329+
// pywrap output
330+
mnm := fsym.ID()
331+
if isMethod {
332+
mnm = sym.id + "_" + fsym.GoName()
333+
}
334+
rvHasHandle := false
335+
if nres > 0 {
336+
ret := res[0]
337+
if !rvIsErr && ret.sym.hasHandle() {
338+
rvHasHandle = true
339+
cvnm := ret.sym.pyPkgId(g.pkg.pkg)
340+
g.pywrap.Printf("return %s(handle=_%s.%s(", cvnm, pkgname, mnm)
341+
} else {
342+
g.pywrap.Printf("return _%s.%s(", pkgname, mnm)
343+
}
344+
} else {
345+
g.pywrap.Printf("_%s.%s(", pkgname, mnm)
329346
}
330347

331348
hasRetCvt := false

bind/symbols.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,6 @@ func isPyCompatField(f *types.Var) (*symbol, error) {
153153
func isPyCompatFunc(sig *types.Signature) (ret types.Type, haserr, hasfun bool, err error) {
154154
res := sig.Results()
155155

156-
if sig.Variadic() {
157-
err = fmt.Errorf("gopy: not yet supporting variadic functions: %s", sig.String())
158-
return
159-
}
160-
161156
switch res.Len() {
162157
case 2:
163158
if !isErrorType(res.At(1).Type()) {

bind/types.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,13 @@ type Func struct {
367367
obj types.Object
368368
name string
369369

370-
id string
371-
doc string
372-
ret types.Type // return type, if any
373-
err bool // true if original go func has comma-error
374-
ctor bool // true if this is a newXXX function
375-
hasfun bool // true if this function has a function argument
370+
id string
371+
doc string
372+
ret types.Type // return type, if any
373+
err bool // true if original go func has comma-error
374+
ctor bool // true if this is a newXXX function
375+
hasfun bool // true if this function has a function argument
376+
isVariadic bool // True, if this is a variadic function.
376377
}
377378

378379
func newFuncFrom(p *Package, parent string, obj types.Object, sig *types.Signature) (*Func, error) {
@@ -392,16 +393,17 @@ func newFuncFrom(p *Package, parent string, obj types.Object, sig *types.Signatu
392393
}
393394

394395
return &Func{
395-
obj: obj,
396-
pkg: p,
397-
sig: sv,
398-
typ: obj.Type(),
399-
name: obj.Name(),
400-
id: id,
401-
doc: p.getDoc(parent, obj),
402-
ret: ret,
403-
err: haserr,
404-
hasfun: hasfun,
396+
obj: obj,
397+
pkg: p,
398+
sig: sv,
399+
typ: obj.Type(),
400+
name: obj.Name(),
401+
id: id,
402+
doc: p.getDoc(parent, obj),
403+
ret: ret,
404+
err: haserr,
405+
hasfun: hasfun,
406+
isVariadic: sig.Variadic(),
405407
}, nil
406408

407409
// TODO: could optimize by generating code once for each type of callback

main_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ var (
4848
"_examples/gopygc": []string{"py2", "py3"},
4949
"_examples/cstrings": []string{"py2", "py3"},
5050
"_examples/pkgconflict": []string{"py2", "py3"},
51+
"_examples/variadic": []string{"py3"},
5152
}
5253

5354
testEnvironment = os.Environ()
@@ -811,6 +812,21 @@ func TestPkgConflict(t *testing.T) {
811812
// })
812813
// }
813814

815+
func TestBindVariadic(t *testing.T) {
816+
// t.Parallel()
817+
path := "_examples/variadic"
818+
testPkg(t, pkg{
819+
path: path,
820+
lang: features[path],
821+
cmd: "build",
822+
extras: nil,
823+
want: []byte(`Variadic 1+2+3+4+5 = 15
824+
NonVariadic 1+[2+3+4]+5 = 15
825+
Type OK
826+
`),
827+
})
828+
}
829+
814830
// Generate / verify SUPPORT_MATRIX.md from features map.
815831
func TestCheckSupportMatrix(t *testing.T) {
816832
var buf bytes.Buffer

0 commit comments

Comments
 (0)