1*4947cdc7SCole Faustpackage starlark 2*4947cdc7SCole Faust 3*4947cdc7SCole Faust// This file defines the bytecode interpreter. 4*4947cdc7SCole Faust 5*4947cdc7SCole Faustimport ( 6*4947cdc7SCole Faust "fmt" 7*4947cdc7SCole Faust "os" 8*4947cdc7SCole Faust "sync/atomic" 9*4947cdc7SCole Faust "unsafe" 10*4947cdc7SCole Faust 11*4947cdc7SCole Faust "go.starlark.net/internal/compile" 12*4947cdc7SCole Faust "go.starlark.net/internal/spell" 13*4947cdc7SCole Faust "go.starlark.net/resolve" 14*4947cdc7SCole Faust "go.starlark.net/syntax" 15*4947cdc7SCole Faust) 16*4947cdc7SCole Faust 17*4947cdc7SCole Faustconst vmdebug = false // TODO(adonovan): use a bitfield of specific kinds of error. 18*4947cdc7SCole Faust 19*4947cdc7SCole Faust// TODO(adonovan): 20*4947cdc7SCole Faust// - optimize position table. 21*4947cdc7SCole Faust// - opt: record MaxIterStack during compilation and preallocate the stack. 22*4947cdc7SCole Faust 23*4947cdc7SCole Faustfunc (fn *Function) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) { 24*4947cdc7SCole Faust // Postcondition: args is not mutated. This is stricter than required by Callable, 25*4947cdc7SCole Faust // but allows CALL to avoid a copy. 26*4947cdc7SCole Faust 27*4947cdc7SCole Faust if !resolve.AllowRecursion { 28*4947cdc7SCole Faust // detect recursion 29*4947cdc7SCole Faust for _, fr := range thread.stack[:len(thread.stack)-1] { 30*4947cdc7SCole Faust // We look for the same function code, 31*4947cdc7SCole Faust // not function value, otherwise the user could 32*4947cdc7SCole Faust // defeat the check by writing the Y combinator. 33*4947cdc7SCole Faust if frfn, ok := fr.Callable().(*Function); ok && frfn.funcode == fn.funcode { 34*4947cdc7SCole Faust return nil, fmt.Errorf("function %s called recursively", fn.Name()) 35*4947cdc7SCole Faust } 36*4947cdc7SCole Faust } 37*4947cdc7SCole Faust } 38*4947cdc7SCole Faust 39*4947cdc7SCole Faust f := fn.funcode 40*4947cdc7SCole Faust fr := thread.frameAt(0) 41*4947cdc7SCole Faust 42*4947cdc7SCole Faust // Allocate space for stack and locals. 43*4947cdc7SCole Faust // Logically these do not escape from this frame 44*4947cdc7SCole Faust // (See https://github.com/golang/go/issues/20533.) 45*4947cdc7SCole Faust // 46*4947cdc7SCole Faust // This heap allocation looks expensive, but I was unable to get 47*4947cdc7SCole Faust // more than 1% real time improvement in a large alloc-heavy 48*4947cdc7SCole Faust // benchmark (in which this alloc was 8% of alloc-bytes) 49*4947cdc7SCole Faust // by allocating space for 8 Values in each frame, or 50*4947cdc7SCole Faust // by allocating stack by slicing an array held by the Thread 51*4947cdc7SCole Faust // that is expanded in chunks of min(k, nspace), for k=256 or 1024. 52*4947cdc7SCole Faust nlocals := len(f.Locals) 53*4947cdc7SCole Faust nspace := nlocals + f.MaxStack 54*4947cdc7SCole Faust space := make([]Value, nspace) 55*4947cdc7SCole Faust locals := space[:nlocals:nlocals] // local variables, starting with parameters 56*4947cdc7SCole Faust stack := space[nlocals:] // operand stack 57*4947cdc7SCole Faust 58*4947cdc7SCole Faust // Digest arguments and set parameters. 59*4947cdc7SCole Faust err := setArgs(locals, fn, args, kwargs) 60*4947cdc7SCole Faust if err != nil { 61*4947cdc7SCole Faust return nil, thread.evalError(err) 62*4947cdc7SCole Faust } 63*4947cdc7SCole Faust 64*4947cdc7SCole Faust fr.locals = locals 65*4947cdc7SCole Faust 66*4947cdc7SCole Faust if vmdebug { 67*4947cdc7SCole Faust fmt.Printf("Entering %s @ %s\n", f.Name, f.Position(0)) 68*4947cdc7SCole Faust fmt.Printf("%d stack, %d locals\n", len(stack), len(locals)) 69*4947cdc7SCole Faust defer fmt.Println("Leaving ", f.Name) 70*4947cdc7SCole Faust } 71*4947cdc7SCole Faust 72*4947cdc7SCole Faust // Spill indicated locals to cells. 73*4947cdc7SCole Faust // Each cell is a separate alloc to avoid spurious liveness. 74*4947cdc7SCole Faust for _, index := range f.Cells { 75*4947cdc7SCole Faust locals[index] = &cell{locals[index]} 76*4947cdc7SCole Faust } 77*4947cdc7SCole Faust 78*4947cdc7SCole Faust // TODO(adonovan): add static check that beneath this point 79*4947cdc7SCole Faust // - there is exactly one return statement 80*4947cdc7SCole Faust // - there is no redefinition of 'err'. 81*4947cdc7SCole Faust 82*4947cdc7SCole Faust var iterstack []Iterator // stack of active iterators 83*4947cdc7SCole Faust 84*4947cdc7SCole Faust sp := 0 85*4947cdc7SCole Faust var pc uint32 86*4947cdc7SCole Faust var result Value 87*4947cdc7SCole Faust code := f.Code 88*4947cdc7SCole Faustloop: 89*4947cdc7SCole Faust for { 90*4947cdc7SCole Faust thread.steps++ 91*4947cdc7SCole Faust if thread.steps >= thread.maxSteps { 92*4947cdc7SCole Faust thread.Cancel("too many steps") 93*4947cdc7SCole Faust } 94*4947cdc7SCole Faust if reason := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&thread.cancelReason))); reason != nil { 95*4947cdc7SCole Faust err = fmt.Errorf("Starlark computation cancelled: %s", *(*string)(reason)) 96*4947cdc7SCole Faust break loop 97*4947cdc7SCole Faust } 98*4947cdc7SCole Faust 99*4947cdc7SCole Faust fr.pc = pc 100*4947cdc7SCole Faust 101*4947cdc7SCole Faust op := compile.Opcode(code[pc]) 102*4947cdc7SCole Faust pc++ 103*4947cdc7SCole Faust var arg uint32 104*4947cdc7SCole Faust if op >= compile.OpcodeArgMin { 105*4947cdc7SCole Faust // TODO(adonovan): opt: profile this. 106*4947cdc7SCole Faust // Perhaps compiling big endian would be less work to decode? 107*4947cdc7SCole Faust for s := uint(0); ; s += 7 { 108*4947cdc7SCole Faust b := code[pc] 109*4947cdc7SCole Faust pc++ 110*4947cdc7SCole Faust arg |= uint32(b&0x7f) << s 111*4947cdc7SCole Faust if b < 0x80 { 112*4947cdc7SCole Faust break 113*4947cdc7SCole Faust } 114*4947cdc7SCole Faust } 115*4947cdc7SCole Faust } 116*4947cdc7SCole Faust if vmdebug { 117*4947cdc7SCole Faust fmt.Fprintln(os.Stderr, stack[:sp]) // very verbose! 118*4947cdc7SCole Faust compile.PrintOp(f, fr.pc, op, arg) 119*4947cdc7SCole Faust } 120*4947cdc7SCole Faust 121*4947cdc7SCole Faust switch op { 122*4947cdc7SCole Faust case compile.NOP: 123*4947cdc7SCole Faust // nop 124*4947cdc7SCole Faust 125*4947cdc7SCole Faust case compile.DUP: 126*4947cdc7SCole Faust stack[sp] = stack[sp-1] 127*4947cdc7SCole Faust sp++ 128*4947cdc7SCole Faust 129*4947cdc7SCole Faust case compile.DUP2: 130*4947cdc7SCole Faust stack[sp] = stack[sp-2] 131*4947cdc7SCole Faust stack[sp+1] = stack[sp-1] 132*4947cdc7SCole Faust sp += 2 133*4947cdc7SCole Faust 134*4947cdc7SCole Faust case compile.POP: 135*4947cdc7SCole Faust sp-- 136*4947cdc7SCole Faust 137*4947cdc7SCole Faust case compile.EXCH: 138*4947cdc7SCole Faust stack[sp-2], stack[sp-1] = stack[sp-1], stack[sp-2] 139*4947cdc7SCole Faust 140*4947cdc7SCole Faust case compile.EQL, compile.NEQ, compile.GT, compile.LT, compile.LE, compile.GE: 141*4947cdc7SCole Faust op := syntax.Token(op-compile.EQL) + syntax.EQL 142*4947cdc7SCole Faust y := stack[sp-1] 143*4947cdc7SCole Faust x := stack[sp-2] 144*4947cdc7SCole Faust sp -= 2 145*4947cdc7SCole Faust ok, err2 := Compare(op, x, y) 146*4947cdc7SCole Faust if err2 != nil { 147*4947cdc7SCole Faust err = err2 148*4947cdc7SCole Faust break loop 149*4947cdc7SCole Faust } 150*4947cdc7SCole Faust stack[sp] = Bool(ok) 151*4947cdc7SCole Faust sp++ 152*4947cdc7SCole Faust 153*4947cdc7SCole Faust case compile.PLUS, 154*4947cdc7SCole Faust compile.MINUS, 155*4947cdc7SCole Faust compile.STAR, 156*4947cdc7SCole Faust compile.SLASH, 157*4947cdc7SCole Faust compile.SLASHSLASH, 158*4947cdc7SCole Faust compile.PERCENT, 159*4947cdc7SCole Faust compile.AMP, 160*4947cdc7SCole Faust compile.PIPE, 161*4947cdc7SCole Faust compile.CIRCUMFLEX, 162*4947cdc7SCole Faust compile.LTLT, 163*4947cdc7SCole Faust compile.GTGT, 164*4947cdc7SCole Faust compile.IN: 165*4947cdc7SCole Faust binop := syntax.Token(op-compile.PLUS) + syntax.PLUS 166*4947cdc7SCole Faust if op == compile.IN { 167*4947cdc7SCole Faust binop = syntax.IN // IN token is out of order 168*4947cdc7SCole Faust } 169*4947cdc7SCole Faust y := stack[sp-1] 170*4947cdc7SCole Faust x := stack[sp-2] 171*4947cdc7SCole Faust sp -= 2 172*4947cdc7SCole Faust z, err2 := Binary(binop, x, y) 173*4947cdc7SCole Faust if err2 != nil { 174*4947cdc7SCole Faust err = err2 175*4947cdc7SCole Faust break loop 176*4947cdc7SCole Faust } 177*4947cdc7SCole Faust stack[sp] = z 178*4947cdc7SCole Faust sp++ 179*4947cdc7SCole Faust 180*4947cdc7SCole Faust case compile.UPLUS, compile.UMINUS, compile.TILDE: 181*4947cdc7SCole Faust var unop syntax.Token 182*4947cdc7SCole Faust if op == compile.TILDE { 183*4947cdc7SCole Faust unop = syntax.TILDE 184*4947cdc7SCole Faust } else { 185*4947cdc7SCole Faust unop = syntax.Token(op-compile.UPLUS) + syntax.PLUS 186*4947cdc7SCole Faust } 187*4947cdc7SCole Faust x := stack[sp-1] 188*4947cdc7SCole Faust y, err2 := Unary(unop, x) 189*4947cdc7SCole Faust if err2 != nil { 190*4947cdc7SCole Faust err = err2 191*4947cdc7SCole Faust break loop 192*4947cdc7SCole Faust } 193*4947cdc7SCole Faust stack[sp-1] = y 194*4947cdc7SCole Faust 195*4947cdc7SCole Faust case compile.INPLACE_ADD: 196*4947cdc7SCole Faust y := stack[sp-1] 197*4947cdc7SCole Faust x := stack[sp-2] 198*4947cdc7SCole Faust sp -= 2 199*4947cdc7SCole Faust 200*4947cdc7SCole Faust // It's possible that y is not Iterable but 201*4947cdc7SCole Faust // nonetheless defines x+y, in which case we 202*4947cdc7SCole Faust // should fall back to the general case. 203*4947cdc7SCole Faust var z Value 204*4947cdc7SCole Faust if xlist, ok := x.(*List); ok { 205*4947cdc7SCole Faust if yiter, ok := y.(Iterable); ok { 206*4947cdc7SCole Faust if err = xlist.checkMutable("apply += to"); err != nil { 207*4947cdc7SCole Faust break loop 208*4947cdc7SCole Faust } 209*4947cdc7SCole Faust listExtend(xlist, yiter) 210*4947cdc7SCole Faust z = xlist 211*4947cdc7SCole Faust } 212*4947cdc7SCole Faust } 213*4947cdc7SCole Faust if z == nil { 214*4947cdc7SCole Faust z, err = Binary(syntax.PLUS, x, y) 215*4947cdc7SCole Faust if err != nil { 216*4947cdc7SCole Faust break loop 217*4947cdc7SCole Faust } 218*4947cdc7SCole Faust } 219*4947cdc7SCole Faust 220*4947cdc7SCole Faust stack[sp] = z 221*4947cdc7SCole Faust sp++ 222*4947cdc7SCole Faust 223*4947cdc7SCole Faust case compile.NONE: 224*4947cdc7SCole Faust stack[sp] = None 225*4947cdc7SCole Faust sp++ 226*4947cdc7SCole Faust 227*4947cdc7SCole Faust case compile.TRUE: 228*4947cdc7SCole Faust stack[sp] = True 229*4947cdc7SCole Faust sp++ 230*4947cdc7SCole Faust 231*4947cdc7SCole Faust case compile.FALSE: 232*4947cdc7SCole Faust stack[sp] = False 233*4947cdc7SCole Faust sp++ 234*4947cdc7SCole Faust 235*4947cdc7SCole Faust case compile.MANDATORY: 236*4947cdc7SCole Faust stack[sp] = mandatory{} 237*4947cdc7SCole Faust sp++ 238*4947cdc7SCole Faust 239*4947cdc7SCole Faust case compile.JMP: 240*4947cdc7SCole Faust pc = arg 241*4947cdc7SCole Faust 242*4947cdc7SCole Faust case compile.CALL, compile.CALL_VAR, compile.CALL_KW, compile.CALL_VAR_KW: 243*4947cdc7SCole Faust var kwargs Value 244*4947cdc7SCole Faust if op == compile.CALL_KW || op == compile.CALL_VAR_KW { 245*4947cdc7SCole Faust kwargs = stack[sp-1] 246*4947cdc7SCole Faust sp-- 247*4947cdc7SCole Faust } 248*4947cdc7SCole Faust 249*4947cdc7SCole Faust var args Value 250*4947cdc7SCole Faust if op == compile.CALL_VAR || op == compile.CALL_VAR_KW { 251*4947cdc7SCole Faust args = stack[sp-1] 252*4947cdc7SCole Faust sp-- 253*4947cdc7SCole Faust } 254*4947cdc7SCole Faust 255*4947cdc7SCole Faust // named args (pairs) 256*4947cdc7SCole Faust var kvpairs []Tuple 257*4947cdc7SCole Faust if nkvpairs := int(arg & 0xff); nkvpairs > 0 { 258*4947cdc7SCole Faust kvpairs = make([]Tuple, 0, nkvpairs) 259*4947cdc7SCole Faust kvpairsAlloc := make(Tuple, 2*nkvpairs) // allocate a single backing array 260*4947cdc7SCole Faust sp -= 2 * nkvpairs 261*4947cdc7SCole Faust for i := 0; i < nkvpairs; i++ { 262*4947cdc7SCole Faust pair := kvpairsAlloc[:2:2] 263*4947cdc7SCole Faust kvpairsAlloc = kvpairsAlloc[2:] 264*4947cdc7SCole Faust pair[0] = stack[sp+2*i] // name 265*4947cdc7SCole Faust pair[1] = stack[sp+2*i+1] // value 266*4947cdc7SCole Faust kvpairs = append(kvpairs, pair) 267*4947cdc7SCole Faust } 268*4947cdc7SCole Faust } 269*4947cdc7SCole Faust if kwargs != nil { 270*4947cdc7SCole Faust // Add key/value items from **kwargs dictionary. 271*4947cdc7SCole Faust dict, ok := kwargs.(IterableMapping) 272*4947cdc7SCole Faust if !ok { 273*4947cdc7SCole Faust err = fmt.Errorf("argument after ** must be a mapping, not %s", kwargs.Type()) 274*4947cdc7SCole Faust break loop 275*4947cdc7SCole Faust } 276*4947cdc7SCole Faust items := dict.Items() 277*4947cdc7SCole Faust for _, item := range items { 278*4947cdc7SCole Faust if _, ok := item[0].(String); !ok { 279*4947cdc7SCole Faust err = fmt.Errorf("keywords must be strings, not %s", item[0].Type()) 280*4947cdc7SCole Faust break loop 281*4947cdc7SCole Faust } 282*4947cdc7SCole Faust } 283*4947cdc7SCole Faust if len(kvpairs) == 0 { 284*4947cdc7SCole Faust kvpairs = items 285*4947cdc7SCole Faust } else { 286*4947cdc7SCole Faust kvpairs = append(kvpairs, items...) 287*4947cdc7SCole Faust } 288*4947cdc7SCole Faust } 289*4947cdc7SCole Faust 290*4947cdc7SCole Faust // positional args 291*4947cdc7SCole Faust var positional Tuple 292*4947cdc7SCole Faust if npos := int(arg >> 8); npos > 0 { 293*4947cdc7SCole Faust positional = stack[sp-npos : sp] 294*4947cdc7SCole Faust sp -= npos 295*4947cdc7SCole Faust 296*4947cdc7SCole Faust // Copy positional arguments into a new array, 297*4947cdc7SCole Faust // unless the callee is another Starlark function, 298*4947cdc7SCole Faust // in which case it can be trusted not to mutate them. 299*4947cdc7SCole Faust if _, ok := stack[sp-1].(*Function); !ok || args != nil { 300*4947cdc7SCole Faust positional = append(Tuple(nil), positional...) 301*4947cdc7SCole Faust } 302*4947cdc7SCole Faust } 303*4947cdc7SCole Faust if args != nil { 304*4947cdc7SCole Faust // Add elements from *args sequence. 305*4947cdc7SCole Faust iter := Iterate(args) 306*4947cdc7SCole Faust if iter == nil { 307*4947cdc7SCole Faust err = fmt.Errorf("argument after * must be iterable, not %s", args.Type()) 308*4947cdc7SCole Faust break loop 309*4947cdc7SCole Faust } 310*4947cdc7SCole Faust var elem Value 311*4947cdc7SCole Faust for iter.Next(&elem) { 312*4947cdc7SCole Faust positional = append(positional, elem) 313*4947cdc7SCole Faust } 314*4947cdc7SCole Faust iter.Done() 315*4947cdc7SCole Faust } 316*4947cdc7SCole Faust 317*4947cdc7SCole Faust function := stack[sp-1] 318*4947cdc7SCole Faust 319*4947cdc7SCole Faust if vmdebug { 320*4947cdc7SCole Faust fmt.Printf("VM call %s args=%s kwargs=%s @%s\n", 321*4947cdc7SCole Faust function, positional, kvpairs, f.Position(fr.pc)) 322*4947cdc7SCole Faust } 323*4947cdc7SCole Faust 324*4947cdc7SCole Faust thread.endProfSpan() 325*4947cdc7SCole Faust z, err2 := Call(thread, function, positional, kvpairs) 326*4947cdc7SCole Faust thread.beginProfSpan() 327*4947cdc7SCole Faust if err2 != nil { 328*4947cdc7SCole Faust err = err2 329*4947cdc7SCole Faust break loop 330*4947cdc7SCole Faust } 331*4947cdc7SCole Faust if vmdebug { 332*4947cdc7SCole Faust fmt.Printf("Resuming %s @ %s\n", f.Name, f.Position(0)) 333*4947cdc7SCole Faust } 334*4947cdc7SCole Faust stack[sp-1] = z 335*4947cdc7SCole Faust 336*4947cdc7SCole Faust case compile.ITERPUSH: 337*4947cdc7SCole Faust x := stack[sp-1] 338*4947cdc7SCole Faust sp-- 339*4947cdc7SCole Faust iter := Iterate(x) 340*4947cdc7SCole Faust if iter == nil { 341*4947cdc7SCole Faust err = fmt.Errorf("%s value is not iterable", x.Type()) 342*4947cdc7SCole Faust break loop 343*4947cdc7SCole Faust } 344*4947cdc7SCole Faust iterstack = append(iterstack, iter) 345*4947cdc7SCole Faust 346*4947cdc7SCole Faust case compile.ITERJMP: 347*4947cdc7SCole Faust iter := iterstack[len(iterstack)-1] 348*4947cdc7SCole Faust if iter.Next(&stack[sp]) { 349*4947cdc7SCole Faust sp++ 350*4947cdc7SCole Faust } else { 351*4947cdc7SCole Faust pc = arg 352*4947cdc7SCole Faust } 353*4947cdc7SCole Faust 354*4947cdc7SCole Faust case compile.ITERPOP: 355*4947cdc7SCole Faust n := len(iterstack) - 1 356*4947cdc7SCole Faust iterstack[n].Done() 357*4947cdc7SCole Faust iterstack = iterstack[:n] 358*4947cdc7SCole Faust 359*4947cdc7SCole Faust case compile.NOT: 360*4947cdc7SCole Faust stack[sp-1] = !stack[sp-1].Truth() 361*4947cdc7SCole Faust 362*4947cdc7SCole Faust case compile.RETURN: 363*4947cdc7SCole Faust result = stack[sp-1] 364*4947cdc7SCole Faust break loop 365*4947cdc7SCole Faust 366*4947cdc7SCole Faust case compile.SETINDEX: 367*4947cdc7SCole Faust z := stack[sp-1] 368*4947cdc7SCole Faust y := stack[sp-2] 369*4947cdc7SCole Faust x := stack[sp-3] 370*4947cdc7SCole Faust sp -= 3 371*4947cdc7SCole Faust err = setIndex(x, y, z) 372*4947cdc7SCole Faust if err != nil { 373*4947cdc7SCole Faust break loop 374*4947cdc7SCole Faust } 375*4947cdc7SCole Faust 376*4947cdc7SCole Faust case compile.INDEX: 377*4947cdc7SCole Faust y := stack[sp-1] 378*4947cdc7SCole Faust x := stack[sp-2] 379*4947cdc7SCole Faust sp -= 2 380*4947cdc7SCole Faust z, err2 := getIndex(x, y) 381*4947cdc7SCole Faust if err2 != nil { 382*4947cdc7SCole Faust err = err2 383*4947cdc7SCole Faust break loop 384*4947cdc7SCole Faust } 385*4947cdc7SCole Faust stack[sp] = z 386*4947cdc7SCole Faust sp++ 387*4947cdc7SCole Faust 388*4947cdc7SCole Faust case compile.ATTR: 389*4947cdc7SCole Faust x := stack[sp-1] 390*4947cdc7SCole Faust name := f.Prog.Names[arg] 391*4947cdc7SCole Faust y, err2 := getAttr(x, name) 392*4947cdc7SCole Faust if err2 != nil { 393*4947cdc7SCole Faust err = err2 394*4947cdc7SCole Faust break loop 395*4947cdc7SCole Faust } 396*4947cdc7SCole Faust stack[sp-1] = y 397*4947cdc7SCole Faust 398*4947cdc7SCole Faust case compile.SETFIELD: 399*4947cdc7SCole Faust y := stack[sp-1] 400*4947cdc7SCole Faust x := stack[sp-2] 401*4947cdc7SCole Faust sp -= 2 402*4947cdc7SCole Faust name := f.Prog.Names[arg] 403*4947cdc7SCole Faust if err2 := setField(x, name, y); err2 != nil { 404*4947cdc7SCole Faust err = err2 405*4947cdc7SCole Faust break loop 406*4947cdc7SCole Faust } 407*4947cdc7SCole Faust 408*4947cdc7SCole Faust case compile.MAKEDICT: 409*4947cdc7SCole Faust stack[sp] = new(Dict) 410*4947cdc7SCole Faust sp++ 411*4947cdc7SCole Faust 412*4947cdc7SCole Faust case compile.SETDICT, compile.SETDICTUNIQ: 413*4947cdc7SCole Faust dict := stack[sp-3].(*Dict) 414*4947cdc7SCole Faust k := stack[sp-2] 415*4947cdc7SCole Faust v := stack[sp-1] 416*4947cdc7SCole Faust sp -= 3 417*4947cdc7SCole Faust oldlen := dict.Len() 418*4947cdc7SCole Faust if err2 := dict.SetKey(k, v); err2 != nil { 419*4947cdc7SCole Faust err = err2 420*4947cdc7SCole Faust break loop 421*4947cdc7SCole Faust } 422*4947cdc7SCole Faust if op == compile.SETDICTUNIQ && dict.Len() == oldlen { 423*4947cdc7SCole Faust err = fmt.Errorf("duplicate key: %v", k) 424*4947cdc7SCole Faust break loop 425*4947cdc7SCole Faust } 426*4947cdc7SCole Faust 427*4947cdc7SCole Faust case compile.APPEND: 428*4947cdc7SCole Faust elem := stack[sp-1] 429*4947cdc7SCole Faust list := stack[sp-2].(*List) 430*4947cdc7SCole Faust sp -= 2 431*4947cdc7SCole Faust list.elems = append(list.elems, elem) 432*4947cdc7SCole Faust 433*4947cdc7SCole Faust case compile.SLICE: 434*4947cdc7SCole Faust x := stack[sp-4] 435*4947cdc7SCole Faust lo := stack[sp-3] 436*4947cdc7SCole Faust hi := stack[sp-2] 437*4947cdc7SCole Faust step := stack[sp-1] 438*4947cdc7SCole Faust sp -= 4 439*4947cdc7SCole Faust res, err2 := slice(x, lo, hi, step) 440*4947cdc7SCole Faust if err2 != nil { 441*4947cdc7SCole Faust err = err2 442*4947cdc7SCole Faust break loop 443*4947cdc7SCole Faust } 444*4947cdc7SCole Faust stack[sp] = res 445*4947cdc7SCole Faust sp++ 446*4947cdc7SCole Faust 447*4947cdc7SCole Faust case compile.UNPACK: 448*4947cdc7SCole Faust n := int(arg) 449*4947cdc7SCole Faust iterable := stack[sp-1] 450*4947cdc7SCole Faust sp-- 451*4947cdc7SCole Faust iter := Iterate(iterable) 452*4947cdc7SCole Faust if iter == nil { 453*4947cdc7SCole Faust err = fmt.Errorf("got %s in sequence assignment", iterable.Type()) 454*4947cdc7SCole Faust break loop 455*4947cdc7SCole Faust } 456*4947cdc7SCole Faust i := 0 457*4947cdc7SCole Faust sp += n 458*4947cdc7SCole Faust for i < n && iter.Next(&stack[sp-1-i]) { 459*4947cdc7SCole Faust i++ 460*4947cdc7SCole Faust } 461*4947cdc7SCole Faust var dummy Value 462*4947cdc7SCole Faust if iter.Next(&dummy) { 463*4947cdc7SCole Faust // NB: Len may return -1 here in obscure cases. 464*4947cdc7SCole Faust err = fmt.Errorf("too many values to unpack (got %d, want %d)", Len(iterable), n) 465*4947cdc7SCole Faust break loop 466*4947cdc7SCole Faust } 467*4947cdc7SCole Faust iter.Done() 468*4947cdc7SCole Faust if i < n { 469*4947cdc7SCole Faust err = fmt.Errorf("too few values to unpack (got %d, want %d)", i, n) 470*4947cdc7SCole Faust break loop 471*4947cdc7SCole Faust } 472*4947cdc7SCole Faust 473*4947cdc7SCole Faust case compile.CJMP: 474*4947cdc7SCole Faust if stack[sp-1].Truth() { 475*4947cdc7SCole Faust pc = arg 476*4947cdc7SCole Faust } 477*4947cdc7SCole Faust sp-- 478*4947cdc7SCole Faust 479*4947cdc7SCole Faust case compile.CONSTANT: 480*4947cdc7SCole Faust stack[sp] = fn.module.constants[arg] 481*4947cdc7SCole Faust sp++ 482*4947cdc7SCole Faust 483*4947cdc7SCole Faust case compile.MAKETUPLE: 484*4947cdc7SCole Faust n := int(arg) 485*4947cdc7SCole Faust tuple := make(Tuple, n) 486*4947cdc7SCole Faust sp -= n 487*4947cdc7SCole Faust copy(tuple, stack[sp:]) 488*4947cdc7SCole Faust stack[sp] = tuple 489*4947cdc7SCole Faust sp++ 490*4947cdc7SCole Faust 491*4947cdc7SCole Faust case compile.MAKELIST: 492*4947cdc7SCole Faust n := int(arg) 493*4947cdc7SCole Faust elems := make([]Value, n) 494*4947cdc7SCole Faust sp -= n 495*4947cdc7SCole Faust copy(elems, stack[sp:]) 496*4947cdc7SCole Faust stack[sp] = NewList(elems) 497*4947cdc7SCole Faust sp++ 498*4947cdc7SCole Faust 499*4947cdc7SCole Faust case compile.MAKEFUNC: 500*4947cdc7SCole Faust funcode := f.Prog.Functions[arg] 501*4947cdc7SCole Faust tuple := stack[sp-1].(Tuple) 502*4947cdc7SCole Faust n := len(tuple) - len(funcode.Freevars) 503*4947cdc7SCole Faust defaults := tuple[:n:n] 504*4947cdc7SCole Faust freevars := tuple[n:] 505*4947cdc7SCole Faust stack[sp-1] = &Function{ 506*4947cdc7SCole Faust funcode: funcode, 507*4947cdc7SCole Faust module: fn.module, 508*4947cdc7SCole Faust defaults: defaults, 509*4947cdc7SCole Faust freevars: freevars, 510*4947cdc7SCole Faust } 511*4947cdc7SCole Faust 512*4947cdc7SCole Faust case compile.LOAD: 513*4947cdc7SCole Faust n := int(arg) 514*4947cdc7SCole Faust module := string(stack[sp-1].(String)) 515*4947cdc7SCole Faust sp-- 516*4947cdc7SCole Faust 517*4947cdc7SCole Faust if thread.Load == nil { 518*4947cdc7SCole Faust err = fmt.Errorf("load not implemented by this application") 519*4947cdc7SCole Faust break loop 520*4947cdc7SCole Faust } 521*4947cdc7SCole Faust 522*4947cdc7SCole Faust thread.endProfSpan() 523*4947cdc7SCole Faust dict, err2 := thread.Load(thread, module) 524*4947cdc7SCole Faust thread.beginProfSpan() 525*4947cdc7SCole Faust if err2 != nil { 526*4947cdc7SCole Faust err = wrappedError{ 527*4947cdc7SCole Faust msg: fmt.Sprintf("cannot load %s: %v", module, err2), 528*4947cdc7SCole Faust cause: err2, 529*4947cdc7SCole Faust } 530*4947cdc7SCole Faust break loop 531*4947cdc7SCole Faust } 532*4947cdc7SCole Faust 533*4947cdc7SCole Faust for i := 0; i < n; i++ { 534*4947cdc7SCole Faust from := string(stack[sp-1-i].(String)) 535*4947cdc7SCole Faust v, ok := dict[from] 536*4947cdc7SCole Faust if !ok { 537*4947cdc7SCole Faust err = fmt.Errorf("load: name %s not found in module %s", from, module) 538*4947cdc7SCole Faust if n := spell.Nearest(from, dict.Keys()); n != "" { 539*4947cdc7SCole Faust err = fmt.Errorf("%s (did you mean %s?)", err, n) 540*4947cdc7SCole Faust } 541*4947cdc7SCole Faust break loop 542*4947cdc7SCole Faust } 543*4947cdc7SCole Faust stack[sp-1-i] = v 544*4947cdc7SCole Faust } 545*4947cdc7SCole Faust 546*4947cdc7SCole Faust case compile.SETLOCAL: 547*4947cdc7SCole Faust locals[arg] = stack[sp-1] 548*4947cdc7SCole Faust sp-- 549*4947cdc7SCole Faust 550*4947cdc7SCole Faust case compile.SETLOCALCELL: 551*4947cdc7SCole Faust locals[arg].(*cell).v = stack[sp-1] 552*4947cdc7SCole Faust sp-- 553*4947cdc7SCole Faust 554*4947cdc7SCole Faust case compile.SETGLOBAL: 555*4947cdc7SCole Faust fn.module.globals[arg] = stack[sp-1] 556*4947cdc7SCole Faust sp-- 557*4947cdc7SCole Faust 558*4947cdc7SCole Faust case compile.LOCAL: 559*4947cdc7SCole Faust x := locals[arg] 560*4947cdc7SCole Faust if x == nil { 561*4947cdc7SCole Faust err = fmt.Errorf("local variable %s referenced before assignment", f.Locals[arg].Name) 562*4947cdc7SCole Faust break loop 563*4947cdc7SCole Faust } 564*4947cdc7SCole Faust stack[sp] = x 565*4947cdc7SCole Faust sp++ 566*4947cdc7SCole Faust 567*4947cdc7SCole Faust case compile.FREE: 568*4947cdc7SCole Faust stack[sp] = fn.freevars[arg] 569*4947cdc7SCole Faust sp++ 570*4947cdc7SCole Faust 571*4947cdc7SCole Faust case compile.LOCALCELL: 572*4947cdc7SCole Faust v := locals[arg].(*cell).v 573*4947cdc7SCole Faust if v == nil { 574*4947cdc7SCole Faust err = fmt.Errorf("local variable %s referenced before assignment", f.Locals[arg].Name) 575*4947cdc7SCole Faust break loop 576*4947cdc7SCole Faust } 577*4947cdc7SCole Faust stack[sp] = v 578*4947cdc7SCole Faust sp++ 579*4947cdc7SCole Faust 580*4947cdc7SCole Faust case compile.FREECELL: 581*4947cdc7SCole Faust v := fn.freevars[arg].(*cell).v 582*4947cdc7SCole Faust if v == nil { 583*4947cdc7SCole Faust err = fmt.Errorf("local variable %s referenced before assignment", f.Freevars[arg].Name) 584*4947cdc7SCole Faust break loop 585*4947cdc7SCole Faust } 586*4947cdc7SCole Faust stack[sp] = v 587*4947cdc7SCole Faust sp++ 588*4947cdc7SCole Faust 589*4947cdc7SCole Faust case compile.GLOBAL: 590*4947cdc7SCole Faust x := fn.module.globals[arg] 591*4947cdc7SCole Faust if x == nil { 592*4947cdc7SCole Faust err = fmt.Errorf("global variable %s referenced before assignment", f.Prog.Globals[arg].Name) 593*4947cdc7SCole Faust break loop 594*4947cdc7SCole Faust } 595*4947cdc7SCole Faust stack[sp] = x 596*4947cdc7SCole Faust sp++ 597*4947cdc7SCole Faust 598*4947cdc7SCole Faust case compile.PREDECLARED: 599*4947cdc7SCole Faust name := f.Prog.Names[arg] 600*4947cdc7SCole Faust x := fn.module.predeclared[name] 601*4947cdc7SCole Faust if x == nil { 602*4947cdc7SCole Faust err = fmt.Errorf("internal error: predeclared variable %s is uninitialized", name) 603*4947cdc7SCole Faust break loop 604*4947cdc7SCole Faust } 605*4947cdc7SCole Faust stack[sp] = x 606*4947cdc7SCole Faust sp++ 607*4947cdc7SCole Faust 608*4947cdc7SCole Faust case compile.UNIVERSAL: 609*4947cdc7SCole Faust stack[sp] = Universe[f.Prog.Names[arg]] 610*4947cdc7SCole Faust sp++ 611*4947cdc7SCole Faust 612*4947cdc7SCole Faust default: 613*4947cdc7SCole Faust err = fmt.Errorf("unimplemented: %s", op) 614*4947cdc7SCole Faust break loop 615*4947cdc7SCole Faust } 616*4947cdc7SCole Faust } 617*4947cdc7SCole Faust 618*4947cdc7SCole Faust // ITERPOP the rest of the iterator stack. 619*4947cdc7SCole Faust for _, iter := range iterstack { 620*4947cdc7SCole Faust iter.Done() 621*4947cdc7SCole Faust } 622*4947cdc7SCole Faust 623*4947cdc7SCole Faust fr.locals = nil 624*4947cdc7SCole Faust 625*4947cdc7SCole Faust return result, err 626*4947cdc7SCole Faust} 627*4947cdc7SCole Faust 628*4947cdc7SCole Fausttype wrappedError struct { 629*4947cdc7SCole Faust msg string 630*4947cdc7SCole Faust cause error 631*4947cdc7SCole Faust} 632*4947cdc7SCole Faust 633*4947cdc7SCole Faustfunc (e wrappedError) Error() string { 634*4947cdc7SCole Faust return e.msg 635*4947cdc7SCole Faust} 636*4947cdc7SCole Faust 637*4947cdc7SCole Faust// Implements the xerrors.Wrapper interface 638*4947cdc7SCole Faust// https://godoc.org/golang.org/x/xerrors#Wrapper 639*4947cdc7SCole Faustfunc (e wrappedError) Unwrap() error { 640*4947cdc7SCole Faust return e.cause 641*4947cdc7SCole Faust} 642*4947cdc7SCole Faust 643*4947cdc7SCole Faust// mandatory is a sentinel value used in a function's defaults tuple 644*4947cdc7SCole Faust// to indicate that a (keyword-only) parameter is mandatory. 645*4947cdc7SCole Fausttype mandatory struct{} 646*4947cdc7SCole Faust 647*4947cdc7SCole Faustfunc (mandatory) String() string { return "mandatory" } 648*4947cdc7SCole Faustfunc (mandatory) Type() string { return "mandatory" } 649*4947cdc7SCole Faustfunc (mandatory) Freeze() {} // immutable 650*4947cdc7SCole Faustfunc (mandatory) Truth() Bool { return False } 651*4947cdc7SCole Faustfunc (mandatory) Hash() (uint32, error) { return 0, nil } 652*4947cdc7SCole Faust 653*4947cdc7SCole Faust// A cell is a box containing a Value. 654*4947cdc7SCole Faust// Local variables marked as cells hold their value indirectly 655*4947cdc7SCole Faust// so that they may be shared by outer and inner nested functions. 656*4947cdc7SCole Faust// Cells are always accessed using indirect {FREE,LOCAL,SETLOCAL}CELL instructions. 657*4947cdc7SCole Faust// The FreeVars tuple contains only cells. 658*4947cdc7SCole Faust// The FREE instruction always yields a cell. 659*4947cdc7SCole Fausttype cell struct{ v Value } 660*4947cdc7SCole Faust 661*4947cdc7SCole Faustfunc (c *cell) String() string { return "cell" } 662*4947cdc7SCole Faustfunc (c *cell) Type() string { return "cell" } 663*4947cdc7SCole Faustfunc (c *cell) Freeze() { 664*4947cdc7SCole Faust if c.v != nil { 665*4947cdc7SCole Faust c.v.Freeze() 666*4947cdc7SCole Faust } 667*4947cdc7SCole Faust} 668*4947cdc7SCole Faustfunc (c *cell) Truth() Bool { panic("unreachable") } 669*4947cdc7SCole Faustfunc (c *cell) Hash() (uint32, error) { panic("unreachable") } 670