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