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