aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorAlan Donovan <alan@alandonovan.net>2019-02-13 19:18:15 -0500
committeralandonovan <adonovan@google.com>2019-02-13 19:18:15 -0500
commit52153852d546514d9bf61e444fe5d829f3835476 (patch)
treea015da6c381e6aa3f44ad7487e25ab7f1356736d /internal
parent266cd6fde1b6d00f056929eb7d04fee53640b3e6 (diff)
downloadstarlark-go-52153852d546514d9bf61e444fe5d829f3835476.tar.gz
Support keyword-only function parameters (#143)
Following a hitherto undocumented feature of Skylark-in-Java, which in turn follows Python3, a function declaration may now include optional parameters after the *args parameter: ``` def f(a, b, c=1, *args, d=2, **kwargs) ``` The parameter d is a "keyword-only" parameter as it can never by assigned from a positional parameter; all positional arguments surplus to a, b, and c are put in a tuple and assigned to args. To declare a non-variadic function with keyword-only arguments, the *args parameter is replaced by just *: ``` def f(a, b, c=1, *, d=2, **kwargs) ``` The * parameter is not a real parameter; it just serves as a separator between the parameter that may be specified positionally and the keyword-only ones. Spec proposal at bazelbuild/starlark#23 Fixes #61
Diffstat (limited to 'internal')
-rw-r--r--internal/compile/compile.go14
-rw-r--r--internal/compile/serial.go26
2 files changed, 26 insertions, 14 deletions
diff --git a/internal/compile/compile.go b/internal/compile/compile.go
index 6b43fbe..b313a5c 100644
--- a/internal/compile/compile.go
+++ b/internal/compile/compile.go
@@ -37,7 +37,7 @@ import (
const debug = false // TODO(adonovan): use a bitmap of options; and regexp to match files
// Increment this to force recompilation of saved bytecode files.
-const Version = 5
+const Version = 6
type Opcode uint8
@@ -305,10 +305,11 @@ type Funcode struct {
Doc string // docstring of this function
Code []byte // the byte code
pclinetab []uint16 // mapping from pc to linenum
- Locals []Ident // for error messages and tracing
+ Locals []Ident // locals, parameters first
Freevars []Ident // for tracing
MaxStack int
NumParams int
+ NumKwonlyParams int
HasVarargs, HasKwargs bool
}
@@ -1705,7 +1706,14 @@ func (fcomp *fcomp) function(pos syntax.Position, name string, f *syntax.Functio
fmt.Fprintf(os.Stderr, "resuming %s @ %s\n", fcomp.fn.Name, fcomp.pos)
}
- funcode.NumParams = len(f.Params)
+ // def f(a, *, b=1) has only 2 parameters.
+ numParams := len(f.Params)
+ if f.NumKwonlyParams > 0 && !f.HasVarargs {
+ numParams--
+ }
+
+ funcode.NumParams = numParams
+ funcode.NumKwonlyParams = f.NumKwonlyParams
funcode.HasVarargs = f.HasVarargs
funcode.HasKwargs = f.HasKwargs
fcomp.emit1(MAKEFUNC, fcomp.pcomp.functionIndex(funcode))
diff --git a/internal/compile/serial.go b/internal/compile/serial.go
index f6cf807..6056ea7 100644
--- a/internal/compile/serial.go
+++ b/internal/compile/serial.go
@@ -39,6 +39,7 @@ package compile
// freevar []Ident
// maxstack varint
// numparams varint
+// numkwonlyparams varint
// hasvarargs varint (0 or 1)
// haskwargs varint (0 or 1)
//
@@ -185,6 +186,7 @@ func (e *encoder) function(fn *Funcode) {
e.idents(fn.Freevars)
e.int(fn.MaxStack)
e.int(fn.NumParams)
+ e.int(fn.NumKwonlyParams)
e.int(b2i(fn.HasVarargs))
e.int(b2i(fn.HasKwargs))
}
@@ -350,20 +352,22 @@ func (d *decoder) function() *Funcode {
freevars := d.idents()
maxStack := d.int()
numParams := d.int()
+ numKwonlyParams := d.int()
hasVarargs := d.int() != 0
hasKwargs := d.int() != 0
return &Funcode{
// Prog is filled in later.
- Pos: id.Pos,
- Name: id.Name,
- Doc: doc,
- Code: code,
- pclinetab: pclinetab,
- Locals: locals,
- Freevars: freevars,
- MaxStack: maxStack,
- NumParams: numParams,
- HasVarargs: hasVarargs,
- HasKwargs: hasKwargs,
+ Pos: id.Pos,
+ Name: id.Name,
+ Doc: doc,
+ Code: code,
+ pclinetab: pclinetab,
+ Locals: locals,
+ Freevars: freevars,
+ MaxStack: maxStack,
+ NumParams: numParams,
+ NumKwonlyParams: numKwonlyParams,
+ HasVarargs: hasVarargs,
+ HasKwargs: hasKwargs,
}
}