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