diff options
author | alandonovan <adonovan@google.com> | 2018-10-22 13:41:53 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-22 13:41:53 -0400 |
commit | 8160121a4f3bdd86c16f1772825b50eddcf04d72 (patch) | |
tree | 8d0298caf7e2818eb68a41890fcc61e386a9566f /internal/compile/compile.go | |
parent | aeec83fba69eac2758484f82b32c86742979b014 (diff) | |
download | starlark-go-8160121a4f3bdd86c16f1772825b50eddcf04d72.tar.gz |
skylark: fix a crash in call f(*args, named=value) (#136)
* skylark: fix a crash in call f(*args, named=value)
Fixes #135
Diffstat (limited to 'internal/compile/compile.go')
-rw-r--r-- | internal/compile/compile.go | 41 |
1 files changed, 28 insertions, 13 deletions
diff --git a/internal/compile/compile.go b/internal/compile/compile.go index 9f153d9..47858c8 100644 --- a/internal/compile/compile.go +++ b/internal/compile/compile.go @@ -1502,11 +1502,14 @@ func (fcomp *fcomp) call(call *syntax.CallExpr) { func (fcomp *fcomp) args(call *syntax.CallExpr) (op Opcode, arg uint32) { var callmode int // Compute the number of each kind of parameter. - // TODO(adonovan): do this in resolver. var p, n int // number of positional, named arguments var varargs, kwargs syntax.Expr for _, arg := range call.Args { if binary, ok := arg.(*syntax.BinaryExpr); ok && binary.Op == syntax.EQ { + + // named argument (name, value) + fcomp.string(binary.X.(*syntax.Ident).Name) + fcomp.expr(binary.Y) n++ continue } @@ -1521,21 +1524,33 @@ func (fcomp *fcomp) args(call *syntax.CallExpr) (op Opcode, arg uint32) { continue } } - p++ - } - // positional arguments - for _, elem := range call.Args[:p] { - fcomp.expr(elem) + // positional argument + fcomp.expr(arg) + p++ } - // named argument pairs (name, value, ..., name, value) - named := call.Args[p : p+n] - for _, arg := range named { - binary := arg.(*syntax.BinaryExpr) - fcomp.string(binary.X.(*syntax.Ident).Name) - fcomp.expr(binary.Y) - } + // Python2, Python3, and Skylark-in-Java all permit named arguments + // to appear both before and after a *args argument: + // f(1, 2, x=3, *[4], y=5, **dict(z=6)) + // + // However all three implement different argument evaluation orders: + // Python2: 1 2 3 5 4 6 (*args and **kwargs evaluated last) + // Python3: 1 2 4 3 5 6 (positional args evaluated before named args) + // Skylark-in-Java: 1 2 3 4 5 6 (lexical order) + // + // The Skylark-in-Java semantics are clean but hostile to a + // compiler-based implementation because they require that the + // compiler emit code for positional, named, *args, more named, + // and *kwargs arguments and provide the callee with a map of + // the terrain. + // + // For now we implement the Python2 semantics, but + // the spec needs to clarify the correct approach. + // Perhaps it would be best if we statically rejected + // named arguments after *args (e.g. y=5) so that the + // Python2 implementation strategy matches lexical order. + // Discussion in github.com/bazelbuild/starlark#13. // *args if varargs != nil { |