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