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