in starlark/unpack.go [93:179]
func UnpackArgs(fnname string, args Tuple, kwargs []Tuple, pairs ...interface{}) error {
nparams := len(pairs) / 2
var defined intset
defined.init(nparams)
paramName := func(x interface{}) (name string, skipNone bool) { // (no free variables)
name = x.(string)
if strings.HasSuffix(name, "??") {
name = strings.TrimSuffix(name, "??")
skipNone = true
} else if name[len(name)-1] == '?' {
name = name[:len(name)-1]
}
return name, skipNone
}
// positional arguments
if len(args) > nparams {
return fmt.Errorf("%s: got %d arguments, want at most %d",
fnname, len(args), nparams)
}
for i, arg := range args {
defined.set(i)
name, skipNone := paramName(pairs[2*i])
if skipNone {
if _, isNone := arg.(NoneType); isNone {
continue
}
}
if err := unpackOneArg(arg, pairs[2*i+1]); err != nil {
return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err)
}
}
// keyword arguments
kwloop:
for _, item := range kwargs {
name, arg := item[0].(String), item[1]
for i := 0; i < nparams; i++ {
pName, skipNone := paramName(pairs[2*i])
if pName == string(name) {
// found it
if defined.set(i) {
return fmt.Errorf("%s: got multiple values for keyword argument %s",
fnname, name)
}
if skipNone {
if _, isNone := arg.(NoneType); isNone {
continue kwloop
}
}
ptr := pairs[2*i+1]
if err := unpackOneArg(arg, ptr); err != nil {
return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err)
}
continue kwloop
}
}
err := fmt.Errorf("%s: unexpected keyword argument %s", fnname, name)
names := make([]string, 0, nparams)
for i := 0; i < nparams; i += 2 {
param, _ := paramName(pairs[i])
names = append(names, param)
}
if n := spell.Nearest(string(name), names); n != "" {
err = fmt.Errorf("%s (did you mean %s?)", err.Error(), n)
}
return err
}
// Check that all non-optional parameters are defined.
// (We needn't check the first len(args).)
for i := len(args); i < nparams; i++ {
name := pairs[2*i].(string)
if strings.HasSuffix(name, "?") {
break // optional
}
if !defined.get(i) {
return fmt.Errorf("%s: missing argument for %s", fnname, name)
}
}
return nil
}