github.com/google/skylark@v0.0.0-20181101142754-a5f7082aabed/library.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 skylark 6 7 // This file defines the library of built-ins. 8 // 9 // Built-ins must explicitly check the "frozen" flag before updating 10 // mutable types such as lists and dicts. 11 12 import ( 13 "bytes" 14 "fmt" 15 "log" 16 "math/big" 17 "os" 18 "reflect" 19 "sort" 20 "strconv" 21 "strings" 22 "unicode" 23 "unicode/utf8" 24 25 "github.com/google/skylark/syntax" 26 ) 27 28 // Universe defines the set of universal built-ins, such as None, True, and len. 29 // 30 // The Go application may add or remove items from the 31 // universe dictionary before Skylark evaluation begins. 32 // All values in the dictionary must be immutable. 33 // Skylark programs cannot modify the dictionary. 34 var Universe StringDict 35 36 func init() { 37 // https://github.com/google/skylark/blob/master/doc/spec.md#built-in-constants-and-functions 38 Universe = StringDict{ 39 "None": None, 40 "True": True, 41 "False": False, 42 "any": NewBuiltin("any", any), 43 "all": NewBuiltin("all", all), 44 "bool": NewBuiltin("bool", bool_), 45 "chr": NewBuiltin("chr", chr), 46 "dict": NewBuiltin("dict", dict), 47 "dir": NewBuiltin("dir", dir), 48 "enumerate": NewBuiltin("enumerate", enumerate), 49 "float": NewBuiltin("float", float), // requires resolve.AllowFloat 50 "getattr": NewBuiltin("getattr", getattr), 51 "hasattr": NewBuiltin("hasattr", hasattr), 52 "hash": NewBuiltin("hash", hash), 53 "int": NewBuiltin("int", int_), 54 "len": NewBuiltin("len", len_), 55 "list": NewBuiltin("list", list), 56 "max": NewBuiltin("max", minmax), 57 "min": NewBuiltin("min", minmax), 58 "ord": NewBuiltin("ord", ord), 59 "print": NewBuiltin("print", print), 60 "range": NewBuiltin("range", range_), 61 "repr": NewBuiltin("repr", repr), 62 "reversed": NewBuiltin("reversed", reversed), 63 "set": NewBuiltin("set", set), // requires resolve.AllowSet 64 "sorted": NewBuiltin("sorted", sorted), 65 "str": NewBuiltin("str", str), 66 "tuple": NewBuiltin("tuple", tuple), 67 "type": NewBuiltin("type", type_), 68 "zip": NewBuiltin("zip", zip), 69 } 70 } 71 72 type builtinMethod func(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) 73 74 // methods of built-in types 75 // https://github.com/google/skylark/blob/master/doc/spec.md#built-in-methods 76 var ( 77 dictMethods = map[string]builtinMethod{ 78 "clear": dict_clear, 79 "get": dict_get, 80 "items": dict_items, 81 "keys": dict_keys, 82 "pop": dict_pop, 83 "popitem": dict_popitem, 84 "setdefault": dict_setdefault, 85 "update": dict_update, 86 "values": dict_values, 87 } 88 89 listMethods = map[string]builtinMethod{ 90 "append": list_append, 91 "clear": list_clear, 92 "extend": list_extend, 93 "index": list_index, 94 "insert": list_insert, 95 "pop": list_pop, 96 "remove": list_remove, 97 } 98 99 stringMethods = map[string]builtinMethod{ 100 "capitalize": string_capitalize, 101 "codepoint_ords": string_iterable, 102 "codepoints": string_iterable, // sic 103 "count": string_count, 104 "elem_ords": string_iterable, 105 "elems": string_iterable, // sic 106 "endswith": string_startswith, // sic 107 "find": string_find, 108 "format": string_format, 109 "index": string_index, 110 "isalnum": string_isalnum, 111 "isalpha": string_isalpha, 112 "isdigit": string_isdigit, 113 "islower": string_islower, 114 "isspace": string_isspace, 115 "istitle": string_istitle, 116 "isupper": string_isupper, 117 "join": string_join, 118 "lower": string_lower, 119 "lstrip": string_strip, // sic 120 "partition": string_partition, 121 "replace": string_replace, 122 "rfind": string_rfind, 123 "rindex": string_rindex, 124 "rpartition": string_partition, // sic 125 "rsplit": string_split, // sic 126 "rstrip": string_strip, // sic 127 "split": string_split, 128 "splitlines": string_splitlines, 129 "startswith": string_startswith, 130 "strip": string_strip, 131 "title": string_title, 132 "upper": string_upper, 133 } 134 135 setMethods = map[string]builtinMethod{ 136 "union": set_union, 137 } 138 ) 139 140 func builtinMethodOf(recv Value, name string) builtinMethod { 141 switch recv.(type) { 142 case String: 143 return stringMethods[name] 144 case *List: 145 return listMethods[name] 146 case *Dict: 147 return dictMethods[name] 148 case *Set: 149 return setMethods[name] 150 } 151 return nil 152 } 153 154 func builtinAttr(recv Value, name string, methods map[string]builtinMethod) (Value, error) { 155 method := methods[name] 156 if method == nil { 157 return nil, nil // no such method 158 } 159 160 // Allocate a closure over 'method'. 161 impl := func(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 162 return method(b.Name(), b.Receiver(), args, kwargs) 163 } 164 return NewBuiltin(name, impl).BindReceiver(recv), nil 165 } 166 167 func builtinAttrNames(methods map[string]builtinMethod) []string { 168 names := make([]string, 0, len(methods)) 169 for name := range methods { 170 names = append(names, name) 171 } 172 sort.Strings(names) 173 return names 174 } 175 176 // UnpackArgs unpacks the positional and keyword arguments into the 177 // supplied parameter variables. pairs is an alternating list of names 178 // and pointers to variables. 179 // 180 // If the variable is a bool, int, string, *List, *Dict, Callable, 181 // Iterable, or user-defined implementation of Value, 182 // UnpackArgs performs the appropriate type check. 183 // (An int uses the AsInt32 check.) 184 // If the parameter name ends with "?", 185 // it and all following parameters are optional. 186 // 187 // If the variable implements Value, UnpackArgs may call 188 // its Type() method while constructing the error message. 189 // 190 // Beware: an optional *List, *Dict, Callable, Iterable, or Value variable that is 191 // not assigned is not a valid Skylark Value, so the caller must 192 // explicitly handle such cases by interpreting nil as None or some 193 // computed default. 194 func UnpackArgs(fnname string, args Tuple, kwargs []Tuple, pairs ...interface{}) error { 195 nparams := len(pairs) / 2 196 var defined intset 197 defined.init(nparams) 198 199 // positional arguments 200 if len(args) > nparams { 201 return fmt.Errorf("%s: got %d arguments, want at most %d", 202 fnname, len(args), nparams) 203 } 204 for i, arg := range args { 205 defined.set(i) 206 if err := unpackOneArg(arg, pairs[2*i+1]); err != nil { 207 return fmt.Errorf("%s: for parameter %d: %s", fnname, i+1, err) 208 } 209 } 210 211 // keyword arguments 212 kwloop: 213 for _, item := range kwargs { 214 name, arg := item[0].(String), item[1] 215 for i := 0; i < nparams; i++ { 216 paramName := pairs[2*i].(string) 217 if paramName[len(paramName)-1] == '?' { 218 paramName = paramName[:len(paramName)-1] 219 } 220 if paramName == string(name) { 221 // found it 222 if defined.set(i) { 223 return fmt.Errorf("%s: got multiple values for keyword argument %s", 224 fnname, name) 225 } 226 ptr := pairs[2*i+1] 227 if err := unpackOneArg(arg, ptr); err != nil { 228 return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err) 229 } 230 continue kwloop 231 } 232 } 233 return fmt.Errorf("%s: unexpected keyword argument %s", fnname, name) 234 } 235 236 // Check that all non-optional parameters are defined. 237 // (We needn't check the first len(args).) 238 for i := len(args); i < nparams; i++ { 239 name := pairs[2*i].(string) 240 if strings.HasSuffix(name, "?") { 241 break // optional 242 } 243 if !defined.get(i) { 244 return fmt.Errorf("%s: missing argument for %s", fnname, name) 245 } 246 } 247 248 return nil 249 } 250 251 // UnpackPositionalArgs unpacks the positional arguments into 252 // corresponding variables. Each element of vars is a pointer; see 253 // UnpackArgs for allowed types and conversions. 254 // 255 // UnpackPositionalArgs reports an error if the number of arguments is 256 // less than min or greater than len(vars), if kwargs is nonempty, or if 257 // any conversion fails. 258 func UnpackPositionalArgs(fnname string, args Tuple, kwargs []Tuple, min int, vars ...interface{}) error { 259 if len(kwargs) > 0 { 260 return fmt.Errorf("%s: unexpected keyword arguments", fnname) 261 } 262 max := len(vars) 263 if len(args) < min { 264 var atleast string 265 if min < max { 266 atleast = "at least " 267 } 268 return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atleast, min) 269 } 270 if len(args) > max { 271 var atmost string 272 if max > min { 273 atmost = "at most " 274 } 275 return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atmost, max) 276 } 277 for i, arg := range args { 278 if err := unpackOneArg(arg, vars[i]); err != nil { 279 return fmt.Errorf("%s: for parameter %d: %s", fnname, i+1, err) 280 } 281 } 282 return nil 283 } 284 285 func unpackOneArg(v Value, ptr interface{}) error { 286 ok := true 287 switch ptr := ptr.(type) { 288 case *Value: 289 *ptr = v 290 case *string: 291 *ptr, ok = AsString(v) 292 if !ok { 293 return fmt.Errorf("got %s, want string", v.Type()) 294 } 295 case *bool: 296 *ptr = bool(v.Truth()) 297 case *int: 298 var err error 299 *ptr, err = AsInt32(v) 300 if err != nil { 301 return err 302 } 303 case **List: 304 *ptr, ok = v.(*List) 305 if !ok { 306 return fmt.Errorf("got %s, want list", v.Type()) 307 } 308 case **Dict: 309 *ptr, ok = v.(*Dict) 310 if !ok { 311 return fmt.Errorf("got %s, want dict", v.Type()) 312 } 313 case *Callable: 314 *ptr, ok = v.(Callable) 315 if !ok { 316 return fmt.Errorf("got %s, want callable", v.Type()) 317 } 318 case *Iterable: 319 *ptr, ok = v.(Iterable) 320 if !ok { 321 return fmt.Errorf("got %s, want iterable", v.Type()) 322 } 323 default: 324 ptrv := reflect.ValueOf(ptr) 325 if ptrv.Kind() != reflect.Ptr { 326 log.Fatalf("internal error: not a pointer: %T", ptr) 327 } 328 param := ptrv.Elem() 329 if !reflect.TypeOf(v).AssignableTo(param.Type()) { 330 // Detect mistakes by caller. 331 if !param.Type().AssignableTo(reflect.TypeOf(new(Value)).Elem()) { 332 log.Fatalf("internal error: invalid pointer type: %T", ptr) 333 } 334 // Assume it's safe to call Type() on a zero instance. 335 paramType := param.Interface().(Value).Type() 336 return fmt.Errorf("got %s, want %s", v.Type(), paramType) 337 } 338 param.Set(reflect.ValueOf(v)) 339 } 340 return nil 341 } 342 343 // ---- built-in functions ---- 344 345 // https://github.com/google/skylark/blob/master/doc/spec.md#all 346 func all(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 347 var iterable Iterable 348 if err := UnpackPositionalArgs("all", args, kwargs, 1, &iterable); err != nil { 349 return nil, err 350 } 351 iter := iterable.Iterate() 352 defer iter.Done() 353 var x Value 354 for iter.Next(&x) { 355 if !x.Truth() { 356 return False, nil 357 } 358 } 359 return True, nil 360 } 361 362 // https://github.com/google/skylark/blob/master/doc/spec.md#any 363 func any(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 364 var iterable Iterable 365 if err := UnpackPositionalArgs("all", args, kwargs, 1, &iterable); err != nil { 366 return nil, err 367 } 368 iter := iterable.Iterate() 369 defer iter.Done() 370 var x Value 371 for iter.Next(&x) { 372 if x.Truth() { 373 return True, nil 374 } 375 } 376 return False, nil 377 } 378 379 // https://github.com/google/skylark/blob/master/doc/spec.md#bool 380 func bool_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 381 var x Value = False 382 if err := UnpackPositionalArgs("bool", args, kwargs, 0, &x); err != nil { 383 return nil, err 384 } 385 return x.Truth(), nil 386 } 387 388 // https://github.com/google/skylark/blob/master/doc/spec.md#chr 389 func chr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 390 if len(kwargs) > 0 { 391 return nil, fmt.Errorf("chr does not accept keyword arguments") 392 } 393 if len(args) != 1 { 394 return nil, fmt.Errorf("chr: got %d arguments, want 1", len(args)) 395 } 396 i, err := AsInt32(args[0]) 397 if err != nil { 398 return nil, fmt.Errorf("chr: got %s, want int", args[0].Type()) 399 } 400 if i < 0 { 401 return nil, fmt.Errorf("chr: Unicode code point %d out of range (<0)", i) 402 } 403 if i > unicode.MaxRune { 404 return nil, fmt.Errorf("chr: Unicode code point U+%X out of range (>0x10FFFF)", i) 405 } 406 return String(string(i)), nil 407 } 408 409 // https://github.com/google/skylark/blob/master/doc/spec.md#dict 410 func dict(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 411 if len(args) > 1 { 412 return nil, fmt.Errorf("dict: got %d arguments, want at most 1", len(args)) 413 } 414 dict := new(Dict) 415 if err := updateDict(dict, args, kwargs); err != nil { 416 return nil, fmt.Errorf("dict: %v", err) 417 } 418 return dict, nil 419 } 420 421 // https://github.com/google/skylark/blob/master/doc/spec.md#dir 422 func dir(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 423 if len(kwargs) > 0 { 424 return nil, fmt.Errorf("dir does not accept keyword arguments") 425 } 426 if len(args) != 1 { 427 return nil, fmt.Errorf("dir: got %d arguments, want 1", len(args)) 428 } 429 430 var names []string 431 if x, ok := args[0].(HasAttrs); ok { 432 names = x.AttrNames() 433 } 434 elems := make([]Value, len(names)) 435 for i, name := range names { 436 elems[i] = String(name) 437 } 438 return NewList(elems), nil 439 } 440 441 // https://github.com/google/skylark/blob/master/doc/spec.md#enumerate 442 func enumerate(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 443 var iterable Iterable 444 var start int 445 if err := UnpackPositionalArgs("enumerate", args, kwargs, 1, &iterable, &start); err != nil { 446 return nil, err 447 } 448 449 iter := iterable.Iterate() 450 if iter == nil { 451 return nil, fmt.Errorf("enumerate: got %s, want iterable", iterable.Type()) 452 } 453 defer iter.Done() 454 455 var pairs []Value 456 var x Value 457 458 if n := Len(iterable); n >= 0 { 459 // common case: known length 460 pairs = make([]Value, 0, n) 461 array := make(Tuple, 2*n) // allocate a single backing array 462 for i := 0; iter.Next(&x); i++ { 463 pair := array[:2:2] 464 array = array[2:] 465 pair[0] = MakeInt(start + i) 466 pair[1] = x 467 pairs = append(pairs, pair) 468 } 469 } else { 470 // non-sequence (unknown length) 471 for i := 0; iter.Next(&x); i++ { 472 pair := Tuple{MakeInt(start + i), x} 473 pairs = append(pairs, pair) 474 } 475 } 476 477 return NewList(pairs), nil 478 } 479 480 func float(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 481 if len(kwargs) > 0 { 482 return nil, fmt.Errorf("float does not accept keyword arguments") 483 } 484 if len(args) == 0 { 485 return Float(0.0), nil 486 } 487 if len(args) != 1 { 488 return nil, fmt.Errorf("float got %d arguments, wants 1", len(args)) 489 } 490 switch x := args[0].(type) { 491 case Bool: 492 if x { 493 return Float(1.0), nil 494 } else { 495 return Float(0.0), nil 496 } 497 case Int: 498 return x.Float(), nil 499 case Float: 500 return x, nil 501 case String: 502 f, err := strconv.ParseFloat(string(x), 64) 503 if err != nil { 504 return nil, err 505 } 506 return Float(f), nil 507 default: 508 return nil, fmt.Errorf("float got %s, want number or string", x.Type()) 509 } 510 } 511 512 // https://github.com/google/skylark/blob/master/doc/spec.md#getattr 513 func getattr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 514 var object, dflt Value 515 var name string 516 if err := UnpackPositionalArgs("getattr", args, kwargs, 2, &object, &name, &dflt); err != nil { 517 return nil, err 518 } 519 if object, ok := object.(HasAttrs); ok { 520 v, err := object.Attr(name) 521 if err != nil { 522 // An error could mean the field doesn't exist, 523 // or it exists but could not be computed. 524 if dflt != nil { 525 return dflt, nil 526 } 527 return nil, err 528 } 529 if v != nil { 530 return v, nil 531 } 532 // (nil, nil) => no such field 533 } 534 if dflt != nil { 535 return dflt, nil 536 } 537 return nil, fmt.Errorf("%s has no .%s field or method", object.Type(), name) 538 } 539 540 // https://github.com/google/skylark/blob/master/doc/spec.md#hasattr 541 func hasattr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 542 var object Value 543 var name string 544 if err := UnpackPositionalArgs("hasattr", args, kwargs, 2, &object, &name); err != nil { 545 return nil, err 546 } 547 if object, ok := object.(HasAttrs); ok { 548 v, err := object.Attr(name) 549 if err == nil { 550 return Bool(v != nil), nil 551 } 552 553 // An error does not conclusively indicate presence or 554 // absence of a field: it could occur while computing 555 // the value of a present attribute, or it could be a 556 // "no such attribute" error with details. 557 for _, x := range object.AttrNames() { 558 if x == name { 559 return True, nil 560 } 561 } 562 } 563 return False, nil 564 } 565 566 // https://github.com/google/skylark/blob/master/doc/spec.md#hash 567 func hash(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 568 var x Value 569 if err := UnpackPositionalArgs("hash", args, kwargs, 1, &x); err != nil { 570 return nil, err 571 } 572 h, err := x.Hash() 573 return MakeUint(uint(h)), err 574 } 575 576 // https://github.com/google/skylark/blob/master/doc/spec.md#int 577 func int_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 578 var x Value = zero 579 var base Value 580 if err := UnpackArgs("int", args, kwargs, "x", &x, "base?", &base); err != nil { 581 return nil, err 582 } 583 584 // "If x is not a number or base is given, x must be a string." 585 if s, ok := AsString(x); ok { 586 b := 10 587 if base != nil { 588 var err error 589 b, err = AsInt32(base) 590 if err != nil || b != 0 && (b < 2 || b > 36) { 591 return nil, fmt.Errorf("int: base must be an integer >= 2 && <= 36") 592 } 593 } 594 595 orig := s // save original for error message 596 597 if len(s) > 1 { 598 var sign string 599 i := 0 600 if s[0] == '+' || s[0] == '-' { 601 sign = s[:1] 602 i++ 603 } 604 605 if i < len(s) && s[i] == '0' { 606 hasbase := 0 607 if i+2 < len(s) { 608 switch s[i+1] { 609 case 'o', 'O': 610 // SetString doesn't understand "0o755" 611 // so modify s to "0755". 612 // Octals are rare, so allocation is fine. 613 s = sign + "0" + s[i+2:] 614 hasbase = 8 615 case 'x', 'X': 616 hasbase = 16 617 case 'b', 'B': 618 hasbase = 2 619 } 620 621 if hasbase != 0 && b != 0 { 622 // Explicit base doesn't match prefix, 623 // e.g. int("0o755", 16). 624 if hasbase != b { 625 goto invalid 626 } 627 628 // SetString requires base=0 629 // if there's a base prefix. 630 b = 0 631 } 632 } 633 634 // For automatic base detection, 635 // a string starting with zero 636 // must be all zeros. 637 // Thus we reject "0755". 638 if hasbase == 0 && b == 0 { 639 for ; i < len(s); i++ { 640 if s[i] != '0' { 641 goto invalid 642 } 643 } 644 } 645 } 646 } 647 648 // NOTE: int(x) permits arbitrary precision, unlike the scanner. 649 if i, ok := new(big.Int).SetString(s, b); ok { 650 return Int{i}, nil 651 } 652 653 invalid: 654 return nil, fmt.Errorf("int: invalid literal with base %d: %s", b, orig) 655 } 656 657 if base != nil { 658 return nil, fmt.Errorf("int: can't convert non-string with explicit base") 659 } 660 661 if b, ok := x.(Bool); ok { 662 if b { 663 return one, nil 664 } else { 665 return zero, nil 666 } 667 } 668 669 i, err := NumberToInt(x) 670 if err != nil { 671 return nil, fmt.Errorf("int: %s", err) 672 } 673 return i, nil 674 } 675 676 // https://github.com/google/skylark/blob/master/doc/spec.md#len 677 func len_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 678 var x Value 679 if err := UnpackPositionalArgs("len", args, kwargs, 1, &x); err != nil { 680 return nil, err 681 } 682 len := Len(x) 683 if len < 0 { 684 return nil, fmt.Errorf("value of type %s has no len", x.Type()) 685 } 686 return MakeInt(len), nil 687 } 688 689 // https://github.com/google/skylark/blob/master/doc/spec.md#list 690 func list(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 691 var iterable Iterable 692 if err := UnpackPositionalArgs("list", args, kwargs, 0, &iterable); err != nil { 693 return nil, err 694 } 695 var elems []Value 696 if iterable != nil { 697 iter := iterable.Iterate() 698 defer iter.Done() 699 if n := Len(iterable); n > 0 { 700 elems = make([]Value, 0, n) // preallocate if length known 701 } 702 var x Value 703 for iter.Next(&x) { 704 elems = append(elems, x) 705 } 706 } 707 return NewList(elems), nil 708 } 709 710 // https://github.com/google/skylark/blob/master/doc/spec.md#min 711 func minmax(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 712 if len(args) == 0 { 713 return nil, fmt.Errorf("%s requires at least one positional argument", fn.Name()) 714 } 715 var keyFunc Callable 716 if err := UnpackArgs(fn.Name(), nil, kwargs, "key?", &keyFunc); err != nil { 717 return nil, err 718 } 719 var op syntax.Token 720 if fn.Name() == "max" { 721 op = syntax.GT 722 } else { 723 op = syntax.LT 724 } 725 var iterable Value 726 if len(args) == 1 { 727 iterable = args[0] 728 } else { 729 iterable = args 730 } 731 iter := Iterate(iterable) 732 if iter == nil { 733 return nil, fmt.Errorf("%s: %s value is not iterable", fn.Name(), iterable.Type()) 734 } 735 defer iter.Done() 736 var extremum Value 737 if !iter.Next(&extremum) { 738 return nil, fmt.Errorf("%s: argument is an empty sequence", fn.Name()) 739 } 740 741 var extremeKey Value 742 var keyargs Tuple 743 if keyFunc == nil { 744 extremeKey = extremum 745 } else { 746 keyargs = Tuple{extremum} 747 res, err := Call(thread, keyFunc, keyargs, nil) 748 if err != nil { 749 return nil, err 750 } 751 extremeKey = res 752 } 753 754 var x Value 755 for iter.Next(&x) { 756 var key Value 757 if keyFunc == nil { 758 key = x 759 } else { 760 keyargs[0] = x 761 res, err := Call(thread, keyFunc, keyargs, nil) 762 if err != nil { 763 return nil, err 764 } 765 key = res 766 } 767 768 if ok, err := Compare(op, key, extremeKey); err != nil { 769 return nil, err 770 } else if ok { 771 extremum = x 772 extremeKey = key 773 } 774 } 775 return extremum, nil 776 } 777 778 // https://github.com/google/skylark/blob/master/doc/spec.md#ord 779 func ord(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 780 if len(kwargs) > 0 { 781 return nil, fmt.Errorf("ord does not accept keyword arguments") 782 } 783 if len(args) != 1 { 784 return nil, fmt.Errorf("ord: got %d arguments, want 1", len(args)) 785 } 786 s, ok := AsString(args[0]) 787 if !ok { 788 return nil, fmt.Errorf("ord: got %s, want string", args[0].Type()) 789 } 790 r, sz := utf8.DecodeRuneInString(s) 791 if sz == 0 || sz != len(s) { 792 n := utf8.RuneCountInString(s) 793 return nil, fmt.Errorf("ord: string encodes %d Unicode code points, want 1", n) 794 } 795 return MakeInt(int(r)), nil 796 } 797 798 // https://github.com/google/skylark/blob/master/doc/spec.md#print 799 func print(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 800 var buf bytes.Buffer 801 path := make([]Value, 0, 4) 802 sep := "" 803 for _, v := range args { 804 buf.WriteString(sep) 805 if s, ok := AsString(v); ok { 806 buf.WriteString(s) 807 } else { 808 writeValue(&buf, v, path) 809 } 810 sep = " " 811 } 812 for _, pair := range kwargs { 813 buf.WriteString(sep) 814 buf.WriteString(string(pair[0].(String))) 815 buf.WriteString("=") 816 if s, ok := AsString(pair[1]); ok { 817 buf.WriteString(s) 818 } else { 819 writeValue(&buf, pair[1], path) 820 } 821 sep = " " 822 } 823 824 if thread.Print != nil { 825 thread.Print(thread, buf.String()) 826 } else { 827 fmt.Fprintln(os.Stderr, &buf) 828 } 829 return None, nil 830 } 831 832 // https://github.com/google/skylark/blob/master/doc/spec.md#range 833 func range_(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 834 var start, stop, step int 835 step = 1 836 if err := UnpackPositionalArgs("range", args, kwargs, 1, &start, &stop, &step); err != nil { 837 return nil, err 838 } 839 840 // TODO(adonovan): analyze overflow/underflows cases for 32-bit implementations. 841 842 var n int 843 switch len(args) { 844 case 1: 845 // range(stop) 846 start, stop = 0, start 847 fallthrough 848 case 2: 849 // range(start, stop) 850 if stop > start { 851 n = stop - start 852 } 853 case 3: 854 // range(start, stop, step) 855 switch { 856 case step > 0: 857 if stop > start { 858 n = (stop-1-start)/step + 1 859 } 860 case step < 0: 861 if start > stop { 862 n = (start-1-stop)/-step + 1 863 } 864 default: 865 return nil, fmt.Errorf("range: step argument must not be zero") 866 } 867 } 868 869 return rangeValue{start: start, stop: stop, step: step, len: n}, nil 870 } 871 872 // A rangeValue is a comparable, immutable, indexable sequence of integers 873 // defined by the three parameters to a range(...) call. 874 // Invariant: step != 0. 875 type rangeValue struct{ start, stop, step, len int } 876 877 var ( 878 _ Indexable = rangeValue{} 879 _ Sequence = rangeValue{} 880 _ Comparable = rangeValue{} 881 _ Sliceable = rangeValue{} 882 ) 883 884 func (r rangeValue) Len() int { return r.len } 885 func (r rangeValue) Index(i int) Value { return MakeInt(r.start + i*r.step) } 886 func (r rangeValue) Iterate() Iterator { return &rangeIterator{r, 0} } 887 888 func (r rangeValue) Slice(start, end, step int) Value { 889 newStart := r.start + r.step*start 890 newStop := r.start + r.step*end 891 newStep := r.step * step 892 var newLen int 893 if step > 0 { 894 newLen = (newStop-1-newStart)/newStep + 1 895 } else { 896 newLen = (newStart-1-newStop)/-newStep + 1 897 } 898 return rangeValue{ 899 start: newStart, 900 stop: newStop, 901 step: newStep, 902 len: newLen, 903 } 904 } 905 906 func (r rangeValue) Freeze() {} // immutable 907 func (r rangeValue) String() string { 908 if r.step != 1 { 909 return fmt.Sprintf("range(%d, %d, %d)", r.start, r.stop, r.step) 910 } else if r.start != 0 { 911 return fmt.Sprintf("range(%d, %d)", r.start, r.stop) 912 } else { 913 return fmt.Sprintf("range(%d)", r.stop) 914 } 915 } 916 func (r rangeValue) Type() string { return "range" } 917 func (r rangeValue) Truth() Bool { return r.len > 0 } 918 func (r rangeValue) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: range") } 919 920 func (x rangeValue) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 921 y := y_.(rangeValue) 922 switch op { 923 case syntax.EQL: 924 return rangeEqual(x, y), nil 925 case syntax.NEQ: 926 return !rangeEqual(x, y), nil 927 default: 928 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) 929 } 930 } 931 932 func rangeEqual(x, y rangeValue) bool { 933 // Two ranges compare equal if they denote the same sequence. 934 return x.len == y.len && 935 (x.len == 0 || x.start == y.start && x.step == y.step) 936 } 937 938 func (r rangeValue) contains(x Int) bool { 939 x32, err := AsInt32(x) 940 if err != nil { 941 return false // out of range 942 } 943 delta := x32 - r.start 944 quo, rem := delta/r.step, delta%r.step 945 return rem == 0 && 0 <= quo && quo < r.len 946 } 947 948 type rangeIterator struct { 949 r rangeValue 950 i int 951 } 952 953 func (it *rangeIterator) Next(p *Value) bool { 954 if it.i < it.r.len { 955 *p = it.r.Index(it.i) 956 it.i++ 957 return true 958 } 959 return false 960 } 961 func (*rangeIterator) Done() {} 962 963 // https://github.com/google/skylark/blob/master/doc/spec.md#repr 964 func repr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 965 var x Value 966 if err := UnpackPositionalArgs("repr", args, kwargs, 1, &x); err != nil { 967 return nil, err 968 } 969 return String(x.String()), nil 970 } 971 972 // https://github.com/google/skylark/blob/master/doc/spec.md#reversed 973 func reversed(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 974 var iterable Iterable 975 if err := UnpackPositionalArgs("reversed", args, kwargs, 1, &iterable); err != nil { 976 return nil, err 977 } 978 iter := iterable.Iterate() 979 defer iter.Done() 980 var elems []Value 981 if n := Len(args[0]); n >= 0 { 982 elems = make([]Value, 0, n) // preallocate if length known 983 } 984 var x Value 985 for iter.Next(&x) { 986 elems = append(elems, x) 987 } 988 n := len(elems) 989 for i := 0; i < n>>1; i++ { 990 elems[i], elems[n-1-i] = elems[n-1-i], elems[i] 991 } 992 return NewList(elems), nil 993 } 994 995 // https://github.com/google/skylark/blob/master/doc/spec.md#set 996 func set(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 997 var iterable Iterable 998 if err := UnpackPositionalArgs("set", args, kwargs, 0, &iterable); err != nil { 999 return nil, err 1000 } 1001 set := new(Set) 1002 if iterable != nil { 1003 iter := iterable.Iterate() 1004 defer iter.Done() 1005 var x Value 1006 for iter.Next(&x) { 1007 if err := set.Insert(x); err != nil { 1008 return nil, err 1009 } 1010 } 1011 } 1012 return set, nil 1013 } 1014 1015 // https://github.com/google/skylark/blob/master/doc/spec.md#sorted 1016 func sorted(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 1017 var iterable Iterable 1018 var key Callable 1019 var reverse bool 1020 if err := UnpackArgs("sorted", args, kwargs, 1021 "iterable", &iterable, 1022 "key?", &key, 1023 "reverse?", &reverse, 1024 ); err != nil { 1025 return nil, err 1026 } 1027 1028 iter := iterable.Iterate() 1029 defer iter.Done() 1030 var values []Value 1031 if n := Len(iterable); n > 0 { 1032 values = make(Tuple, 0, n) // preallocate if length is known 1033 } 1034 var x Value 1035 for iter.Next(&x) { 1036 values = append(values, x) 1037 } 1038 1039 // Derive keys from values by applying key function. 1040 var keys []Value 1041 if key != nil { 1042 keys = make([]Value, len(values)) 1043 for i, v := range values { 1044 k, err := Call(thread, key, Tuple{v}, nil) 1045 if err != nil { 1046 return nil, err // to preserve backtrace, don't modify error 1047 } 1048 keys[i] = k 1049 } 1050 } 1051 1052 slice := &sortSlice{keys: keys, values: values} 1053 if reverse { 1054 sort.Stable(sort.Reverse(slice)) 1055 } else { 1056 sort.Stable(slice) 1057 } 1058 return NewList(slice.values), slice.err 1059 } 1060 1061 type sortSlice struct { 1062 keys []Value // nil => values[i] is key 1063 values []Value 1064 err error 1065 } 1066 1067 func (s *sortSlice) Len() int { return len(s.values) } 1068 func (s *sortSlice) Less(i, j int) bool { 1069 keys := s.keys 1070 if s.keys == nil { 1071 keys = s.values 1072 } 1073 ok, err := Compare(syntax.LT, keys[i], keys[j]) 1074 if err != nil { 1075 s.err = err 1076 } 1077 return ok 1078 } 1079 func (s *sortSlice) Swap(i, j int) { 1080 if s.keys != nil { 1081 s.keys[i], s.keys[j] = s.keys[j], s.keys[i] 1082 } 1083 s.values[i], s.values[j] = s.values[j], s.values[i] 1084 } 1085 1086 // https://github.com/google/skylark/blob/master/doc/spec.md#str 1087 func str(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 1088 if len(kwargs) > 0 { 1089 return nil, fmt.Errorf("str does not accept keyword arguments") 1090 } 1091 if len(args) != 1 { 1092 return nil, fmt.Errorf("str: got %d arguments, want exactly 1", len(args)) 1093 } 1094 x := args[0] 1095 if _, ok := AsString(x); !ok { 1096 x = String(x.String()) 1097 } 1098 return x, nil 1099 } 1100 1101 // https://github.com/google/skylark/blob/master/doc/spec.md#tuple 1102 func tuple(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 1103 var iterable Iterable 1104 if err := UnpackPositionalArgs("tuple", args, kwargs, 0, &iterable); err != nil { 1105 return nil, err 1106 } 1107 if len(args) == 0 { 1108 return Tuple(nil), nil 1109 } 1110 iter := iterable.Iterate() 1111 defer iter.Done() 1112 var elems Tuple 1113 if n := Len(iterable); n > 0 { 1114 elems = make(Tuple, 0, n) // preallocate if length is known 1115 } 1116 var x Value 1117 for iter.Next(&x) { 1118 elems = append(elems, x) 1119 } 1120 return elems, nil 1121 } 1122 1123 // https://github.com/google/skylark/blob/master/doc/spec.md#type 1124 func type_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 1125 if len(kwargs) > 0 { 1126 return nil, fmt.Errorf("type does not accept keyword arguments") 1127 } 1128 if len(args) != 1 { 1129 return nil, fmt.Errorf("type: got %d arguments, want exactly 1", len(args)) 1130 } 1131 return String(args[0].Type()), nil 1132 } 1133 1134 // https://github.com/google/skylark/blob/master/doc/spec.md#zip 1135 func zip(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { 1136 if len(kwargs) > 0 { 1137 return nil, fmt.Errorf("zip does not accept keyword arguments") 1138 } 1139 rows, cols := 0, len(args) 1140 iters := make([]Iterator, cols) 1141 defer func() { 1142 for _, iter := range iters { 1143 if iter != nil { 1144 iter.Done() 1145 } 1146 } 1147 }() 1148 for i, seq := range args { 1149 it := Iterate(seq) 1150 if it == nil { 1151 return nil, fmt.Errorf("zip: argument #%d is not iterable: %s", i+1, seq.Type()) 1152 } 1153 iters[i] = it 1154 n := Len(seq) 1155 if i == 0 || n < rows { 1156 rows = n // possibly -1 1157 } 1158 } 1159 var result []Value 1160 if rows >= 0 { 1161 // length known 1162 result = make([]Value, rows) 1163 array := make(Tuple, cols*rows) // allocate a single backing array 1164 for i := 0; i < rows; i++ { 1165 tuple := array[:cols:cols] 1166 array = array[cols:] 1167 for j, iter := range iters { 1168 iter.Next(&tuple[j]) 1169 } 1170 result[i] = tuple 1171 } 1172 } else { 1173 // length not known 1174 outer: 1175 for { 1176 tuple := make(Tuple, cols) 1177 for i, iter := range iters { 1178 if !iter.Next(&tuple[i]) { 1179 break outer 1180 } 1181 } 1182 result = append(result, tuple) 1183 } 1184 } 1185 return NewList(result), nil 1186 } 1187 1188 // ---- methods of built-in types --- 1189 1190 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·get 1191 func dict_get(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1192 var key, dflt Value 1193 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &key, &dflt); err != nil { 1194 return nil, err 1195 } 1196 if v, ok, err := recv.(*Dict).Get(key); err != nil { 1197 return nil, err 1198 } else if ok { 1199 return v, nil 1200 } else if dflt != nil { 1201 return dflt, nil 1202 } 1203 return None, nil 1204 } 1205 1206 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·clear 1207 func dict_clear(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1208 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1209 return nil, err 1210 } 1211 return None, recv.(*Dict).Clear() 1212 } 1213 1214 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·items 1215 func dict_items(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1216 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1217 return nil, err 1218 } 1219 items := recv.(*Dict).Items() 1220 res := make([]Value, len(items)) 1221 for i, item := range items { 1222 res[i] = item // convert [2]Value to Value 1223 } 1224 return NewList(res), nil 1225 } 1226 1227 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·keys 1228 func dict_keys(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1229 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1230 return nil, err 1231 } 1232 return NewList(recv.(*Dict).Keys()), nil 1233 } 1234 1235 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·pop 1236 func dict_pop(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1237 recv := recv_.(*Dict) 1238 var k, d Value 1239 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &k, &d); err != nil { 1240 return nil, err 1241 } 1242 if v, found, err := recv.Delete(k); err != nil { 1243 return nil, err // dict is frozen or key is unhashable 1244 } else if found { 1245 return v, nil 1246 } else if d != nil { 1247 return d, nil 1248 } 1249 return nil, fmt.Errorf("pop: missing key") 1250 } 1251 1252 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·popitem 1253 func dict_popitem(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1254 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1255 return nil, err 1256 } 1257 recv := recv_.(*Dict) 1258 k, ok := recv.ht.first() 1259 if !ok { 1260 return nil, fmt.Errorf("popitem: empty dict") 1261 } 1262 v, _, err := recv.Delete(k) 1263 if err != nil { 1264 return nil, err // dict is frozen 1265 } 1266 return Tuple{k, v}, nil 1267 } 1268 1269 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·setdefault 1270 func dict_setdefault(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1271 var key, dflt Value = nil, None 1272 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &key, &dflt); err != nil { 1273 return nil, err 1274 } 1275 dict := recv.(*Dict) 1276 if v, ok, err := dict.Get(key); err != nil { 1277 return nil, err 1278 } else if ok { 1279 return v, nil 1280 } else { 1281 return dflt, dict.SetKey(key, dflt) 1282 } 1283 } 1284 1285 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·update 1286 func dict_update(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1287 if len(args) > 1 { 1288 return nil, fmt.Errorf("update: got %d arguments, want at most 1", len(args)) 1289 } 1290 if err := updateDict(recv.(*Dict), args, kwargs); err != nil { 1291 return nil, fmt.Errorf("update: %v", err) 1292 } 1293 return None, nil 1294 } 1295 1296 // https://github.com/google/skylark/blob/master/doc/spec.md#dict·update 1297 func dict_values(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1298 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1299 return nil, err 1300 } 1301 items := recv.(*Dict).Items() 1302 res := make([]Value, len(items)) 1303 for i, item := range items { 1304 res[i] = item[1] 1305 } 1306 return NewList(res), nil 1307 } 1308 1309 // https://github.com/google/skylark/blob/master/doc/spec.md#list·append 1310 func list_append(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1311 recv := recv_.(*List) 1312 var object Value 1313 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &object); err != nil { 1314 return nil, err 1315 } 1316 if err := recv.checkMutable("append to", true); err != nil { 1317 return nil, err 1318 } 1319 recv.elems = append(recv.elems, object) 1320 return None, nil 1321 } 1322 1323 // https://github.com/google/skylark/blob/master/doc/spec.md#list·clear 1324 func list_clear(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1325 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1326 return nil, err 1327 } 1328 return None, recv_.(*List).Clear() 1329 } 1330 1331 // https://github.com/google/skylark/blob/master/doc/spec.md#list·extend 1332 func list_extend(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1333 recv := recv_.(*List) 1334 var iterable Iterable 1335 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &iterable); err != nil { 1336 return nil, err 1337 } 1338 if err := recv.checkMutable("extend", true); err != nil { 1339 return nil, err 1340 } 1341 listExtend(recv, iterable) 1342 return None, nil 1343 } 1344 1345 // https://github.com/google/skylark/blob/master/doc/spec.md#list·index 1346 func list_index(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1347 recv := recv_.(*List) 1348 var value, start_, end_ Value 1349 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &value, &start_, &end_); err != nil { 1350 return nil, err 1351 } 1352 1353 start, end, err := indices(start_, end_, recv.Len()) 1354 if err != nil { 1355 return nil, fmt.Errorf("%s: %s", fnname, err) 1356 } 1357 1358 for i := start; i < end; i++ { 1359 if eq, err := Equal(recv.elems[i], value); err != nil { 1360 return nil, fmt.Errorf("index: %s", err) 1361 } else if eq { 1362 return MakeInt(i), nil 1363 } 1364 } 1365 return nil, fmt.Errorf("index: value not in list") 1366 } 1367 1368 // https://github.com/google/skylark/blob/master/doc/spec.md#list·insert 1369 func list_insert(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1370 recv := recv_.(*List) 1371 var index int 1372 var object Value 1373 if err := UnpackPositionalArgs(fnname, args, kwargs, 2, &index, &object); err != nil { 1374 return nil, err 1375 } 1376 if err := recv.checkMutable("insert into", true); err != nil { 1377 return nil, err 1378 } 1379 1380 if index < 0 { 1381 index += recv.Len() 1382 } 1383 1384 if index >= recv.Len() { 1385 // end 1386 recv.elems = append(recv.elems, object) 1387 } else { 1388 if index < 0 { 1389 index = 0 // start 1390 } 1391 recv.elems = append(recv.elems, nil) 1392 copy(recv.elems[index+1:], recv.elems[index:]) // slide up one 1393 recv.elems[index] = object 1394 } 1395 return None, nil 1396 } 1397 1398 // https://github.com/google/skylark/blob/master/doc/spec.md#list·remove 1399 func list_remove(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1400 recv := recv_.(*List) 1401 var value Value 1402 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &value); err != nil { 1403 return nil, err 1404 } 1405 if err := recv.checkMutable("remove from", true); err != nil { 1406 return nil, err 1407 } 1408 for i, elem := range recv.elems { 1409 if eq, err := Equal(elem, value); err != nil { 1410 return nil, fmt.Errorf("remove: %v", err) 1411 } else if eq { 1412 recv.elems = append(recv.elems[:i], recv.elems[i+1:]...) 1413 return None, nil 1414 } 1415 } 1416 return nil, fmt.Errorf("remove: element not found") 1417 } 1418 1419 // https://github.com/google/skylark/blob/master/doc/spec.md#list·pop 1420 func list_pop(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1421 list := recv.(*List) 1422 index := list.Len() - 1 1423 if err := UnpackPositionalArgs(fnname, args, kwargs, 0, &index); err != nil { 1424 return nil, err 1425 } 1426 if index < 0 || index >= list.Len() { 1427 return nil, fmt.Errorf("pop: index %d is out of range [0:%d]", index, list.Len()) 1428 } 1429 if err := list.checkMutable("pop from", true); err != nil { 1430 return nil, err 1431 } 1432 res := list.elems[index] 1433 list.elems = append(list.elems[:index], list.elems[index+1:]...) 1434 return res, nil 1435 } 1436 1437 // https://github.com/google/skylark/blob/master/doc/spec.md#string·capitalize 1438 func string_capitalize(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1439 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1440 return nil, err 1441 } 1442 return String(strings.Title(string(recv.(String)))), nil 1443 } 1444 1445 // string_iterable returns an unspecified iterable value whose iterator yields: 1446 // - elems: successive 1-byte substrings 1447 // - codepoints: successive substrings that encode a single Unicode code point. 1448 // - elem_ords: numeric values of successive bytes 1449 // - codepoint_ords: numeric values of successive Unicode code points 1450 func string_iterable(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1451 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1452 return nil, err 1453 } 1454 return stringIterable{ 1455 s: recv.(String), 1456 ords: fnname[len(fnname)-2] == 'd', 1457 codepoints: fnname[0] == 'c', 1458 }, nil 1459 } 1460 1461 // https://github.com/google/skylark/blob/master/doc/spec.md#string·count 1462 func string_count(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1463 recv := string(recv_.(String)) 1464 1465 var sub string 1466 var start_, end_ Value 1467 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &sub, &start_, &end_); err != nil { 1468 return nil, err 1469 } 1470 1471 start, end, err := indices(start_, end_, len(recv)) 1472 if err != nil { 1473 return nil, fmt.Errorf("%s: %s", fnname, err) 1474 } 1475 1476 var slice string 1477 if start < end { 1478 slice = recv[start:end] 1479 } 1480 return MakeInt(strings.Count(slice, sub)), nil 1481 } 1482 1483 // https://github.com/google/skylark/blob/master/doc/spec.md#string·isalnum 1484 func string_isalnum(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1485 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1486 return nil, err 1487 } 1488 recv := string(recv_.(String)) 1489 for _, r := range recv { 1490 if !unicode.IsLetter(r) && !unicode.IsDigit(r) { 1491 return False, nil 1492 } 1493 } 1494 return Bool(recv != ""), nil 1495 } 1496 1497 // https://github.com/google/skylark/blob/master/doc/spec.md#string·isalpha 1498 func string_isalpha(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1499 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1500 return nil, err 1501 } 1502 recv := string(recv_.(String)) 1503 for _, r := range recv { 1504 if !unicode.IsLetter(r) { 1505 return False, nil 1506 } 1507 } 1508 return Bool(recv != ""), nil 1509 } 1510 1511 // https://github.com/google/skylark/blob/master/doc/spec.md#string·isdigit 1512 func string_isdigit(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1513 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1514 return nil, err 1515 } 1516 recv := string(recv_.(String)) 1517 for _, r := range recv { 1518 if !unicode.IsDigit(r) { 1519 return False, nil 1520 } 1521 } 1522 return Bool(recv != ""), nil 1523 } 1524 1525 // https://github.com/google/skylark/blob/master/doc/spec.md#string·islower 1526 func string_islower(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1527 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1528 return nil, err 1529 } 1530 recv := string(recv_.(String)) 1531 return Bool(isCasedString(recv) && recv == strings.ToLower(recv)), nil 1532 } 1533 1534 // isCasedString reports whether its argument contains any cased characters. 1535 func isCasedString(s string) bool { 1536 for _, r := range s { 1537 if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || unicode.SimpleFold(r) != r { 1538 return true 1539 } 1540 } 1541 return false 1542 } 1543 1544 // https://github.com/google/skylark/blob/master/doc/spec.md#string·isspace 1545 func string_isspace(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1546 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1547 return nil, err 1548 } 1549 recv := string(recv_.(String)) 1550 for _, r := range recv { 1551 if !unicode.IsSpace(r) { 1552 return False, nil 1553 } 1554 } 1555 return Bool(recv != ""), nil 1556 } 1557 1558 // https://github.com/google/skylark/blob/master/doc/spec.md#string·istitle 1559 func string_istitle(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1560 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1561 return nil, err 1562 } 1563 recv := string(recv_.(String)) 1564 1565 // Python semantics differ from x==strings.{To,}Title(x) in Go: 1566 // "uppercase characters may only follow uncased characters and 1567 // lowercase characters only cased ones." 1568 var cased, prevCased bool 1569 for _, r := range recv { 1570 if unicode.IsUpper(r) { 1571 if prevCased { 1572 return False, nil 1573 } 1574 cased = true 1575 prevCased = true 1576 } else if unicode.IsLower(r) { 1577 if !prevCased { 1578 return False, nil 1579 } 1580 prevCased = true 1581 cased = true 1582 } else { 1583 prevCased = false 1584 } 1585 } 1586 return Bool(cased), nil 1587 } 1588 1589 // https://github.com/google/skylark/blob/master/doc/spec.md#string·isupper 1590 func string_isupper(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1591 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1592 return nil, err 1593 } 1594 recv := string(recv_.(String)) 1595 return Bool(isCasedString(recv) && recv == strings.ToUpper(recv)), nil 1596 } 1597 1598 // https://github.com/google/skylark/blob/master/doc/spec.md#string·find 1599 func string_find(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1600 return string_find_impl(fnname, string(recv.(String)), args, kwargs, true, false) 1601 } 1602 1603 // https://github.com/google/skylark/blob/master/doc/spec.md#string·format 1604 func string_format(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1605 format := string(recv_.(String)) 1606 var auto, manual bool // kinds of positional indexing used 1607 path := make([]Value, 0, 4) 1608 var buf bytes.Buffer 1609 index := 0 1610 for { 1611 literal := format 1612 i := strings.IndexByte(format, '{') 1613 if i >= 0 { 1614 literal = format[:i] 1615 } 1616 1617 // Replace "}}" with "}" in non-field portion, rejecting a lone '}'. 1618 for { 1619 j := strings.IndexByte(literal, '}') 1620 if j < 0 { 1621 buf.WriteString(literal) 1622 break 1623 } 1624 if len(literal) == j+1 || literal[j+1] != '}' { 1625 return nil, fmt.Errorf("single '}' in format") 1626 } 1627 buf.WriteString(literal[:j+1]) 1628 literal = literal[j+2:] 1629 } 1630 1631 if i < 0 { 1632 break // end of format string 1633 } 1634 1635 if i+1 < len(format) && format[i+1] == '{' { 1636 // "{{" means a literal '{' 1637 buf.WriteByte('{') 1638 format = format[i+2:] 1639 continue 1640 } 1641 1642 format = format[i+1:] 1643 i = strings.IndexByte(format, '}') 1644 if i < 0 { 1645 return nil, fmt.Errorf("unmatched '{' in format") 1646 } 1647 1648 var arg Value 1649 conv := "s" 1650 var spec string 1651 1652 field := format[:i] 1653 format = format[i+1:] 1654 1655 var name string 1656 if i := strings.IndexByte(field, '!'); i < 0 { 1657 // "name" or "name:spec" 1658 if i := strings.IndexByte(field, ':'); i < 0 { 1659 name = field 1660 } else { 1661 name = field[:i] 1662 spec = field[i+1:] 1663 } 1664 } else { 1665 // "name!conv" or "name!conv:spec" 1666 name = field[:i] 1667 field = field[i+1:] 1668 // "conv" or "conv:spec" 1669 if i := strings.IndexByte(field, ':'); i < 0 { 1670 conv = field 1671 } else { 1672 conv = field[:i] 1673 spec = field[i+1:] 1674 } 1675 } 1676 1677 if name == "" { 1678 // "{}": automatic indexing 1679 if manual { 1680 return nil, fmt.Errorf("cannot switch from manual field specification to automatic field numbering") 1681 } 1682 auto = true 1683 if index >= len(args) { 1684 return nil, fmt.Errorf("tuple index out of range") 1685 } 1686 arg = args[index] 1687 index++ 1688 } else if num, err := strconv.Atoi(name); err == nil && !strings.HasPrefix(name, "-") { 1689 // positional argument 1690 if auto { 1691 return nil, fmt.Errorf("cannot switch from automatic field numbering to manual field specification") 1692 } 1693 manual = true 1694 if num >= len(args) { 1695 return nil, fmt.Errorf("tuple index out of range") 1696 } else { 1697 arg = args[num] 1698 } 1699 } else { 1700 // keyword argument 1701 for _, kv := range kwargs { 1702 if string(kv[0].(String)) == name { 1703 arg = kv[1] 1704 break 1705 } 1706 } 1707 if arg == nil { 1708 // Skylark does not support Python's x.y or a[i] syntaxes, 1709 // or nested use of {...}. 1710 if strings.Contains(name, ".") { 1711 return nil, fmt.Errorf("attribute syntax x.y is not supported in replacement fields: %s", name) 1712 } 1713 if strings.Contains(name, "[") { 1714 return nil, fmt.Errorf("element syntax a[i] is not supported in replacement fields: %s", name) 1715 } 1716 if strings.Contains(name, "{") { 1717 return nil, fmt.Errorf("nested replacement fields not supported") 1718 } 1719 return nil, fmt.Errorf("keyword %s not found", name) 1720 } 1721 } 1722 1723 if spec != "" { 1724 // Skylark does not support Python's format_spec features. 1725 return nil, fmt.Errorf("format spec features not supported in replacement fields: %s", spec) 1726 } 1727 1728 switch conv { 1729 case "s": 1730 if str, ok := AsString(arg); ok { 1731 buf.WriteString(str) 1732 } else { 1733 writeValue(&buf, arg, path) 1734 } 1735 case "r": 1736 writeValue(&buf, arg, path) 1737 default: 1738 return nil, fmt.Errorf("unknown conversion %q", conv) 1739 } 1740 } 1741 return String(buf.String()), nil 1742 } 1743 1744 // https://github.com/google/skylark/blob/master/doc/spec.md#string·index 1745 func string_index(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1746 return string_find_impl(fnname, string(recv.(String)), args, kwargs, false, false) 1747 } 1748 1749 // https://github.com/google/skylark/blob/master/doc/spec.md#string·join 1750 func string_join(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1751 recv := string(recv_.(String)) 1752 var iterable Iterable 1753 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &iterable); err != nil { 1754 return nil, err 1755 } 1756 iter := iterable.Iterate() 1757 defer iter.Done() 1758 var buf bytes.Buffer 1759 var x Value 1760 for i := 0; iter.Next(&x); i++ { 1761 if i > 0 { 1762 buf.WriteString(recv) 1763 } 1764 s, ok := AsString(x) 1765 if !ok { 1766 return nil, fmt.Errorf("in list, want string, got %s", x.Type()) 1767 } 1768 buf.WriteString(s) 1769 } 1770 return String(buf.String()), nil 1771 } 1772 1773 // https://github.com/google/skylark/blob/master/doc/spec.md#string·lower 1774 func string_lower(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1775 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1776 return nil, err 1777 } 1778 return String(strings.ToLower(string(recv.(String)))), nil 1779 } 1780 1781 // https://github.com/google/skylark/blob/master/doc/spec.md#string·lstrip 1782 func string_lstrip(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1783 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1784 return nil, err 1785 } 1786 return String(strings.TrimLeftFunc(string(recv.(String)), unicode.IsSpace)), nil 1787 } 1788 1789 // https://github.com/google/skylark/blob/master/doc/spec.md#string·partition 1790 func string_partition(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1791 recv := string(recv_.(String)) 1792 var sep string 1793 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &sep); err != nil { 1794 return nil, err 1795 } 1796 if sep == "" { 1797 return nil, fmt.Errorf("%s: empty separator", fnname) 1798 } 1799 var i int 1800 if fnname[0] == 'p' { 1801 i = strings.Index(recv, sep) // partition 1802 } else { 1803 i = strings.LastIndex(recv, sep) // rpartition 1804 } 1805 tuple := make(Tuple, 0, 3) 1806 if i < 0 { 1807 if fnname[0] == 'p' { 1808 tuple = append(tuple, String(recv), String(""), String("")) 1809 } else { 1810 tuple = append(tuple, String(""), String(""), String(recv)) 1811 } 1812 } else { 1813 tuple = append(tuple, String(recv[:i]), String(sep), String(recv[i+len(sep):])) 1814 } 1815 return tuple, nil 1816 } 1817 1818 // https://github.com/google/skylark/blob/master/doc/spec.md#string·replace 1819 func string_replace(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1820 recv := string(recv_.(String)) 1821 var old, new string 1822 count := -1 1823 if err := UnpackPositionalArgs(fnname, args, kwargs, 2, &old, &new, &count); err != nil { 1824 return nil, err 1825 } 1826 return String(strings.Replace(recv, old, new, count)), nil 1827 } 1828 1829 // https://github.com/google/skylark/blob/master/doc/spec.md#string·rfind 1830 func string_rfind(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1831 return string_find_impl(fnname, string(recv.(String)), args, kwargs, true, true) 1832 } 1833 1834 // https://github.com/google/skylark/blob/master/doc/spec.md#string·rindex 1835 func string_rindex(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1836 return string_find_impl(fnname, string(recv.(String)), args, kwargs, false, true) 1837 } 1838 1839 // https://github.com/google/skylark/blob/master/doc/spec.md#string·rstrip 1840 func string_rstrip(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1841 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1842 return nil, err 1843 } 1844 return String(strings.TrimRightFunc(string(recv.(String)), unicode.IsSpace)), nil 1845 } 1846 1847 // https://github.com/google/skylark/blob/master/doc/spec.md#string·startswith 1848 // https://github.com/google/skylark/blob/master/doc/spec.md#string·endswith 1849 func string_startswith(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1850 var x Value 1851 var start, end Value = None, None 1852 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &x, &start, &end); err != nil { 1853 return nil, err 1854 } 1855 1856 // compute effective substring. 1857 s := string(recv_.(String)) 1858 if start, end, err := indices(start, end, len(s)); err != nil { 1859 return nil, err 1860 } else { 1861 if end < start { 1862 end = start // => empty result 1863 } 1864 s = s[start:end] 1865 } 1866 1867 f := strings.HasPrefix 1868 if fnname[0] == 'e' { // endswith 1869 f = strings.HasSuffix 1870 } 1871 1872 switch x := x.(type) { 1873 case Tuple: 1874 for i, x := range x { 1875 prefix, ok := AsString(x) 1876 if !ok { 1877 return nil, fmt.Errorf("%s: want string, got %s, for element %d", 1878 fnname, x.Type(), i) 1879 } 1880 if f(s, prefix) { 1881 return True, nil 1882 } 1883 } 1884 return False, nil 1885 case String: 1886 return Bool(f(s, string(x))), nil 1887 } 1888 return nil, fmt.Errorf("%s: got %s, want string or tuple of string", fnname, x.Type()) 1889 } 1890 1891 // https://github.com/google/skylark/blob/master/doc/spec.md#string·strip 1892 // https://github.com/google/skylark/blob/master/doc/spec.md#string·lstrip 1893 // https://github.com/google/skylark/blob/master/doc/spec.md#string·rstrip 1894 func string_strip(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1895 var chars string 1896 if err := UnpackPositionalArgs(fnname, args, kwargs, 0, &chars); err != nil { 1897 return nil, err 1898 } 1899 recv := string(recv_.(String)) 1900 var s string 1901 switch fnname[0] { 1902 case 's': // strip 1903 if chars != "" { 1904 s = strings.Trim(recv, chars) 1905 } else { 1906 s = strings.TrimSpace(recv) 1907 } 1908 case 'l': // lstrip 1909 if chars != "" { 1910 s = strings.TrimLeft(recv, chars) 1911 } else { 1912 s = strings.TrimLeftFunc(recv, unicode.IsSpace) 1913 } 1914 case 'r': // rstrip 1915 if chars != "" { 1916 s = strings.TrimRight(recv, chars) 1917 } else { 1918 s = strings.TrimRightFunc(recv, unicode.IsSpace) 1919 } 1920 } 1921 return String(s), nil 1922 } 1923 1924 // https://github.com/google/skylark/blob/master/doc/spec.md#string·title 1925 func string_title(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1926 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1927 return nil, err 1928 } 1929 return String(strings.Title(strings.ToLower(string(recv.(String))))), nil 1930 } 1931 1932 // https://github.com/google/skylark/blob/master/doc/spec.md#string·upper 1933 func string_upper(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 1934 if err := UnpackPositionalArgs(fnname, args, kwargs, 0); err != nil { 1935 return nil, err 1936 } 1937 return String(strings.ToUpper(string(recv.(String)))), nil 1938 } 1939 1940 // https://github.com/google/skylark/blob/master/doc/spec.md#string·split 1941 // https://github.com/google/skylark/blob/master/doc/spec.md#string·rsplit 1942 func string_split(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) { 1943 recv := string(recv_.(String)) 1944 var sep_ Value 1945 maxsplit := -1 1946 if err := UnpackPositionalArgs(fnname, args, kwargs, 0, &sep_, &maxsplit); err != nil { 1947 return nil, err 1948 } 1949 1950 var res []string 1951 1952 if sep_ == nil || sep_ == None { 1953 // special case: split on whitespace 1954 if maxsplit < 0 { 1955 res = strings.Fields(recv) 1956 } else if fnname == "split" { 1957 res = splitspace(recv, maxsplit) 1958 } else { // rsplit 1959 res = rsplitspace(recv, maxsplit) 1960 } 1961 1962 } else if sep, ok := AsString(sep_); ok { 1963 if sep == "" { 1964 return nil, fmt.Errorf("split: empty separator") 1965 } 1966 // usual case: split on non-empty separator 1967 if maxsplit < 0 { 1968 res = strings.Split(recv, sep) 1969 } else if fnname == "split" { 1970 res = strings.SplitN(recv, sep, maxsplit+1) 1971 } else { // rsplit 1972 res = strings.Split(recv, sep) 1973 if excess := len(res) - maxsplit; excess > 0 { 1974 res[0] = strings.Join(res[:excess], sep) 1975 res = append(res[:1], res[excess:]...) 1976 } 1977 } 1978 1979 } else { 1980 return nil, fmt.Errorf("split: got %s for separator, want string", sep_.Type()) 1981 } 1982 1983 list := make([]Value, len(res)) 1984 for i, x := range res { 1985 list[i] = String(x) 1986 } 1987 return NewList(list), nil 1988 } 1989 1990 // Precondition: max >= 0. 1991 func rsplitspace(s string, max int) []string { 1992 res := make([]string, 0, max+1) 1993 end := -1 // index of field end, or -1 in a region of spaces. 1994 for i := len(s); i > 0; { 1995 r, sz := utf8.DecodeLastRuneInString(s[:i]) 1996 if unicode.IsSpace(r) { 1997 if end >= 0 { 1998 if len(res) == max { 1999 break // let this field run to the start 2000 } 2001 res = append(res, s[i:end]) 2002 end = -1 2003 } 2004 } else if end < 0 { 2005 end = i 2006 } 2007 i -= sz 2008 } 2009 if end >= 0 { 2010 res = append(res, s[:end]) 2011 } 2012 2013 resLen := len(res) 2014 for i := 0; i < resLen/2; i++ { 2015 res[i], res[resLen-1-i] = res[resLen-1-i], res[i] 2016 } 2017 2018 return res 2019 } 2020 2021 // Precondition: max >= 0. 2022 func splitspace(s string, max int) []string { 2023 var res []string 2024 start := -1 // index of field start, or -1 in a region of spaces 2025 for i, r := range s { 2026 if unicode.IsSpace(r) { 2027 if start >= 0 { 2028 if len(res) == max { 2029 break // let this field run to the end 2030 } 2031 res = append(res, s[start:i]) 2032 start = -1 2033 } 2034 } else if start == -1 { 2035 start = i 2036 } 2037 } 2038 if start >= 0 { 2039 res = append(res, s[start:]) 2040 } 2041 return res 2042 } 2043 2044 // https://github.com/google/skylark/blob/master/doc/spec.md#string·splitlines 2045 func string_splitlines(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 2046 var keepends bool 2047 if err := UnpackPositionalArgs(fnname, args, kwargs, 0, &keepends); err != nil { 2048 return nil, err 2049 } 2050 s := string(recv.(String)) 2051 var lines []string 2052 // TODO(adonovan): handle CRLF correctly. 2053 if keepends { 2054 lines = strings.SplitAfter(s, "\n") 2055 } else { 2056 lines = strings.Split(s, "\n") 2057 } 2058 if strings.HasSuffix(s, "\n") { 2059 lines = lines[:len(lines)-1] 2060 } 2061 list := make([]Value, len(lines)) 2062 for i, x := range lines { 2063 list[i] = String(x) 2064 } 2065 return NewList(list), nil 2066 } 2067 2068 // https://github.com/google/skylark/blob/master/doc/spec.md#set·union. 2069 func set_union(fnname string, recv Value, args Tuple, kwargs []Tuple) (Value, error) { 2070 var iterable Iterable 2071 if err := UnpackPositionalArgs(fnname, args, kwargs, 0, &iterable); err != nil { 2072 return nil, err 2073 } 2074 iter := iterable.Iterate() 2075 defer iter.Done() 2076 union, err := recv.(*Set).Union(iter) 2077 if err != nil { 2078 return nil, fmt.Errorf("union: %v", err) 2079 } 2080 return union, nil 2081 } 2082 2083 // Common implementation of string_{r}{find,index}. 2084 func string_find_impl(fnname string, s string, args Tuple, kwargs []Tuple, allowError, last bool) (Value, error) { 2085 var sub string 2086 var start_, end_ Value 2087 if err := UnpackPositionalArgs(fnname, args, kwargs, 1, &sub, &start_, &end_); err != nil { 2088 return nil, err 2089 } 2090 2091 start, end, err := indices(start_, end_, len(s)) 2092 if err != nil { 2093 return nil, fmt.Errorf("%s: %s", fnname, err) 2094 } 2095 var slice string 2096 if start < end { 2097 slice = s[start:end] 2098 } 2099 2100 var i int 2101 if last { 2102 i = strings.LastIndex(slice, sub) 2103 } else { 2104 i = strings.Index(slice, sub) 2105 } 2106 if i < 0 { 2107 if !allowError { 2108 return nil, fmt.Errorf("substring not found") 2109 } 2110 return MakeInt(-1), nil 2111 } 2112 return MakeInt(i + start), nil 2113 } 2114 2115 // Common implementation of builtin dict function and dict.update method. 2116 // Precondition: len(updates) == 0 or 1. 2117 func updateDict(dict *Dict, updates Tuple, kwargs []Tuple) error { 2118 if len(updates) == 1 { 2119 switch updates := updates[0].(type) { 2120 case NoneType: 2121 // no-op 2122 case *Dict: 2123 // Iterate over dict's key/value pairs, not just keys. 2124 for _, item := range updates.Items() { 2125 if err := dict.SetKey(item[0], item[1]); err != nil { 2126 return err // dict is frozen 2127 } 2128 } 2129 default: 2130 // all other sequences 2131 iter := Iterate(updates) 2132 if iter == nil { 2133 return fmt.Errorf("got %s, want iterable", updates.Type()) 2134 } 2135 defer iter.Done() 2136 var pair Value 2137 for i := 0; iter.Next(&pair); i++ { 2138 iter2 := Iterate(pair) 2139 if iter2 == nil { 2140 return fmt.Errorf("dictionary update sequence element #%d is not iterable (%s)", i, pair.Type()) 2141 2142 } 2143 defer iter2.Done() 2144 len := Len(pair) 2145 if len < 0 { 2146 return fmt.Errorf("dictionary update sequence element #%d has unknown length (%s)", i, pair.Type()) 2147 } else if len != 2 { 2148 return fmt.Errorf("dictionary update sequence element #%d has length %d, want 2", i, len) 2149 } 2150 var k, v Value 2151 iter2.Next(&k) 2152 iter2.Next(&v) 2153 if err := dict.SetKey(k, v); err != nil { 2154 return err 2155 } 2156 } 2157 } 2158 } 2159 2160 // Then add the kwargs. 2161 for _, pair := range kwargs { 2162 if err := dict.SetKey(pair[0], pair[1]); err != nil { 2163 return err // dict is frozen 2164 } 2165 } 2166 2167 return nil 2168 }