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