github.com/k14s/starlark-go@v0.0.0-20200720175618-3a5c849cc368/starlark/eval.go (about)

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