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  }