xref: /aosp_15_r20/external/starlark-go/starlark/interp.go (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
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