1*4947cdc7SCole Faustpackage starlark 2*4947cdc7SCole Faust 3*4947cdc7SCole Faust// This file defines the Unpack helper functions used by 4*4947cdc7SCole Faust// built-in functions to interpret their call arguments. 5*4947cdc7SCole Faust 6*4947cdc7SCole Faustimport ( 7*4947cdc7SCole Faust "fmt" 8*4947cdc7SCole Faust "log" 9*4947cdc7SCole Faust "reflect" 10*4947cdc7SCole Faust "strings" 11*4947cdc7SCole Faust) 12*4947cdc7SCole Faust 13*4947cdc7SCole Faust// An Unpacker defines custom argument unpacking behavior. 14*4947cdc7SCole Faust// See UnpackArgs. 15*4947cdc7SCole Fausttype Unpacker interface { 16*4947cdc7SCole Faust Unpack(v Value) error 17*4947cdc7SCole Faust} 18*4947cdc7SCole Faust 19*4947cdc7SCole Faust// UnpackArgs unpacks the positional and keyword arguments into the 20*4947cdc7SCole Faust// supplied parameter variables. pairs is an alternating list of names 21*4947cdc7SCole Faust// and pointers to variables. 22*4947cdc7SCole Faust// 23*4947cdc7SCole Faust// If the variable is a bool, integer, string, *List, *Dict, Callable, 24*4947cdc7SCole Faust// Iterable, or user-defined implementation of Value, 25*4947cdc7SCole Faust// UnpackArgs performs the appropriate type check. 26*4947cdc7SCole Faust// Predeclared Go integer types uses the AsInt check. 27*4947cdc7SCole Faust// If the parameter name ends with "?", 28*4947cdc7SCole Faust// it and all following parameters are optional. 29*4947cdc7SCole Faust// 30*4947cdc7SCole Faust// If the variable implements Unpacker, its Unpack argument 31*4947cdc7SCole Faust// is called with the argument value, allowing an application 32*4947cdc7SCole Faust// to define its own argument validation and conversion. 33*4947cdc7SCole Faust// 34*4947cdc7SCole Faust// If the variable implements Value, UnpackArgs may call 35*4947cdc7SCole Faust// its Type() method while constructing the error message. 36*4947cdc7SCole Faust// 37*4947cdc7SCole Faust// Examples: 38*4947cdc7SCole Faust// 39*4947cdc7SCole Faust// var ( 40*4947cdc7SCole Faust// a Value 41*4947cdc7SCole Faust// b = MakeInt(42) 42*4947cdc7SCole Faust// c Value = starlark.None 43*4947cdc7SCole Faust// ) 44*4947cdc7SCole Faust// 45*4947cdc7SCole Faust// // 1. mixed parameters, like def f(a, b=42, c=None). 46*4947cdc7SCole Faust// err := UnpackArgs("f", args, kwargs, "a", &a, "b?", &b, "c?", &c) 47*4947cdc7SCole Faust// 48*4947cdc7SCole Faust// // 2. keyword parameters only, like def f(*, a, b, c=None). 49*4947cdc7SCole Faust// if len(args) > 0 { 50*4947cdc7SCole Faust// return fmt.Errorf("f: unexpected positional arguments") 51*4947cdc7SCole Faust// } 52*4947cdc7SCole Faust// err := UnpackArgs("f", args, kwargs, "a", &a, "b?", &b, "c?", &c) 53*4947cdc7SCole Faust// 54*4947cdc7SCole Faust// // 3. positional parameters only, like def f(a, b=42, c=None, /) in Python 3.8. 55*4947cdc7SCole Faust// err := UnpackPositionalArgs("f", args, kwargs, 1, &a, &b, &c) 56*4947cdc7SCole Faust// 57*4947cdc7SCole Faust// More complex forms such as def f(a, b=42, *args, c, d=123, **kwargs) 58*4947cdc7SCole Faust// require additional logic, but their need in built-ins is exceedingly rare. 59*4947cdc7SCole Faust// 60*4947cdc7SCole Faust// In the examples above, the declaration of b with type Int causes UnpackArgs 61*4947cdc7SCole Faust// to require that b's argument value, if provided, is also an int. 62*4947cdc7SCole Faust// To allow arguments of any type, while retaining the default value of 42, 63*4947cdc7SCole Faust// declare b as a Value: 64*4947cdc7SCole Faust// 65*4947cdc7SCole Faust// var b Value = MakeInt(42) 66*4947cdc7SCole Faust// 67*4947cdc7SCole Faust// The zero value of a variable of type Value, such as 'a' in the 68*4947cdc7SCole Faust// examples above, is not a valid Starlark value, so if the parameter is 69*4947cdc7SCole Faust// optional, the caller must explicitly handle the default case by 70*4947cdc7SCole Faust// interpreting nil as None or some computed default. The same is true 71*4947cdc7SCole Faust// for the zero values of variables of type *List, *Dict, Callable, or 72*4947cdc7SCole Faust// Iterable. For example: 73*4947cdc7SCole Faust// 74*4947cdc7SCole Faust// // def myfunc(d=None, e=[], f={}) 75*4947cdc7SCole Faust// var ( 76*4947cdc7SCole Faust// d Value 77*4947cdc7SCole Faust// e *List 78*4947cdc7SCole Faust// f *Dict 79*4947cdc7SCole Faust// ) 80*4947cdc7SCole Faust// err := UnpackArgs("myfunc", args, kwargs, "d?", &d, "e?", &e, "f?", &f) 81*4947cdc7SCole Faust// if d == nil { d = None; } 82*4947cdc7SCole Faust// if e == nil { e = new(List); } 83*4947cdc7SCole Faust// if f == nil { f = new(Dict); } 84*4947cdc7SCole Faust// 85*4947cdc7SCole Faustfunc UnpackArgs(fnname string, args Tuple, kwargs []Tuple, pairs ...interface{}) error { 86*4947cdc7SCole Faust nparams := len(pairs) / 2 87*4947cdc7SCole Faust var defined intset 88*4947cdc7SCole Faust defined.init(nparams) 89*4947cdc7SCole Faust 90*4947cdc7SCole Faust paramName := func(x interface{}) string { // (no free variables) 91*4947cdc7SCole Faust name := x.(string) 92*4947cdc7SCole Faust if name[len(name)-1] == '?' { 93*4947cdc7SCole Faust name = name[:len(name)-1] 94*4947cdc7SCole Faust } 95*4947cdc7SCole Faust return name 96*4947cdc7SCole Faust } 97*4947cdc7SCole Faust 98*4947cdc7SCole Faust // positional arguments 99*4947cdc7SCole Faust if len(args) > nparams { 100*4947cdc7SCole Faust return fmt.Errorf("%s: got %d arguments, want at most %d", 101*4947cdc7SCole Faust fnname, len(args), nparams) 102*4947cdc7SCole Faust } 103*4947cdc7SCole Faust for i, arg := range args { 104*4947cdc7SCole Faust defined.set(i) 105*4947cdc7SCole Faust if err := unpackOneArg(arg, pairs[2*i+1]); err != nil { 106*4947cdc7SCole Faust name := paramName(pairs[2*i]) 107*4947cdc7SCole Faust return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err) 108*4947cdc7SCole Faust } 109*4947cdc7SCole Faust } 110*4947cdc7SCole Faust 111*4947cdc7SCole Faust // keyword arguments 112*4947cdc7SCole Faustkwloop: 113*4947cdc7SCole Faust for _, item := range kwargs { 114*4947cdc7SCole Faust name, arg := item[0].(String), item[1] 115*4947cdc7SCole Faust for i := 0; i < nparams; i++ { 116*4947cdc7SCole Faust if paramName(pairs[2*i]) == string(name) { 117*4947cdc7SCole Faust // found it 118*4947cdc7SCole Faust if defined.set(i) { 119*4947cdc7SCole Faust return fmt.Errorf("%s: got multiple values for keyword argument %s", 120*4947cdc7SCole Faust fnname, name) 121*4947cdc7SCole Faust } 122*4947cdc7SCole Faust ptr := pairs[2*i+1] 123*4947cdc7SCole Faust if err := unpackOneArg(arg, ptr); err != nil { 124*4947cdc7SCole Faust return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err) 125*4947cdc7SCole Faust } 126*4947cdc7SCole Faust continue kwloop 127*4947cdc7SCole Faust } 128*4947cdc7SCole Faust } 129*4947cdc7SCole Faust return fmt.Errorf("%s: unexpected keyword argument %s", fnname, name) 130*4947cdc7SCole Faust } 131*4947cdc7SCole Faust 132*4947cdc7SCole Faust // Check that all non-optional parameters are defined. 133*4947cdc7SCole Faust // (We needn't check the first len(args).) 134*4947cdc7SCole Faust for i := len(args); i < nparams; i++ { 135*4947cdc7SCole Faust name := pairs[2*i].(string) 136*4947cdc7SCole Faust if strings.HasSuffix(name, "?") { 137*4947cdc7SCole Faust break // optional 138*4947cdc7SCole Faust } 139*4947cdc7SCole Faust if !defined.get(i) { 140*4947cdc7SCole Faust return fmt.Errorf("%s: missing argument for %s", fnname, name) 141*4947cdc7SCole Faust } 142*4947cdc7SCole Faust } 143*4947cdc7SCole Faust 144*4947cdc7SCole Faust return nil 145*4947cdc7SCole Faust} 146*4947cdc7SCole Faust 147*4947cdc7SCole Faust// UnpackPositionalArgs unpacks the positional arguments into 148*4947cdc7SCole Faust// corresponding variables. Each element of vars is a pointer; see 149*4947cdc7SCole Faust// UnpackArgs for allowed types and conversions. 150*4947cdc7SCole Faust// 151*4947cdc7SCole Faust// UnpackPositionalArgs reports an error if the number of arguments is 152*4947cdc7SCole Faust// less than min or greater than len(vars), if kwargs is nonempty, or if 153*4947cdc7SCole Faust// any conversion fails. 154*4947cdc7SCole Faust// 155*4947cdc7SCole Faust// See UnpackArgs for general comments. 156*4947cdc7SCole Faustfunc UnpackPositionalArgs(fnname string, args Tuple, kwargs []Tuple, min int, vars ...interface{}) error { 157*4947cdc7SCole Faust if len(kwargs) > 0 { 158*4947cdc7SCole Faust return fmt.Errorf("%s: unexpected keyword arguments", fnname) 159*4947cdc7SCole Faust } 160*4947cdc7SCole Faust max := len(vars) 161*4947cdc7SCole Faust if len(args) < min { 162*4947cdc7SCole Faust var atleast string 163*4947cdc7SCole Faust if min < max { 164*4947cdc7SCole Faust atleast = "at least " 165*4947cdc7SCole Faust } 166*4947cdc7SCole Faust return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atleast, min) 167*4947cdc7SCole Faust } 168*4947cdc7SCole Faust if len(args) > max { 169*4947cdc7SCole Faust var atmost string 170*4947cdc7SCole Faust if max > min { 171*4947cdc7SCole Faust atmost = "at most " 172*4947cdc7SCole Faust } 173*4947cdc7SCole Faust return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atmost, max) 174*4947cdc7SCole Faust } 175*4947cdc7SCole Faust for i, arg := range args { 176*4947cdc7SCole Faust if err := unpackOneArg(arg, vars[i]); err != nil { 177*4947cdc7SCole Faust return fmt.Errorf("%s: for parameter %d: %s", fnname, i+1, err) 178*4947cdc7SCole Faust } 179*4947cdc7SCole Faust } 180*4947cdc7SCole Faust return nil 181*4947cdc7SCole Faust} 182*4947cdc7SCole Faust 183*4947cdc7SCole Faustfunc unpackOneArg(v Value, ptr interface{}) error { 184*4947cdc7SCole Faust // On failure, don't clobber *ptr. 185*4947cdc7SCole Faust switch ptr := ptr.(type) { 186*4947cdc7SCole Faust case Unpacker: 187*4947cdc7SCole Faust return ptr.Unpack(v) 188*4947cdc7SCole Faust case *Value: 189*4947cdc7SCole Faust *ptr = v 190*4947cdc7SCole Faust case *string: 191*4947cdc7SCole Faust s, ok := AsString(v) 192*4947cdc7SCole Faust if !ok { 193*4947cdc7SCole Faust return fmt.Errorf("got %s, want string", v.Type()) 194*4947cdc7SCole Faust } 195*4947cdc7SCole Faust *ptr = s 196*4947cdc7SCole Faust case *bool: 197*4947cdc7SCole Faust b, ok := v.(Bool) 198*4947cdc7SCole Faust if !ok { 199*4947cdc7SCole Faust return fmt.Errorf("got %s, want bool", v.Type()) 200*4947cdc7SCole Faust } 201*4947cdc7SCole Faust *ptr = bool(b) 202*4947cdc7SCole Faust case *int, *int8, *int16, *int32, *int64, 203*4947cdc7SCole Faust *uint, *uint8, *uint16, *uint32, *uint64, *uintptr: 204*4947cdc7SCole Faust return AsInt(v, ptr) 205*4947cdc7SCole Faust case *float64: 206*4947cdc7SCole Faust f, ok := v.(Float) 207*4947cdc7SCole Faust if !ok { 208*4947cdc7SCole Faust return fmt.Errorf("got %s, want float", v.Type()) 209*4947cdc7SCole Faust } 210*4947cdc7SCole Faust *ptr = float64(f) 211*4947cdc7SCole Faust case **List: 212*4947cdc7SCole Faust list, ok := v.(*List) 213*4947cdc7SCole Faust if !ok { 214*4947cdc7SCole Faust return fmt.Errorf("got %s, want list", v.Type()) 215*4947cdc7SCole Faust } 216*4947cdc7SCole Faust *ptr = list 217*4947cdc7SCole Faust case **Dict: 218*4947cdc7SCole Faust dict, ok := v.(*Dict) 219*4947cdc7SCole Faust if !ok { 220*4947cdc7SCole Faust return fmt.Errorf("got %s, want dict", v.Type()) 221*4947cdc7SCole Faust } 222*4947cdc7SCole Faust *ptr = dict 223*4947cdc7SCole Faust case *Callable: 224*4947cdc7SCole Faust f, ok := v.(Callable) 225*4947cdc7SCole Faust if !ok { 226*4947cdc7SCole Faust return fmt.Errorf("got %s, want callable", v.Type()) 227*4947cdc7SCole Faust } 228*4947cdc7SCole Faust *ptr = f 229*4947cdc7SCole Faust case *Iterable: 230*4947cdc7SCole Faust it, ok := v.(Iterable) 231*4947cdc7SCole Faust if !ok { 232*4947cdc7SCole Faust return fmt.Errorf("got %s, want iterable", v.Type()) 233*4947cdc7SCole Faust } 234*4947cdc7SCole Faust *ptr = it 235*4947cdc7SCole Faust default: 236*4947cdc7SCole Faust // v must have type *V, where V is some subtype of starlark.Value. 237*4947cdc7SCole Faust ptrv := reflect.ValueOf(ptr) 238*4947cdc7SCole Faust if ptrv.Kind() != reflect.Ptr { 239*4947cdc7SCole Faust log.Panicf("internal error: not a pointer: %T", ptr) 240*4947cdc7SCole Faust } 241*4947cdc7SCole Faust paramVar := ptrv.Elem() 242*4947cdc7SCole Faust if !reflect.TypeOf(v).AssignableTo(paramVar.Type()) { 243*4947cdc7SCole Faust // The value is not assignable to the variable. 244*4947cdc7SCole Faust 245*4947cdc7SCole Faust // Detect a possible bug in the Go program that called Unpack: 246*4947cdc7SCole Faust // If the variable *ptr is not a subtype of Value, 247*4947cdc7SCole Faust // no value of v can possibly work. 248*4947cdc7SCole Faust if !paramVar.Type().AssignableTo(reflect.TypeOf(new(Value)).Elem()) { 249*4947cdc7SCole Faust log.Panicf("pointer element type does not implement Value: %T", ptr) 250*4947cdc7SCole Faust } 251*4947cdc7SCole Faust 252*4947cdc7SCole Faust // Report Starlark dynamic type error. 253*4947cdc7SCole Faust // 254*4947cdc7SCole Faust // We prefer the Starlark Value.Type name over 255*4947cdc7SCole Faust // its Go reflect.Type name, but calling the 256*4947cdc7SCole Faust // Value.Type method on the variable is not safe 257*4947cdc7SCole Faust // in general. If the variable is an interface, 258*4947cdc7SCole Faust // the call will fail. Even if the variable has 259*4947cdc7SCole Faust // a concrete type, it might not be safe to call 260*4947cdc7SCole Faust // Type() on a zero instance. Thus we must use 261*4947cdc7SCole Faust // recover. 262*4947cdc7SCole Faust 263*4947cdc7SCole Faust // Default to Go reflect.Type name 264*4947cdc7SCole Faust paramType := paramVar.Type().String() 265*4947cdc7SCole Faust 266*4947cdc7SCole Faust // Attempt to call Value.Type method. 267*4947cdc7SCole Faust func() { 268*4947cdc7SCole Faust defer func() { recover() }() 269*4947cdc7SCole Faust paramType = paramVar.MethodByName("Type").Call(nil)[0].String() 270*4947cdc7SCole Faust }() 271*4947cdc7SCole Faust return fmt.Errorf("got %s, want %s", v.Type(), paramType) 272*4947cdc7SCole Faust } 273*4947cdc7SCole Faust paramVar.Set(reflect.ValueOf(v)) 274*4947cdc7SCole Faust } 275*4947cdc7SCole Faust return nil 276*4947cdc7SCole Faust} 277*4947cdc7SCole Faust 278*4947cdc7SCole Fausttype intset struct { 279*4947cdc7SCole Faust small uint64 // bitset, used if n < 64 280*4947cdc7SCole Faust large map[int]bool // set, used if n >= 64 281*4947cdc7SCole Faust} 282*4947cdc7SCole Faust 283*4947cdc7SCole Faustfunc (is *intset) init(n int) { 284*4947cdc7SCole Faust if n >= 64 { 285*4947cdc7SCole Faust is.large = make(map[int]bool) 286*4947cdc7SCole Faust } 287*4947cdc7SCole Faust} 288*4947cdc7SCole Faust 289*4947cdc7SCole Faustfunc (is *intset) set(i int) (prev bool) { 290*4947cdc7SCole Faust if is.large == nil { 291*4947cdc7SCole Faust prev = is.small&(1<<uint(i)) != 0 292*4947cdc7SCole Faust is.small |= 1 << uint(i) 293*4947cdc7SCole Faust } else { 294*4947cdc7SCole Faust prev = is.large[i] 295*4947cdc7SCole Faust is.large[i] = true 296*4947cdc7SCole Faust } 297*4947cdc7SCole Faust return 298*4947cdc7SCole Faust} 299*4947cdc7SCole Faust 300*4947cdc7SCole Faustfunc (is *intset) get(i int) bool { 301*4947cdc7SCole Faust if is.large == nil { 302*4947cdc7SCole Faust return is.small&(1<<uint(i)) != 0 303*4947cdc7SCole Faust } 304*4947cdc7SCole Faust return is.large[i] 305*4947cdc7SCole Faust} 306*4947cdc7SCole Faust 307*4947cdc7SCole Faustfunc (is *intset) len() int { 308*4947cdc7SCole Faust if is.large == nil { 309*4947cdc7SCole Faust // Suboptimal, but used only for error reporting. 310*4947cdc7SCole Faust len := 0 311*4947cdc7SCole Faust for i := 0; i < 64; i++ { 312*4947cdc7SCole Faust if is.small&(1<<uint(i)) != 0 { 313*4947cdc7SCole Faust len++ 314*4947cdc7SCole Faust } 315*4947cdc7SCole Faust } 316*4947cdc7SCole Faust return len 317*4947cdc7SCole Faust } 318*4947cdc7SCole Faust return len(is.large) 319*4947cdc7SCole Faust} 320