• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 The Bazel Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package starlark
6
7import (
8	"fmt"
9	"io"
10	"io/ioutil"
11	"log"
12	"math/big"
13	"sort"
14	"strings"
15	"sync/atomic"
16	"time"
17	"unicode"
18	"unicode/utf8"
19	"unsafe"
20
21	"go.starlark.net/internal/compile"
22	"go.starlark.net/internal/spell"
23	"go.starlark.net/resolve"
24	"go.starlark.net/syntax"
25)
26
27// A Thread contains the state of a Starlark thread,
28// such as its call stack and thread-local storage.
29// The Thread is threaded throughout the evaluator.
30type Thread struct {
31	// Name is an optional name that describes the thread, for debugging.
32	Name string
33
34	// stack is the stack of (internal) call frames.
35	stack []*frame
36
37	// Print is the client-supplied implementation of the Starlark
38	// 'print' function. If nil, fmt.Fprintln(os.Stderr, msg) is
39	// used instead.
40	Print func(thread *Thread, msg string)
41
42	// Load is the client-supplied implementation of module loading.
43	// Repeated calls with the same module name must return the same
44	// module environment or error.
45	// The error message need not include the module name.
46	//
47	// See example_test.go for some example implementations of Load.
48	Load func(thread *Thread, module string) (StringDict, error)
49
50	// steps counts abstract computation steps executed by this thread.
51	steps, maxSteps uint64
52
53	// cancelReason records the reason from the first call to Cancel.
54	cancelReason *string
55
56	// locals holds arbitrary "thread-local" Go values belonging to the client.
57	// They are accessible to the client but not to any Starlark program.
58	locals map[string]interface{}
59
60	// proftime holds the accumulated execution time since the last profile event.
61	proftime time.Duration
62}
63
64// ExecutionSteps returns a count of abstract computation steps executed
65// by this thread. It is incremented by the interpreter. It may be used
66// as a measure of the approximate cost of Starlark execution, by
67// computing the difference in its value before and after a computation.
68//
69// The precise meaning of "step" is not specified and may change.
70func (thread *Thread) ExecutionSteps() uint64 {
71	return thread.steps
72}
73
74// SetMaxExecutionSteps sets a limit on the number of Starlark
75// computation steps that may be executed by this thread. If the
76// thread's step counter exceeds this limit, the interpreter calls
77// thread.Cancel("too many steps").
78func (thread *Thread) SetMaxExecutionSteps(max uint64) {
79	thread.maxSteps = max
80}
81
82// Cancel causes execution of Starlark code in the specified thread to
83// promptly fail with an EvalError that includes the specified reason.
84// There may be a delay before the interpreter observes the cancellation
85// if the thread is currently in a call to a built-in function.
86//
87// Cancellation cannot be undone.
88//
89// Unlike most methods of Thread, it is safe to call Cancel from any
90// goroutine, even if the thread is actively executing.
91func (thread *Thread) Cancel(reason string) {
92	// Atomically set cancelReason, preserving earlier reason if any.
93	atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&thread.cancelReason)), nil, unsafe.Pointer(&reason))
94}
95
96// SetLocal sets the thread-local value associated with the specified key.
97// It must not be called after execution begins.
98func (thread *Thread) SetLocal(key string, value interface{}) {
99	if thread.locals == nil {
100		thread.locals = make(map[string]interface{})
101	}
102	thread.locals[key] = value
103}
104
105// Local returns the thread-local value associated with the specified key.
106func (thread *Thread) Local(key string) interface{} {
107	return thread.locals[key]
108}
109
110// CallFrame returns a copy of the specified frame of the callstack.
111// It should only be used in built-ins called from Starlark code.
112// Depth 0 means the frame of the built-in itself, 1 is its caller, and so on.
113//
114// It is equivalent to CallStack().At(depth), but more efficient.
115func (thread *Thread) CallFrame(depth int) CallFrame {
116	return thread.frameAt(depth).asCallFrame()
117}
118
119func (thread *Thread) frameAt(depth int) *frame {
120	return thread.stack[len(thread.stack)-1-depth]
121}
122
123// CallStack returns a new slice containing the thread's stack of call frames.
124func (thread *Thread) CallStack() CallStack {
125	frames := make([]CallFrame, len(thread.stack))
126	for i, fr := range thread.stack {
127		frames[i] = fr.asCallFrame()
128	}
129	return frames
130}
131
132// CallStackDepth returns the number of frames in the current call stack.
133func (thread *Thread) CallStackDepth() int { return len(thread.stack) }
134
135// A StringDict is a mapping from names to values, and represents
136// an environment such as the global variables of a module.
137// It is not a true starlark.Value.
138type StringDict map[string]Value
139
140// Keys returns a new sorted slice of d's keys.
141func (d StringDict) Keys() []string {
142	names := make([]string, 0, len(d))
143	for name := range d {
144		names = append(names, name)
145	}
146	sort.Strings(names)
147	return names
148}
149
150func (d StringDict) String() string {
151	buf := new(strings.Builder)
152	buf.WriteByte('{')
153	sep := ""
154	for _, name := range d.Keys() {
155		buf.WriteString(sep)
156		buf.WriteString(name)
157		buf.WriteString(": ")
158		writeValue(buf, d[name], nil)
159		sep = ", "
160	}
161	buf.WriteByte('}')
162	return buf.String()
163}
164
165func (d StringDict) Freeze() {
166	for _, v := range d {
167		v.Freeze()
168	}
169}
170
171// Has reports whether the dictionary contains the specified key.
172func (d StringDict) Has(key string) bool { _, ok := d[key]; return ok }
173
174// A frame records a call to a Starlark function (including module toplevel)
175// or a built-in function or method.
176type frame struct {
177	callable  Callable // current function (or toplevel) or built-in
178	pc        uint32   // program counter (Starlark frames only)
179	locals    []Value  // local variables (Starlark frames only)
180	spanStart int64    // start time of current profiler span
181}
182
183// Position returns the source position of the current point of execution in this frame.
184func (fr *frame) Position() syntax.Position {
185	switch c := fr.callable.(type) {
186	case *Function:
187		// Starlark function
188		return c.funcode.Position(fr.pc)
189	case callableWithPosition:
190		// If a built-in Callable defines
191		// a Position method, use it.
192		return c.Position()
193	}
194	return syntax.MakePosition(&builtinFilename, 0, 0)
195}
196
197var builtinFilename = "<builtin>"
198
199// Function returns the frame's function or built-in.
200func (fr *frame) Callable() Callable { return fr.callable }
201
202// A CallStack is a stack of call frames, outermost first.
203type CallStack []CallFrame
204
205// At returns a copy of the frame at depth i.
206// At(0) returns the topmost frame.
207func (stack CallStack) At(i int) CallFrame { return stack[len(stack)-1-i] }
208
209// Pop removes and returns the topmost frame.
210func (stack *CallStack) Pop() CallFrame {
211	last := len(*stack) - 1
212	top := (*stack)[last]
213	*stack = (*stack)[:last]
214	return top
215}
216
217// String returns a user-friendly description of the stack.
218func (stack CallStack) String() string {
219	out := new(strings.Builder)
220	if len(stack) > 0 {
221		fmt.Fprintf(out, "Traceback (most recent call last):\n")
222	}
223	for _, fr := range stack {
224		fmt.Fprintf(out, "  %s: in %s\n", fr.Pos, fr.Name)
225	}
226	return out.String()
227}
228
229// An EvalError is a Starlark evaluation error and
230// a copy of the thread's stack at the moment of the error.
231type EvalError struct {
232	Msg       string
233	CallStack CallStack
234	cause     error
235}
236
237// A CallFrame represents the function name and current
238// position of execution of an enclosing call frame.
239type CallFrame struct {
240	Name string
241	Pos  syntax.Position
242}
243
244func (fr *frame) asCallFrame() CallFrame {
245	return CallFrame{
246		Name: fr.Callable().Name(),
247		Pos:  fr.Position(),
248	}
249}
250
251func (thread *Thread) evalError(err error) *EvalError {
252	return &EvalError{
253		Msg:       err.Error(),
254		CallStack: thread.CallStack(),
255		cause:     err,
256	}
257}
258
259func (e *EvalError) Error() string { return e.Msg }
260
261// Backtrace returns a user-friendly error message describing the stack
262// of calls that led to this error.
263func (e *EvalError) Backtrace() string {
264	// If the topmost stack frame is a built-in function,
265	// remove it from the stack and add print "Error in fn:".
266	stack := e.CallStack
267	suffix := ""
268	if last := len(stack) - 1; last >= 0 && stack[last].Pos.Filename() == builtinFilename {
269		suffix = " in " + stack[last].Name
270		stack = stack[:last]
271	}
272	return fmt.Sprintf("%sError%s: %s", stack, suffix, e.Msg)
273}
274
275func (e *EvalError) Unwrap() error { return e.cause }
276
277// A Program is a compiled Starlark program.
278//
279// Programs are immutable, and contain no Values.
280// A Program may be created by parsing a source file (see SourceProgram)
281// or by loading a previously saved compiled program (see CompiledProgram).
282type Program struct {
283	compiled *compile.Program
284}
285
286// CompilerVersion is the version number of the protocol for compiled
287// files. Applications must not run programs compiled by one version
288// with an interpreter at another version, and should thus incorporate
289// the compiler version into the cache key when reusing compiled code.
290const CompilerVersion = compile.Version
291
292// Filename returns the name of the file from which this program was loaded.
293func (prog *Program) Filename() string { return prog.compiled.Toplevel.Pos.Filename() }
294
295func (prog *Program) String() string { return prog.Filename() }
296
297// NumLoads returns the number of load statements in the compiled program.
298func (prog *Program) NumLoads() int { return len(prog.compiled.Loads) }
299
300// Load(i) returns the name and position of the i'th module directly
301// loaded by this one, where 0 <= i < NumLoads().
302// The name is unresolved---exactly as it appears in the source.
303func (prog *Program) Load(i int) (string, syntax.Position) {
304	id := prog.compiled.Loads[i]
305	return id.Name, id.Pos
306}
307
308// WriteTo writes the compiled module to the specified output stream.
309func (prog *Program) Write(out io.Writer) error {
310	data := prog.compiled.Encode()
311	_, err := out.Write(data)
312	return err
313}
314
315// ExecFile parses, resolves, and executes a Starlark file in the
316// specified global environment, which may be modified during execution.
317//
318// Thread is the state associated with the Starlark thread.
319//
320// The filename and src parameters are as for syntax.Parse:
321// filename is the name of the file to execute,
322// and the name that appears in error messages;
323// src is an optional source of bytes to use
324// instead of filename.
325//
326// predeclared defines the predeclared names specific to this module.
327// Execution does not modify this dictionary, though it may mutate
328// its values.
329//
330// If ExecFile fails during evaluation, it returns an *EvalError
331// containing a backtrace.
332func ExecFile(thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) {
333	// Parse, resolve, and compile a Starlark source file.
334	_, mod, err := SourceProgram(filename, src, predeclared.Has)
335	if err != nil {
336		return nil, err
337	}
338
339	g, err := mod.Init(thread, predeclared)
340	g.Freeze()
341	return g, err
342}
343
344// SourceProgram produces a new program by parsing, resolving,
345// and compiling a Starlark source file.
346// On success, it returns the parsed file and the compiled program.
347// The filename and src parameters are as for syntax.Parse.
348//
349// The isPredeclared predicate reports whether a name is
350// a pre-declared identifier of the current module.
351// Its typical value is predeclared.Has,
352// where predeclared is a StringDict of pre-declared values.
353func SourceProgram(filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) {
354	f, err := syntax.Parse(filename, src, 0)
355	if err != nil {
356		return nil, nil, err
357	}
358	prog, err := FileProgram(f, isPredeclared)
359	return f, prog, err
360}
361
362// FileProgram produces a new program by resolving,
363// and compiling the Starlark source file syntax tree.
364// On success, it returns the compiled program.
365//
366// Resolving a syntax tree mutates it.
367// Do not call FileProgram more than once on the same file.
368//
369// The isPredeclared predicate reports whether a name is
370// a pre-declared identifier of the current module.
371// Its typical value is predeclared.Has,
372// where predeclared is a StringDict of pre-declared values.
373func FileProgram(f *syntax.File, isPredeclared func(string) bool) (*Program, error) {
374	if err := resolve.File(f, isPredeclared, Universe.Has); err != nil {
375		return nil, err
376	}
377
378	var pos syntax.Position
379	if len(f.Stmts) > 0 {
380		pos = syntax.Start(f.Stmts[0])
381	} else {
382		pos = syntax.MakePosition(&f.Path, 1, 1)
383	}
384
385	module := f.Module.(*resolve.Module)
386	compiled := compile.File(f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
387
388	return &Program{compiled}, nil
389}
390
391// CompiledProgram produces a new program from the representation
392// of a compiled program previously saved by Program.Write.
393func CompiledProgram(in io.Reader) (*Program, error) {
394	data, err := ioutil.ReadAll(in)
395	if err != nil {
396		return nil, err
397	}
398	compiled, err := compile.DecodeProgram(data)
399	if err != nil {
400		return nil, err
401	}
402	return &Program{compiled}, nil
403}
404
405// Init creates a set of global variables for the program,
406// executes the toplevel code of the specified program,
407// and returns a new, unfrozen dictionary of the globals.
408func (prog *Program) Init(thread *Thread, predeclared StringDict) (StringDict, error) {
409	toplevel := makeToplevelFunction(prog.compiled, predeclared)
410
411	_, err := Call(thread, toplevel, nil, nil)
412
413	// Convert the global environment to a map.
414	// We return a (partial) map even in case of error.
415	return toplevel.Globals(), err
416}
417
418// ExecREPLChunk compiles and executes file f in the specified thread
419// and global environment. This is a variant of ExecFile specialized to
420// the needs of a REPL, in which a sequence of input chunks, each
421// syntactically a File, manipulates the same set of module globals,
422// which are not frozen after execution.
423//
424// This function is intended to support only go.starlark.net/repl.
425// Its API stability is not guaranteed.
426func ExecREPLChunk(f *syntax.File, thread *Thread, globals StringDict) error {
427	var predeclared StringDict
428
429	// -- variant of FileProgram --
430
431	if err := resolve.REPLChunk(f, globals.Has, predeclared.Has, Universe.Has); err != nil {
432		return err
433	}
434
435	var pos syntax.Position
436	if len(f.Stmts) > 0 {
437		pos = syntax.Start(f.Stmts[0])
438	} else {
439		pos = syntax.MakePosition(&f.Path, 1, 1)
440	}
441
442	module := f.Module.(*resolve.Module)
443	compiled := compile.File(f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
444	prog := &Program{compiled}
445
446	// -- variant of Program.Init --
447
448	toplevel := makeToplevelFunction(prog.compiled, predeclared)
449
450	// Initialize module globals from parameter.
451	for i, id := range prog.compiled.Globals {
452		if v := globals[id.Name]; v != nil {
453			toplevel.module.globals[i] = v
454		}
455	}
456
457	_, err := Call(thread, toplevel, nil, nil)
458
459	// Reflect changes to globals back to parameter, even after an error.
460	for i, id := range prog.compiled.Globals {
461		if v := toplevel.module.globals[i]; v != nil {
462			globals[id.Name] = v
463		}
464	}
465
466	return err
467}
468
469func makeToplevelFunction(prog *compile.Program, predeclared StringDict) *Function {
470	// Create the Starlark value denoted by each program constant c.
471	constants := make([]Value, len(prog.Constants))
472	for i, c := range prog.Constants {
473		var v Value
474		switch c := c.(type) {
475		case int64:
476			v = MakeInt64(c)
477		case *big.Int:
478			v = MakeBigInt(c)
479		case string:
480			v = String(c)
481		case compile.Bytes:
482			v = Bytes(c)
483		case float64:
484			v = Float(c)
485		default:
486			log.Panicf("unexpected constant %T: %v", c, c)
487		}
488		constants[i] = v
489	}
490
491	return &Function{
492		funcode: prog.Toplevel,
493		module: &module{
494			program:     prog,
495			predeclared: predeclared,
496			globals:     make([]Value, len(prog.Globals)),
497			constants:   constants,
498		},
499	}
500}
501
502// Eval parses, resolves, and evaluates an expression within the
503// specified (predeclared) environment.
504//
505// Evaluation cannot mutate the environment dictionary itself,
506// though it may modify variables reachable from the dictionary.
507//
508// The filename and src parameters are as for syntax.Parse.
509//
510// If Eval fails during evaluation, it returns an *EvalError
511// containing a backtrace.
512func Eval(thread *Thread, filename string, src interface{}, env StringDict) (Value, error) {
513	expr, err := syntax.ParseExpr(filename, src, 0)
514	if err != nil {
515		return nil, err
516	}
517	f, err := makeExprFunc(expr, env)
518	if err != nil {
519		return nil, err
520	}
521	return Call(thread, f, nil, nil)
522}
523
524// EvalExpr resolves and evaluates an expression within the
525// specified (predeclared) environment.
526// Evaluating a comma-separated list of expressions yields a tuple value.
527//
528// Resolving an expression mutates it.
529// Do not call EvalExpr more than once for the same expression.
530//
531// Evaluation cannot mutate the environment dictionary itself,
532// though it may modify variables reachable from the dictionary.
533//
534// If Eval fails during evaluation, it returns an *EvalError
535// containing a backtrace.
536func EvalExpr(thread *Thread, expr syntax.Expr, env StringDict) (Value, error) {
537	fn, err := makeExprFunc(expr, env)
538	if err != nil {
539		return nil, err
540	}
541	return Call(thread, fn, nil, nil)
542}
543
544// ExprFunc returns a no-argument function
545// that evaluates the expression whose source is src.
546func ExprFunc(filename string, src interface{}, env StringDict) (*Function, error) {
547	expr, err := syntax.ParseExpr(filename, src, 0)
548	if err != nil {
549		return nil, err
550	}
551	return makeExprFunc(expr, env)
552}
553
554// makeExprFunc returns a no-argument function whose body is expr.
555func makeExprFunc(expr syntax.Expr, env StringDict) (*Function, error) {
556	locals, err := resolve.Expr(expr, env.Has, Universe.Has)
557	if err != nil {
558		return nil, err
559	}
560
561	return makeToplevelFunction(compile.Expr(expr, "<expr>", locals), env), nil
562}
563
564// The following functions are primitive operations of the byte code interpreter.
565
566// list += iterable
567func listExtend(x *List, y Iterable) {
568	if ylist, ok := y.(*List); ok {
569		// fast path: list += list
570		x.elems = append(x.elems, ylist.elems...)
571	} else {
572		iter := y.Iterate()
573		defer iter.Done()
574		var z Value
575		for iter.Next(&z) {
576			x.elems = append(x.elems, z)
577		}
578	}
579}
580
581// getAttr implements x.dot.
582func getAttr(x Value, name string) (Value, error) {
583	hasAttr, ok := x.(HasAttrs)
584	if !ok {
585		return nil, fmt.Errorf("%s has no .%s field or method", x.Type(), name)
586	}
587
588	var errmsg string
589	v, err := hasAttr.Attr(name)
590	if err == nil {
591		if v != nil {
592			return v, nil // success
593		}
594		// (nil, nil) => generic error
595		errmsg = fmt.Sprintf("%s has no .%s field or method", x.Type(), name)
596	} else if nsa, ok := err.(NoSuchAttrError); ok {
597		errmsg = string(nsa)
598	} else {
599		return nil, err // return error as is
600	}
601
602	// add spelling hint
603	if n := spell.Nearest(name, hasAttr.AttrNames()); n != "" {
604		errmsg = fmt.Sprintf("%s (did you mean .%s?)", errmsg, n)
605	}
606
607	return nil, fmt.Errorf("%s", errmsg)
608}
609
610// setField implements x.name = y.
611func setField(x Value, name string, y Value) error {
612	if x, ok := x.(HasSetField); ok {
613		err := x.SetField(name, y)
614		if _, ok := err.(NoSuchAttrError); ok {
615			// No such field: check spelling.
616			if n := spell.Nearest(name, x.AttrNames()); n != "" {
617				err = fmt.Errorf("%s (did you mean .%s?)", err, n)
618			}
619		}
620		return err
621	}
622
623	return fmt.Errorf("can't assign to .%s field of %s", name, x.Type())
624}
625
626// getIndex implements x[y].
627func getIndex(x, y Value) (Value, error) {
628	switch x := x.(type) {
629	case Mapping: // dict
630		z, found, err := x.Get(y)
631		if err != nil {
632			return nil, err
633		}
634		if !found {
635			return nil, fmt.Errorf("key %v not in %s", y, x.Type())
636		}
637		return z, nil
638
639	case Indexable: // string, list, tuple
640		n := x.Len()
641		i, err := AsInt32(y)
642		if err != nil {
643			return nil, fmt.Errorf("%s index: %s", x.Type(), err)
644		}
645		origI := i
646		if i < 0 {
647			i += n
648		}
649		if i < 0 || i >= n {
650			return nil, outOfRange(origI, n, x)
651		}
652		return x.Index(i), nil
653	}
654	return nil, fmt.Errorf("unhandled index operation %s[%s]", x.Type(), y.Type())
655}
656
657func outOfRange(i, n int, x Value) error {
658	if n == 0 {
659		return fmt.Errorf("index %d out of range: empty %s", i, x.Type())
660	} else {
661		return fmt.Errorf("%s index %d out of range [%d:%d]", x.Type(), i, -n, n-1)
662	}
663}
664
665// setIndex implements x[y] = z.
666func setIndex(x, y, z Value) error {
667	switch x := x.(type) {
668	case HasSetKey:
669		if err := x.SetKey(y, z); err != nil {
670			return err
671		}
672
673	case HasSetIndex:
674		n := x.Len()
675		i, err := AsInt32(y)
676		if err != nil {
677			return err
678		}
679		origI := i
680		if i < 0 {
681			i += n
682		}
683		if i < 0 || i >= n {
684			return outOfRange(origI, n, x)
685		}
686		return x.SetIndex(i, z)
687
688	default:
689		return fmt.Errorf("%s value does not support item assignment", x.Type())
690	}
691	return nil
692}
693
694// Unary applies a unary operator (+, -, ~, not) to its operand.
695func Unary(op syntax.Token, x Value) (Value, error) {
696	// The NOT operator is not customizable.
697	if op == syntax.NOT {
698		return !x.Truth(), nil
699	}
700
701	// Int, Float, and user-defined types
702	if x, ok := x.(HasUnary); ok {
703		// (nil, nil) => unhandled
704		y, err := x.Unary(op)
705		if y != nil || err != nil {
706			return y, err
707		}
708	}
709
710	return nil, fmt.Errorf("unknown unary op: %s %s", op, x.Type())
711}
712
713// Binary applies a strict binary operator (not AND or OR) to its operands.
714// For equality tests or ordered comparisons, use Compare instead.
715func Binary(op syntax.Token, x, y Value) (Value, error) {
716	switch op {
717	case syntax.PLUS:
718		switch x := x.(type) {
719		case String:
720			if y, ok := y.(String); ok {
721				return x + y, nil
722			}
723		case Int:
724			switch y := y.(type) {
725			case Int:
726				return x.Add(y), nil
727			case Float:
728				xf, err := x.finiteFloat()
729				if err != nil {
730					return nil, err
731				}
732				return xf + y, nil
733			}
734		case Float:
735			switch y := y.(type) {
736			case Float:
737				return x + y, nil
738			case Int:
739				yf, err := y.finiteFloat()
740				if err != nil {
741					return nil, err
742				}
743				return x + yf, nil
744			}
745		case *List:
746			if y, ok := y.(*List); ok {
747				z := make([]Value, 0, x.Len()+y.Len())
748				z = append(z, x.elems...)
749				z = append(z, y.elems...)
750				return NewList(z), nil
751			}
752		case Tuple:
753			if y, ok := y.(Tuple); ok {
754				z := make(Tuple, 0, len(x)+len(y))
755				z = append(z, x...)
756				z = append(z, y...)
757				return z, nil
758			}
759		}
760
761	case syntax.MINUS:
762		switch x := x.(type) {
763		case Int:
764			switch y := y.(type) {
765			case Int:
766				return x.Sub(y), nil
767			case Float:
768				xf, err := x.finiteFloat()
769				if err != nil {
770					return nil, err
771				}
772				return xf - y, nil
773			}
774		case Float:
775			switch y := y.(type) {
776			case Float:
777				return x - y, nil
778			case Int:
779				yf, err := y.finiteFloat()
780				if err != nil {
781					return nil, err
782				}
783				return x - yf, nil
784			}
785		}
786
787	case syntax.STAR:
788		switch x := x.(type) {
789		case Int:
790			switch y := y.(type) {
791			case Int:
792				return x.Mul(y), nil
793			case Float:
794				xf, err := x.finiteFloat()
795				if err != nil {
796					return nil, err
797				}
798				return xf * y, nil
799			case String:
800				return stringRepeat(y, x)
801			case Bytes:
802				return bytesRepeat(y, x)
803			case *List:
804				elems, err := tupleRepeat(Tuple(y.elems), x)
805				if err != nil {
806					return nil, err
807				}
808				return NewList(elems), nil
809			case Tuple:
810				return tupleRepeat(y, x)
811			}
812		case Float:
813			switch y := y.(type) {
814			case Float:
815				return x * y, nil
816			case Int:
817				yf, err := y.finiteFloat()
818				if err != nil {
819					return nil, err
820				}
821				return x * yf, nil
822			}
823		case String:
824			if y, ok := y.(Int); ok {
825				return stringRepeat(x, y)
826			}
827		case Bytes:
828			if y, ok := y.(Int); ok {
829				return bytesRepeat(x, y)
830			}
831		case *List:
832			if y, ok := y.(Int); ok {
833				elems, err := tupleRepeat(Tuple(x.elems), y)
834				if err != nil {
835					return nil, err
836				}
837				return NewList(elems), nil
838			}
839		case Tuple:
840			if y, ok := y.(Int); ok {
841				return tupleRepeat(x, y)
842			}
843
844		}
845
846	case syntax.SLASH:
847		switch x := x.(type) {
848		case Int:
849			xf, err := x.finiteFloat()
850			if err != nil {
851				return nil, err
852			}
853			switch y := y.(type) {
854			case Int:
855				yf, err := y.finiteFloat()
856				if err != nil {
857					return nil, err
858				}
859				if yf == 0.0 {
860					return nil, fmt.Errorf("floating-point division by zero")
861				}
862				return xf / yf, nil
863			case Float:
864				if y == 0.0 {
865					return nil, fmt.Errorf("floating-point division by zero")
866				}
867				return xf / y, nil
868			}
869		case Float:
870			switch y := y.(type) {
871			case Float:
872				if y == 0.0 {
873					return nil, fmt.Errorf("floating-point division by zero")
874				}
875				return x / y, nil
876			case Int:
877				yf, err := y.finiteFloat()
878				if err != nil {
879					return nil, err
880				}
881				if yf == 0.0 {
882					return nil, fmt.Errorf("floating-point division by zero")
883				}
884				return x / yf, nil
885			}
886		}
887
888	case syntax.SLASHSLASH:
889		switch x := x.(type) {
890		case Int:
891			switch y := y.(type) {
892			case Int:
893				if y.Sign() == 0 {
894					return nil, fmt.Errorf("floored division by zero")
895				}
896				return x.Div(y), nil
897			case Float:
898				xf, err := x.finiteFloat()
899				if err != nil {
900					return nil, err
901				}
902				if y == 0.0 {
903					return nil, fmt.Errorf("floored division by zero")
904				}
905				return floor(xf / y), nil
906			}
907		case Float:
908			switch y := y.(type) {
909			case Float:
910				if y == 0.0 {
911					return nil, fmt.Errorf("floored division by zero")
912				}
913				return floor(x / y), nil
914			case Int:
915				yf, err := y.finiteFloat()
916				if err != nil {
917					return nil, err
918				}
919				if yf == 0.0 {
920					return nil, fmt.Errorf("floored division by zero")
921				}
922				return floor(x / yf), nil
923			}
924		}
925
926	case syntax.PERCENT:
927		switch x := x.(type) {
928		case Int:
929			switch y := y.(type) {
930			case Int:
931				if y.Sign() == 0 {
932					return nil, fmt.Errorf("integer modulo by zero")
933				}
934				return x.Mod(y), nil
935			case Float:
936				xf, err := x.finiteFloat()
937				if err != nil {
938					return nil, err
939				}
940				if y == 0 {
941					return nil, fmt.Errorf("floating-point modulo by zero")
942				}
943				return xf.Mod(y), nil
944			}
945		case Float:
946			switch y := y.(type) {
947			case Float:
948				if y == 0.0 {
949					return nil, fmt.Errorf("floating-point modulo by zero")
950				}
951				return x.Mod(y), nil
952			case Int:
953				if y.Sign() == 0 {
954					return nil, fmt.Errorf("floating-point modulo by zero")
955				}
956				yf, err := y.finiteFloat()
957				if err != nil {
958					return nil, err
959				}
960				return x.Mod(yf), nil
961			}
962		case String:
963			return interpolate(string(x), y)
964		}
965
966	case syntax.NOT_IN:
967		z, err := Binary(syntax.IN, x, y)
968		if err != nil {
969			return nil, err
970		}
971		return !z.Truth(), nil
972
973	case syntax.IN:
974		switch y := y.(type) {
975		case *List:
976			for _, elem := range y.elems {
977				if eq, err := Equal(elem, x); err != nil {
978					return nil, err
979				} else if eq {
980					return True, nil
981				}
982			}
983			return False, nil
984		case Tuple:
985			for _, elem := range y {
986				if eq, err := Equal(elem, x); err != nil {
987					return nil, err
988				} else if eq {
989					return True, nil
990				}
991			}
992			return False, nil
993		case Mapping: // e.g. dict
994			// Ignore error from Get as we cannot distinguish true
995			// errors (value cycle, type error) from "key not found".
996			_, found, _ := y.Get(x)
997			return Bool(found), nil
998		case *Set:
999			ok, err := y.Has(x)
1000			return Bool(ok), err
1001		case String:
1002			needle, ok := x.(String)
1003			if !ok {
1004				return nil, fmt.Errorf("'in <string>' requires string as left operand, not %s", x.Type())
1005			}
1006			return Bool(strings.Contains(string(y), string(needle))), nil
1007		case Bytes:
1008			switch needle := x.(type) {
1009			case Bytes:
1010				return Bool(strings.Contains(string(y), string(needle))), nil
1011			case Int:
1012				var b byte
1013				if err := AsInt(needle, &b); err != nil {
1014					return nil, fmt.Errorf("int in bytes: %s", err)
1015				}
1016				return Bool(strings.IndexByte(string(y), b) >= 0), nil
1017			default:
1018				return nil, fmt.Errorf("'in bytes' requires bytes or int as left operand, not %s", x.Type())
1019			}
1020		case rangeValue:
1021			i, err := NumberToInt(x)
1022			if err != nil {
1023				return nil, fmt.Errorf("'in <range>' requires integer as left operand, not %s", x.Type())
1024			}
1025			return Bool(y.contains(i)), nil
1026		}
1027
1028	case syntax.PIPE:
1029		switch x := x.(type) {
1030		case Int:
1031			if y, ok := y.(Int); ok {
1032				return x.Or(y), nil
1033			}
1034		case *Set: // union
1035			if y, ok := y.(*Set); ok {
1036				iter := Iterate(y)
1037				defer iter.Done()
1038				return x.Union(iter)
1039			}
1040		}
1041
1042	case syntax.AMP:
1043		switch x := x.(type) {
1044		case Int:
1045			if y, ok := y.(Int); ok {
1046				return x.And(y), nil
1047			}
1048		case *Set: // intersection
1049			if y, ok := y.(*Set); ok {
1050				set := new(Set)
1051				if x.Len() > y.Len() {
1052					x, y = y, x // opt: range over smaller set
1053				}
1054				for _, xelem := range x.elems() {
1055					// Has, Insert cannot fail here.
1056					if found, _ := y.Has(xelem); found {
1057						set.Insert(xelem)
1058					}
1059				}
1060				return set, nil
1061			}
1062		}
1063
1064	case syntax.CIRCUMFLEX:
1065		switch x := x.(type) {
1066		case Int:
1067			if y, ok := y.(Int); ok {
1068				return x.Xor(y), nil
1069			}
1070		case *Set: // symmetric difference
1071			if y, ok := y.(*Set); ok {
1072				set := new(Set)
1073				for _, xelem := range x.elems() {
1074					if found, _ := y.Has(xelem); !found {
1075						set.Insert(xelem)
1076					}
1077				}
1078				for _, yelem := range y.elems() {
1079					if found, _ := x.Has(yelem); !found {
1080						set.Insert(yelem)
1081					}
1082				}
1083				return set, nil
1084			}
1085		}
1086
1087	case syntax.LTLT, syntax.GTGT:
1088		if x, ok := x.(Int); ok {
1089			y, err := AsInt32(y)
1090			if err != nil {
1091				return nil, err
1092			}
1093			if y < 0 {
1094				return nil, fmt.Errorf("negative shift count: %v", y)
1095			}
1096			if op == syntax.LTLT {
1097				if y >= 512 {
1098					return nil, fmt.Errorf("shift count too large: %v", y)
1099				}
1100				return x.Lsh(uint(y)), nil
1101			} else {
1102				return x.Rsh(uint(y)), nil
1103			}
1104		}
1105
1106	default:
1107		// unknown operator
1108		goto unknown
1109	}
1110
1111	// user-defined types
1112	// (nil, nil) => unhandled
1113	if x, ok := x.(HasBinary); ok {
1114		z, err := x.Binary(op, y, Left)
1115		if z != nil || err != nil {
1116			return z, err
1117		}
1118	}
1119	if y, ok := y.(HasBinary); ok {
1120		z, err := y.Binary(op, x, Right)
1121		if z != nil || err != nil {
1122			return z, err
1123		}
1124	}
1125
1126	// unsupported operand types
1127unknown:
1128	return nil, fmt.Errorf("unknown binary op: %s %s %s", x.Type(), op, y.Type())
1129}
1130
1131// It's always possible to overeat in small bites but we'll
1132// try to stop someone swallowing the world in one gulp.
1133const maxAlloc = 1 << 30
1134
1135func tupleRepeat(elems Tuple, n Int) (Tuple, error) {
1136	if len(elems) == 0 {
1137		return nil, nil
1138	}
1139	i, err := AsInt32(n)
1140	if err != nil {
1141		return nil, fmt.Errorf("repeat count %s too large", n)
1142	}
1143	if i < 1 {
1144		return nil, nil
1145	}
1146	// Inv: i > 0, len > 0
1147	sz := len(elems) * i
1148	if sz < 0 || sz >= maxAlloc { // sz < 0 => overflow
1149		// Don't print sz.
1150		return nil, fmt.Errorf("excessive repeat (%d * %d elements)", len(elems), i)
1151	}
1152	res := make([]Value, sz)
1153	// copy elems into res, doubling each time
1154	x := copy(res, elems)
1155	for x < len(res) {
1156		copy(res[x:], res[:x])
1157		x *= 2
1158	}
1159	return res, nil
1160}
1161
1162func bytesRepeat(b Bytes, n Int) (Bytes, error) {
1163	res, err := stringRepeat(String(b), n)
1164	return Bytes(res), err
1165}
1166
1167func stringRepeat(s String, n Int) (String, error) {
1168	if s == "" {
1169		return "", nil
1170	}
1171	i, err := AsInt32(n)
1172	if err != nil {
1173		return "", fmt.Errorf("repeat count %s too large", n)
1174	}
1175	if i < 1 {
1176		return "", nil
1177	}
1178	// Inv: i > 0, len > 0
1179	sz := len(s) * i
1180	if sz < 0 || sz >= maxAlloc { // sz < 0 => overflow
1181		// Don't print sz.
1182		return "", fmt.Errorf("excessive repeat (%d * %d elements)", len(s), i)
1183	}
1184	return String(strings.Repeat(string(s), i)), nil
1185}
1186
1187// Call calls the function fn with the specified positional and keyword arguments.
1188func Call(thread *Thread, fn Value, args Tuple, kwargs []Tuple) (Value, error) {
1189	c, ok := fn.(Callable)
1190	if !ok {
1191		return nil, fmt.Errorf("invalid call of non-function (%s)", fn.Type())
1192	}
1193
1194	// Allocate and push a new frame.
1195	var fr *frame
1196	// Optimization: use slack portion of thread.stack
1197	// slice as a freelist of empty frames.
1198	if n := len(thread.stack); n < cap(thread.stack) {
1199		fr = thread.stack[n : n+1][0]
1200	}
1201	if fr == nil {
1202		fr = new(frame)
1203	}
1204
1205	if thread.stack == nil {
1206		// one-time initialization of thread
1207		if thread.maxSteps == 0 {
1208			thread.maxSteps-- // (MaxUint64)
1209		}
1210	}
1211
1212	thread.stack = append(thread.stack, fr) // push
1213
1214	fr.callable = c
1215
1216	thread.beginProfSpan()
1217	result, err := c.CallInternal(thread, args, kwargs)
1218	thread.endProfSpan()
1219
1220	// Sanity check: nil is not a valid Starlark value.
1221	if result == nil && err == nil {
1222		err = fmt.Errorf("internal error: nil (not None) returned from %s", fn)
1223	}
1224
1225	// Always return an EvalError with an accurate frame.
1226	if err != nil {
1227		if _, ok := err.(*EvalError); !ok {
1228			err = thread.evalError(err)
1229		}
1230	}
1231
1232	*fr = frame{}                                     // clear out any references
1233	thread.stack = thread.stack[:len(thread.stack)-1] // pop
1234
1235	return result, err
1236}
1237
1238func slice(x, lo, hi, step_ Value) (Value, error) {
1239	sliceable, ok := x.(Sliceable)
1240	if !ok {
1241		return nil, fmt.Errorf("invalid slice operand %s", x.Type())
1242	}
1243
1244	n := sliceable.Len()
1245	step := 1
1246	if step_ != None {
1247		var err error
1248		step, err = AsInt32(step_)
1249		if err != nil {
1250			return nil, fmt.Errorf("invalid slice step: %s", err)
1251		}
1252		if step == 0 {
1253			return nil, fmt.Errorf("zero is not a valid slice step")
1254		}
1255	}
1256
1257	// TODO(adonovan): opt: preallocate result array.
1258
1259	var start, end int
1260	if step > 0 {
1261		// positive stride
1262		// default indices are [0:n].
1263		var err error
1264		start, end, err = indices(lo, hi, n)
1265		if err != nil {
1266			return nil, err
1267		}
1268
1269		if end < start {
1270			end = start // => empty result
1271		}
1272	} else {
1273		// negative stride
1274		// default indices are effectively [n-1:-1], though to
1275		// get this effect using explicit indices requires
1276		// [n-1:-1-n:-1] because of the treatment of -ve values.
1277		start = n - 1
1278		if err := asIndex(lo, n, &start); err != nil {
1279			return nil, fmt.Errorf("invalid start index: %s", err)
1280		}
1281		if start >= n {
1282			start = n - 1
1283		}
1284
1285		end = -1
1286		if err := asIndex(hi, n, &end); err != nil {
1287			return nil, fmt.Errorf("invalid end index: %s", err)
1288		}
1289		if end < -1 {
1290			end = -1
1291		}
1292
1293		if start < end {
1294			start = end // => empty result
1295		}
1296	}
1297
1298	return sliceable.Slice(start, end, step), nil
1299}
1300
1301// From Hacker's Delight, section 2.8.
1302func signum64(x int64) int { return int(uint64(x>>63) | uint64(-x)>>63) }
1303func signum(x int) int     { return signum64(int64(x)) }
1304
1305// indices converts start_ and end_ to indices in the range [0:len].
1306// The start index defaults to 0 and the end index defaults to len.
1307// An index -len < i < 0 is treated like i+len.
1308// All other indices outside the range are clamped to the nearest value in the range.
1309// Beware: start may be greater than end.
1310// This function is suitable only for slices with positive strides.
1311func indices(start_, end_ Value, len int) (start, end int, err error) {
1312	start = 0
1313	if err := asIndex(start_, len, &start); err != nil {
1314		return 0, 0, fmt.Errorf("invalid start index: %s", err)
1315	}
1316	// Clamp to [0:len].
1317	if start < 0 {
1318		start = 0
1319	} else if start > len {
1320		start = len
1321	}
1322
1323	end = len
1324	if err := asIndex(end_, len, &end); err != nil {
1325		return 0, 0, fmt.Errorf("invalid end index: %s", err)
1326	}
1327	// Clamp to [0:len].
1328	if end < 0 {
1329		end = 0
1330	} else if end > len {
1331		end = len
1332	}
1333
1334	return start, end, nil
1335}
1336
1337// asIndex sets *result to the integer value of v, adding len to it
1338// if it is negative.  If v is nil or None, *result is unchanged.
1339func asIndex(v Value, len int, result *int) error {
1340	if v != nil && v != None {
1341		var err error
1342		*result, err = AsInt32(v)
1343		if err != nil {
1344			return err
1345		}
1346		if *result < 0 {
1347			*result += len
1348		}
1349	}
1350	return nil
1351}
1352
1353// setArgs sets the values of the formal parameters of function fn in
1354// based on the actual parameter values in args and kwargs.
1355func setArgs(locals []Value, fn *Function, args Tuple, kwargs []Tuple) error {
1356
1357	// This is the general schema of a function:
1358	//
1359	//   def f(p1, p2=dp2, p3=dp3, *args, k1, k2=dk2, k3, **kwargs)
1360	//
1361	// The p parameters are non-kwonly, and may be specified positionally.
1362	// The k parameters are kwonly, and must be specified by name.
1363	// The defaults tuple is (dp2, dp3, mandatory, dk2, mandatory).
1364	//
1365	// Arguments are processed as follows:
1366	// - positional arguments are bound to a prefix of [p1, p2, p3].
1367	// - surplus positional arguments are bound to *args.
1368	// - keyword arguments are bound to any of {p1, p2, p3, k1, k2, k3};
1369	//   duplicate bindings are rejected.
1370	// - surplus keyword arguments are bound to **kwargs.
1371	// - defaults are bound to each parameter from p2 to k3 if no value was set.
1372	//   default values come from the tuple above.
1373	//   It is an error if the tuple entry for an unset parameter is 'mandatory'.
1374
1375	// Nullary function?
1376	if fn.NumParams() == 0 {
1377		if nactual := len(args) + len(kwargs); nactual > 0 {
1378			return fmt.Errorf("function %s accepts no arguments (%d given)", fn.Name(), nactual)
1379		}
1380		return nil
1381	}
1382
1383	cond := func(x bool, y, z interface{}) interface{} {
1384		if x {
1385			return y
1386		}
1387		return z
1388	}
1389
1390	// nparams is the number of ordinary parameters (sans *args and **kwargs).
1391	nparams := fn.NumParams()
1392	var kwdict *Dict
1393	if fn.HasKwargs() {
1394		nparams--
1395		kwdict = new(Dict)
1396		locals[nparams] = kwdict
1397	}
1398	if fn.HasVarargs() {
1399		nparams--
1400	}
1401
1402	// nonkwonly is the number of non-kwonly parameters.
1403	nonkwonly := nparams - fn.NumKwonlyParams()
1404
1405	// Too many positional args?
1406	n := len(args)
1407	if len(args) > nonkwonly {
1408		if !fn.HasVarargs() {
1409			return fmt.Errorf("function %s accepts %s%d positional argument%s (%d given)",
1410				fn.Name(),
1411				cond(len(fn.defaults) > fn.NumKwonlyParams(), "at most ", ""),
1412				nonkwonly,
1413				cond(nonkwonly == 1, "", "s"),
1414				len(args))
1415		}
1416		n = nonkwonly
1417	}
1418
1419	// Bind positional arguments to non-kwonly parameters.
1420	for i := 0; i < n; i++ {
1421		locals[i] = args[i]
1422	}
1423
1424	// Bind surplus positional arguments to *args parameter.
1425	if fn.HasVarargs() {
1426		tuple := make(Tuple, len(args)-n)
1427		for i := n; i < len(args); i++ {
1428			tuple[i-n] = args[i]
1429		}
1430		locals[nparams] = tuple
1431	}
1432
1433	// Bind keyword arguments to parameters.
1434	paramIdents := fn.funcode.Locals[:nparams]
1435	for _, pair := range kwargs {
1436		k, v := pair[0].(String), pair[1]
1437		if i := findParam(paramIdents, string(k)); i >= 0 {
1438			if locals[i] != nil {
1439				return fmt.Errorf("function %s got multiple values for parameter %s", fn.Name(), k)
1440			}
1441			locals[i] = v
1442			continue
1443		}
1444		if kwdict == nil {
1445			return fmt.Errorf("function %s got an unexpected keyword argument %s", fn.Name(), k)
1446		}
1447		oldlen := kwdict.Len()
1448		kwdict.SetKey(k, v)
1449		if kwdict.Len() == oldlen {
1450			return fmt.Errorf("function %s got multiple values for parameter %s", fn.Name(), k)
1451		}
1452	}
1453
1454	// Are defaults required?
1455	if n < nparams || fn.NumKwonlyParams() > 0 {
1456		m := nparams - len(fn.defaults) // first default
1457
1458		// Report errors for missing required arguments.
1459		var missing []string
1460		var i int
1461		for i = n; i < m; i++ {
1462			if locals[i] == nil {
1463				missing = append(missing, paramIdents[i].Name)
1464			}
1465		}
1466
1467		// Bind default values to parameters.
1468		for ; i < nparams; i++ {
1469			if locals[i] == nil {
1470				dflt := fn.defaults[i-m]
1471				if _, ok := dflt.(mandatory); ok {
1472					missing = append(missing, paramIdents[i].Name)
1473					continue
1474				}
1475				locals[i] = dflt
1476			}
1477		}
1478
1479		if missing != nil {
1480			return fmt.Errorf("function %s missing %d argument%s (%s)",
1481				fn.Name(), len(missing), cond(len(missing) > 1, "s", ""), strings.Join(missing, ", "))
1482		}
1483	}
1484	return nil
1485}
1486
1487func findParam(params []compile.Binding, name string) int {
1488	for i, param := range params {
1489		if param.Name == name {
1490			return i
1491		}
1492	}
1493	return -1
1494}
1495
1496// https://github.com/google/starlark-go/blob/master/doc/spec.md#string-interpolation
1497func interpolate(format string, x Value) (Value, error) {
1498	buf := new(strings.Builder)
1499	index := 0
1500	nargs := 1
1501	if tuple, ok := x.(Tuple); ok {
1502		nargs = len(tuple)
1503	}
1504	for {
1505		i := strings.IndexByte(format, '%')
1506		if i < 0 {
1507			buf.WriteString(format)
1508			break
1509		}
1510		buf.WriteString(format[:i])
1511		format = format[i+1:]
1512
1513		if format != "" && format[0] == '%' {
1514			buf.WriteByte('%')
1515			format = format[1:]
1516			continue
1517		}
1518
1519		var arg Value
1520		if format != "" && format[0] == '(' {
1521			// keyword argument: %(name)s.
1522			format = format[1:]
1523			j := strings.IndexByte(format, ')')
1524			if j < 0 {
1525				return nil, fmt.Errorf("incomplete format key")
1526			}
1527			key := format[:j]
1528			if dict, ok := x.(Mapping); !ok {
1529				return nil, fmt.Errorf("format requires a mapping")
1530			} else if v, found, _ := dict.Get(String(key)); found {
1531				arg = v
1532			} else {
1533				return nil, fmt.Errorf("key not found: %s", key)
1534			}
1535			format = format[j+1:]
1536		} else {
1537			// positional argument: %s.
1538			if index >= nargs {
1539				return nil, fmt.Errorf("not enough arguments for format string")
1540			}
1541			if tuple, ok := x.(Tuple); ok {
1542				arg = tuple[index]
1543			} else {
1544				arg = x
1545			}
1546		}
1547
1548		// NOTE: Starlark does not support any of these optional Python features:
1549		// - optional conversion flags: [#0- +], etc.
1550		// - optional minimum field width (number or *).
1551		// - optional precision (.123 or *)
1552		// - optional length modifier
1553
1554		// conversion type
1555		if format == "" {
1556			return nil, fmt.Errorf("incomplete format")
1557		}
1558		switch c := format[0]; c {
1559		case 's', 'r':
1560			if str, ok := AsString(arg); ok && c == 's' {
1561				buf.WriteString(str)
1562			} else {
1563				writeValue(buf, arg, nil)
1564			}
1565		case 'd', 'i', 'o', 'x', 'X':
1566			i, err := NumberToInt(arg)
1567			if err != nil {
1568				return nil, fmt.Errorf("%%%c format requires integer: %v", c, err)
1569			}
1570			switch c {
1571			case 'd', 'i':
1572				fmt.Fprintf(buf, "%d", i)
1573			case 'o':
1574				fmt.Fprintf(buf, "%o", i)
1575			case 'x':
1576				fmt.Fprintf(buf, "%x", i)
1577			case 'X':
1578				fmt.Fprintf(buf, "%X", i)
1579			}
1580		case 'e', 'f', 'g', 'E', 'F', 'G':
1581			f, ok := AsFloat(arg)
1582			if !ok {
1583				return nil, fmt.Errorf("%%%c format requires float, not %s", c, arg.Type())
1584			}
1585			Float(f).format(buf, c)
1586		case 'c':
1587			switch arg := arg.(type) {
1588			case Int:
1589				// chr(int)
1590				r, err := AsInt32(arg)
1591				if err != nil || r < 0 || r > unicode.MaxRune {
1592					return nil, fmt.Errorf("%%c format requires a valid Unicode code point, got %s", arg)
1593				}
1594				buf.WriteRune(rune(r))
1595			case String:
1596				r, size := utf8.DecodeRuneInString(string(arg))
1597				if size != len(arg) || len(arg) == 0 {
1598					return nil, fmt.Errorf("%%c format requires a single-character string")
1599				}
1600				buf.WriteRune(r)
1601			default:
1602				return nil, fmt.Errorf("%%c format requires int or single-character string, not %s", arg.Type())
1603			}
1604		case '%':
1605			buf.WriteByte('%')
1606		default:
1607			return nil, fmt.Errorf("unknown conversion %%%c", c)
1608		}
1609		format = format[1:]
1610		index++
1611	}
1612
1613	if index < nargs {
1614		return nil, fmt.Errorf("too many arguments for format string")
1615	}
1616
1617	return String(buf.String()), nil
1618}
1619