blob: eb0e84e922913634246eac68792457fdf1ff826f [file] [log] [blame]
Alan Donovan312d1a52017-10-02 10:10:28 -04001// 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
Alan Donovane3deafe2018-10-23 11:05:09 -04005// Package starlark provides a Starlark interpreter.
Alan Donovan312d1a52017-10-02 10:10:28 -04006//
Alan Donovane3deafe2018-10-23 11:05:09 -04007// Starlark values are represented by the Value interface.
Alan Donovan312d1a52017-10-02 10:10:28 -04008// The following built-in Value types are known to the evaluator:
9//
10// NoneType -- NoneType
11// Bool -- bool
12// Int -- int
13// Float -- float
14// String -- string
15// *List -- list
16// Tuple -- tuple
17// *Dict -- dict
18// *Set -- set
Alan Donovane3deafe2018-10-23 11:05:09 -040019// *Function -- function (implemented in Starlark)
alandonovan4cbd8962017-10-19 13:18:36 -040020// *Builtin -- builtin_function_or_method (function or method implemented in Go)
Alan Donovan312d1a52017-10-02 10:10:28 -040021//
22// Client applications may define new data types that satisfy at least
23// the Value interface. Such types may provide additional operations by
24// implementing any of these optional interfaces:
25//
26// Callable -- value is callable like a function
27// Comparable -- value defines its own comparison operations
28// Iterable -- value is iterable using 'for' loops
29// Sequence -- value is iterable sequence of known length
30// Indexable -- value is sequence with efficient random access
jmillikin-stripe3ccab942018-10-05 07:09:12 -070031// Mapping -- value maps from keys to values, like a dictionary
Alan Donovan312d1a52017-10-02 10:10:28 -040032// HasBinary -- value defines binary operations such as * and +
33// HasAttrs -- value has readable fields or methods x.f
34// HasSetField -- value has settable fields x.f
35// HasSetIndex -- value supports element update using x[i]=y
jmillikin-stripe3ccab942018-10-05 07:09:12 -070036// HasSetKey -- value supports map update using x[k]=v
alandonovan58f91012019-01-03 16:32:47 -050037// HasUnary -- value defines unary operations such as + and -
Alan Donovan312d1a52017-10-02 10:10:28 -040038//
39// Client applications may also define domain-specific functions in Go
Alan Donovane3deafe2018-10-23 11:05:09 -040040// and make them available to Starlark programs. Use NewBuiltin to
Alan Donovan312d1a52017-10-02 10:10:28 -040041// construct a built-in value that wraps a Go function. The
42// implementation of the Go function may use UnpackArgs to make sense of
43// the positional and keyword arguments provided by the caller.
44//
alandonovan6677ee52020-02-03 09:41:50 -050045// Starlark's None value is not equal to Go's nil. Go's nil is not a legal
46// Starlark value, but the compiler will not stop you from converting nil
47// to Value. Be careful to avoid allowing Go nil values to leak into
48// Starlark data structures.
Alan Donovan312d1a52017-10-02 10:10:28 -040049//
50// The Compare operation requires two arguments of the same
51// type, but this constraint cannot be expressed in Go's type system.
52// (This is the classic "binary method problem".)
53// So, each Value type's CompareSameType method is a partial function
54// that compares a value only against others of the same type.
55// Use the package's standalone Compare (or Equal) function to compare
56// an arbitrary pair of values.
57//
Alan Donovane3deafe2018-10-23 11:05:09 -040058// To parse and evaluate a Starlark source file, use ExecFile. The Eval
Alan Donovan312d1a52017-10-02 10:10:28 -040059// function evaluates a single expression. All evaluator functions
60// require a Thread parameter which defines the "thread-local storage"
Alan Donovane3deafe2018-10-23 11:05:09 -040061// of a Starlark thread and may be used to plumb application state
alandonovan6677ee52020-02-03 09:41:50 -050062// through Starlark code and into callbacks. When evaluation fails it
Alan Donovan312d1a52017-10-02 10:10:28 -040063// returns an EvalError from which the application may obtain a
Alan Donovane3deafe2018-10-23 11:05:09 -040064// backtrace of active Starlark calls.
Alan Donovan312d1a52017-10-02 10:10:28 -040065//
Alan Donovan6beab7e2018-10-31 17:53:09 -040066package starlark // import "go.starlark.net/starlark"
Alan Donovan312d1a52017-10-02 10:10:28 -040067
Alan Donovane3deafe2018-10-23 11:05:09 -040068// This file defines the data types of Starlark and their basic operations.
Alan Donovan312d1a52017-10-02 10:10:28 -040069
70import (
Alan Donovan312d1a52017-10-02 10:10:28 -040071 "fmt"
72 "math"
73 "math/big"
74 "reflect"
75 "strconv"
76 "strings"
77 "unicode/utf8"
78
Alan Donovan6beab7e2018-10-31 17:53:09 -040079 "go.starlark.net/internal/compile"
80 "go.starlark.net/syntax"
Alan Donovan312d1a52017-10-02 10:10:28 -040081)
82
Alan Donovane3deafe2018-10-23 11:05:09 -040083// Value is a value in the Starlark interpreter.
Alan Donovan312d1a52017-10-02 10:10:28 -040084type Value interface {
85 // String returns the string representation of the value.
Alan Donovane3deafe2018-10-23 11:05:09 -040086 // Starlark string values are quoted as if by Python's repr.
Alan Donovan312d1a52017-10-02 10:10:28 -040087 String() string
88
89 // Type returns a short string describing the value's type.
90 Type() string
91
92 // Freeze causes the value, and all values transitively
93 // reachable from it through collections and closures, to be
94 // marked as frozen. All subsequent mutations to the data
95 // structure through this API will fail dynamically, making the
96 // data structure immutable and safe for publishing to other
Alan Donovane3deafe2018-10-23 11:05:09 -040097 // Starlark interpreters running concurrently.
Alan Donovan312d1a52017-10-02 10:10:28 -040098 Freeze()
99
alandonovan5ce1e422017-10-17 15:20:32 -0400100 // Truth returns the truth value of an object.
Alan Donovan312d1a52017-10-02 10:10:28 -0400101 Truth() Bool
102
103 // Hash returns a function of x such that Equals(x, y) => Hash(x) == Hash(y).
104 // Hash may fail if the value's type is not hashable, or if the value
alandonovane35f71a2019-05-14 14:50:48 -0400105 // contains a non-hashable value. The hash is used only by dictionaries and
106 // is not exposed to the Starlark program.
Alan Donovan312d1a52017-10-02 10:10:28 -0400107 Hash() (uint32, error)
108}
109
110// A Comparable is a value that defines its own equivalence relation and
111// perhaps ordered comparisons.
112type Comparable interface {
113 Value
114 // CompareSameType compares one value to another of the same Type().
115 // The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE.
116 // CompareSameType returns an error if an ordered comparison was
117 // requested for a type that does not support it.
118 //
119 // Implementations that recursively compare subcomponents of
120 // the value should use the CompareDepth function, not Compare, to
121 // avoid infinite recursion on cyclic structures.
122 //
123 // The depth parameter is used to bound comparisons of cyclic
124 // data structures. Implementations should decrement depth
125 // before calling CompareDepth and should return an error if depth
126 // < 1.
127 //
128 // Client code should not call this method. Instead, use the
129 // standalone Compare or Equals functions, which are defined for
130 // all pairs of operands.
131 CompareSameType(op syntax.Token, y Value, depth int) (bool, error)
132}
133
134var (
135 _ Comparable = None
136 _ Comparable = Int{}
137 _ Comparable = False
138 _ Comparable = Float(0)
139 _ Comparable = String("")
140 _ Comparable = (*Dict)(nil)
141 _ Comparable = (*List)(nil)
142 _ Comparable = Tuple(nil)
143 _ Comparable = (*Set)(nil)
144)
145
146// A Callable value f may be the operand of a function call, f(x).
alandonovanaeec83f2018-10-22 13:24:13 -0400147//
148// Clients should use the Call function, never the CallInternal method.
Alan Donovan312d1a52017-10-02 10:10:28 -0400149type Callable interface {
150 Value
151 Name() string
alandonovanaeec83f2018-10-22 13:24:13 -0400152 CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error)
Alan Donovan312d1a52017-10-02 10:10:28 -0400153}
154
alandonovan40b4ab62019-04-03 16:41:37 -0400155type callableWithPosition interface {
156 Callable
157 Position() syntax.Position
158}
159
Alan Donovan312d1a52017-10-02 10:10:28 -0400160var (
alandonovan40b4ab62019-04-03 16:41:37 -0400161 _ Callable = (*Builtin)(nil)
162 _ Callable = (*Function)(nil)
163 _ callableWithPosition = (*Function)(nil)
Alan Donovan312d1a52017-10-02 10:10:28 -0400164)
165
166// An Iterable abstracts a sequence of values.
167// An iterable value may be iterated over by a 'for' loop or used where
Alan Donovane3deafe2018-10-23 11:05:09 -0400168// any other Starlark iterable is allowed. Unlike a Sequence, the length
Alan Donovan312d1a52017-10-02 10:10:28 -0400169// of an Iterable is not necessarily known in advance of iteration.
170type Iterable interface {
171 Value
172 Iterate() Iterator // must be followed by call to Iterator.Done
173}
174
175// A Sequence is a sequence of values of known length.
176type Sequence interface {
177 Iterable
178 Len() int
179}
180
181var (
182 _ Sequence = (*Dict)(nil)
183 _ Sequence = (*Set)(nil)
184)
185
186// An Indexable is a sequence of known length that supports efficient random access.
187// It is not necessarily iterable.
188type Indexable interface {
189 Value
190 Index(i int) Value // requires 0 <= i < Len()
191 Len() int
192}
193
Nick Santosd3cd7362018-05-18 12:58:53 -0400194// A Sliceable is a sequence that can be cut into pieces with the slice operator (x[i:j:step]).
195//
196// All native indexable objects are sliceable.
197// This is a separate interface for backwards-compatibility.
198type Sliceable interface {
199 Indexable
200 // For positive strides (step > 0), 0 <= start <= end <= n.
201 // For negative strides (step < 0), -1 <= end <= start < n.
Josh Bleecher Snyderd5c553a2019-01-16 12:51:06 -0800202 // The caller must ensure that the start and end indices are valid
203 // and that step is non-zero.
Nick Santosd3cd7362018-05-18 12:58:53 -0400204 Slice(start, end, step int) Value
205}
206
Alan Donovan312d1a52017-10-02 10:10:28 -0400207// A HasSetIndex is an Indexable value whose elements may be assigned (x[i] = y).
208//
209// The implementation should not add Len to a negative index as the
210// evaluator does this before the call.
211type HasSetIndex interface {
212 Indexable
213 SetIndex(index int, v Value) error
214}
215
216var (
217 _ HasSetIndex = (*List)(nil)
218 _ Indexable = Tuple(nil)
219 _ Indexable = String("")
Nick Santosd3cd7362018-05-18 12:58:53 -0400220 _ Sliceable = Tuple(nil)
221 _ Sliceable = String("")
222 _ Sliceable = (*List)(nil)
Alan Donovan312d1a52017-10-02 10:10:28 -0400223)
224
225// An Iterator provides a sequence of values to the caller.
226//
227// The caller must call Done when the iterator is no longer needed.
228// Operations that modify a sequence will fail if it has active iterators.
229//
230// Example usage:
231//
232// iter := iterable.Iterator()
233// defer iter.Done()
234// var x Value
235// for iter.Next(&x) {
236// ...
237// }
238//
239type Iterator interface {
240 // If the iterator is exhausted, Next returns false.
241 // Otherwise it sets *p to the current element of the sequence,
242 // advances the iterator, and returns true.
243 Next(p *Value) bool
244 Done()
245}
246
jmillikin-stripe3ccab942018-10-05 07:09:12 -0700247// A Mapping is a mapping from keys to values, such as a dictionary.
alandonovan1ed64972019-01-04 13:04:39 -0500248//
249// If a type satisfies both Mapping and Iterable, the iterator yields
250// the keys of the mapping.
Alan Donovan312d1a52017-10-02 10:10:28 -0400251type Mapping interface {
252 Value
253 // Get returns the value corresponding to the specified key,
254 // or !found if the mapping does not contain the key.
alandonovan7f065b62018-03-19 14:58:49 -0400255 //
256 // Get also defines the behavior of "v in mapping".
257 // The 'in' operator reports the 'found' component, ignoring errors.
Alan Donovan312d1a52017-10-02 10:10:28 -0400258 Get(Value) (v Value, found bool, err error)
259}
260
alandonovan1ed64972019-01-04 13:04:39 -0500261// An IterableMapping is a mapping that supports key enumeration.
262type IterableMapping interface {
263 Mapping
264 Iterate() Iterator // see Iterable interface
265 Items() []Tuple // a new slice containing all key/value pairs
266}
267
268var _ IterableMapping = (*Dict)(nil)
Alan Donovan312d1a52017-10-02 10:10:28 -0400269
jmillikin-stripe3ccab942018-10-05 07:09:12 -0700270// A HasSetKey supports map update using x[k]=v syntax, like a dictionary.
271type HasSetKey interface {
272 Mapping
273 SetKey(k, v Value) error
274}
275
276var _ HasSetKey = (*Dict)(nil)
277
Alan Donovan312d1a52017-10-02 10:10:28 -0400278// A HasBinary value may be used as either operand of these binary operators:
alandonovan93b8d142019-01-06 11:57:29 -0500279// + - * / // % in not in | & ^ << >>
280//
Alan Donovan312d1a52017-10-02 10:10:28 -0400281// The Side argument indicates whether the receiver is the left or right operand.
282//
283// An implementation may decline to handle an operation by returning (nil, nil).
284// For this reason, clients should always call the standalone Binary(op, x, y)
285// function rather than calling the method directly.
286type HasBinary interface {
287 Value
288 Binary(op syntax.Token, y Value, side Side) (Value, error)
289}
290
291type Side bool
292
293const (
294 Left Side = false
295 Right Side = true
296)
297
alandonovan58f91012019-01-03 16:32:47 -0500298// A HasUnary value may be used as the operand of these unary operators:
299// + - ~
300//
301// An implementation may decline to handle an operation by returning (nil, nil).
302// For this reason, clients should always call the standalone Unary(op, x)
303// function rather than calling the method directly.
304type HasUnary interface {
305 Value
306 Unary(op syntax.Token) (Value, error)
307}
308
Alan Donovan312d1a52017-10-02 10:10:28 -0400309// A HasAttrs value has fields or methods that may be read by a dot expression (y = x.f).
310// Attribute names may be listed using the built-in 'dir' function.
311//
312// For implementation convenience, a result of (nil, nil) from Attr is
313// interpreted as a "no such field or method" error. Implementations are
314// free to return a more precise error.
315type HasAttrs interface {
316 Value
317 Attr(name string) (Value, error) // returns (nil, nil) if attribute not present
318 AttrNames() []string // callers must not modify the result.
319}
320
321var (
322 _ HasAttrs = String("")
323 _ HasAttrs = new(List)
324 _ HasAttrs = new(Dict)
325 _ HasAttrs = new(Set)
326)
327
328// A HasSetField value has fields that may be written by a dot expression (x.f = y).
Alan Donovan557c1f12019-02-04 16:12:53 -0500329//
alandonovan6afa1bb2019-02-06 17:49:05 -0500330// An implementation of SetField may return a NoSuchAttrError,
331// in which case the runtime may augment the error message to
332// warn of possible misspelling.
Alan Donovan312d1a52017-10-02 10:10:28 -0400333type HasSetField interface {
334 HasAttrs
335 SetField(name string, val Value) error
336}
337
alandonovan6afa1bb2019-02-06 17:49:05 -0500338// A NoSuchAttrError may be returned by an implementation of
339// HasAttrs.Attr or HasSetField.SetField to indicate that no such field
340// exists. In that case the runtime may augment the error message to
341// warn of possible misspelling.
342type NoSuchAttrError string
343
344func (e NoSuchAttrError) Error() string { return string(e) }
Alan Donovan557c1f12019-02-04 16:12:53 -0500345
Alan Donovan312d1a52017-10-02 10:10:28 -0400346// NoneType is the type of None. Its only legal value is None.
347// (We represent it as a number, not struct{}, so that None may be constant.)
348type NoneType byte
349
350const None = NoneType(0)
351
352func (NoneType) String() string { return "None" }
353func (NoneType) Type() string { return "NoneType" }
354func (NoneType) Freeze() {} // immutable
355func (NoneType) Truth() Bool { return False }
356func (NoneType) Hash() (uint32, error) { return 0, nil }
357func (NoneType) CompareSameType(op syntax.Token, y Value, depth int) (bool, error) {
358 return threeway(op, 0), nil
359}
360
Alan Donovane3deafe2018-10-23 11:05:09 -0400361// Bool is the type of a Starlark bool.
Alan Donovan312d1a52017-10-02 10:10:28 -0400362type Bool bool
363
364const (
365 False Bool = false
366 True Bool = true
367)
368
369func (b Bool) String() string {
370 if b {
371 return "True"
372 } else {
373 return "False"
374 }
375}
376func (b Bool) Type() string { return "bool" }
377func (b Bool) Freeze() {} // immutable
378func (b Bool) Truth() Bool { return b }
379func (b Bool) Hash() (uint32, error) { return uint32(b2i(bool(b))), nil }
380func (x Bool) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
381 y := y_.(Bool)
382 return threeway(op, b2i(bool(x))-b2i(bool(y))), nil
383}
384
Alan Donovane3deafe2018-10-23 11:05:09 -0400385// Float is the type of a Starlark float.
Alan Donovan312d1a52017-10-02 10:10:28 -0400386type Float float64
387
388func (f Float) String() string { return strconv.FormatFloat(float64(f), 'g', 6, 64) }
389func (f Float) Type() string { return "float" }
390func (f Float) Freeze() {} // immutable
391func (f Float) Truth() Bool { return f != 0.0 }
392func (f Float) Hash() (uint32, error) {
393 // Equal float and int values must yield the same hash.
394 // TODO(adonovan): opt: if f is non-integral, and thus not equal
395 // to any Int, we can avoid the Int conversion and use a cheaper hash.
396 if isFinite(float64(f)) {
397 return finiteFloatToInt(f).Hash()
398 }
399 return 1618033, nil // NaN, +/-Inf
400}
401
402func floor(f Float) Float { return Float(math.Floor(float64(f))) }
403
404// isFinite reports whether f represents a finite rational value.
405// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
406func isFinite(f float64) bool {
407 return math.Abs(f) <= math.MaxFloat64
408}
409
410func (x Float) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
411 y := y_.(Float)
412 switch op {
413 case syntax.EQL:
414 return x == y, nil
415 case syntax.NEQ:
416 return x != y, nil
417 case syntax.LE:
418 return x <= y, nil
419 case syntax.LT:
420 return x < y, nil
421 case syntax.GE:
422 return x >= y, nil
423 case syntax.GT:
424 return x > y, nil
425 }
426 panic(op)
427}
428
429func (f Float) rational() *big.Rat { return new(big.Rat).SetFloat64(float64(f)) }
430
431// AsFloat returns the float64 value closest to x.
432// The f result is undefined if x is not a float or int.
433func AsFloat(x Value) (f float64, ok bool) {
434 switch x := x.(type) {
435 case Float:
436 return float64(x), true
437 case Int:
438 return float64(x.Float()), true
439 }
440 return 0, false
441}
442
alandonovan227f4aa2020-10-06 17:39:52 -0400443func (x Float) Mod(y Float) Float {
444 z := Float(math.Mod(float64(x), float64(y)))
445 if (x < 0) != (y < 0) && z != 0 {
446 z += y
447 }
448 return z
449}
Alan Donovan312d1a52017-10-02 10:10:28 -0400450
alandonovan58f91012019-01-03 16:32:47 -0500451// Unary implements the operations +float and -float.
452func (f Float) Unary(op syntax.Token) (Value, error) {
453 switch op {
454 case syntax.MINUS:
455 return -f, nil
456 case syntax.PLUS:
457 return +f, nil
458 }
459 return nil, nil
460}
461
Alan Donovane3deafe2018-10-23 11:05:09 -0400462// String is the type of a Starlark string.
Alan Donovan312d1a52017-10-02 10:10:28 -0400463//
alandonovana21eb0f2018-06-25 15:30:48 -0400464// A String encapsulates an an immutable sequence of bytes,
465// but strings are not directly iterable. Instead, iterate
466// over the result of calling one of these four methods:
467// codepoints, codepoint_ords, elems, elem_ords.
alandonovanc996ede2018-10-12 13:53:43 -0400468//
469// Warning: the contract of the Value interface's String method is that
Alan Donovane3deafe2018-10-23 11:05:09 -0400470// it returns the value printed in Starlark notation,
alandonovanc996ede2018-10-12 13:53:43 -0400471// so s.String() or fmt.Sprintf("%s", s) returns a quoted string.
472// Use string(s) or s.GoString() or fmt.Sprintf("%#v", s) to obtain the raw contents
Alan Donovane3deafe2018-10-23 11:05:09 -0400473// of a Starlark string as a Go string.
Alan Donovan312d1a52017-10-02 10:10:28 -0400474type String string
475
476func (s String) String() string { return strconv.Quote(string(s)) }
alandonovanc996ede2018-10-12 13:53:43 -0400477func (s String) GoString() string { return string(s) }
Alan Donovan312d1a52017-10-02 10:10:28 -0400478func (s String) Type() string { return "string" }
479func (s String) Freeze() {} // immutable
480func (s String) Truth() Bool { return len(s) > 0 }
481func (s String) Hash() (uint32, error) { return hashString(string(s)), nil }
482func (s String) Len() int { return len(s) } // bytes
483func (s String) Index(i int) Value { return s[i : i+1] }
484
Nick Santosd3cd7362018-05-18 12:58:53 -0400485func (s String) Slice(start, end, step int) Value {
486 if step == 1 {
alandonovan5c7d5aa2018-12-03 17:05:15 -0500487 return s[start:end]
Nick Santosd3cd7362018-05-18 12:58:53 -0400488 }
489
490 sign := signum(step)
491 var str []byte
492 for i := start; signum(end-i) == sign; i += step {
493 str = append(str, s[i])
494 }
495 return String(str)
496}
497
Alan Donovan312d1a52017-10-02 10:10:28 -0400498func (s String) Attr(name string) (Value, error) { return builtinAttr(s, name, stringMethods) }
499func (s String) AttrNames() []string { return builtinAttrNames(stringMethods) }
500
501func (x String) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
502 y := y_.(String)
503 return threeway(op, strings.Compare(string(x), string(y))), nil
504}
505
506func AsString(x Value) (string, bool) { v, ok := x.(String); return string(v), ok }
507
508// A stringIterable is an iterable whose iterator yields a sequence of
alandonovanfa00d7b2018-03-05 14:40:59 -0500509// either Unicode code points or elements (bytes),
Alan Donovan312d1a52017-10-02 10:10:28 -0400510// either numerically or as successive substrings.
511type stringIterable struct {
512 s String
alandonovan0569d1c2018-03-29 14:47:42 -0400513 ords bool
Alan Donovan312d1a52017-10-02 10:10:28 -0400514 codepoints bool
515}
516
517var _ Iterable = (*stringIterable)(nil)
518
519func (si stringIterable) String() string {
alandonovan0569d1c2018-03-29 14:47:42 -0400520 var etype string
521 if si.codepoints {
522 etype = "codepoint"
Alan Donovan312d1a52017-10-02 10:10:28 -0400523 } else {
alandonovan0569d1c2018-03-29 14:47:42 -0400524 etype = "elem"
525 }
526 if si.ords {
527 return si.s.String() + "." + etype + "_ords()"
528 } else {
529 return si.s.String() + "." + etype + "s()"
Alan Donovan312d1a52017-10-02 10:10:28 -0400530 }
531}
532func (si stringIterable) Type() string {
533 if si.codepoints {
534 return "codepoints"
535 } else {
alandonovanfa00d7b2018-03-05 14:40:59 -0500536 return "elems"
Alan Donovan312d1a52017-10-02 10:10:28 -0400537 }
538}
539func (si stringIterable) Freeze() {} // immutable
540func (si stringIterable) Truth() Bool { return True }
541func (si stringIterable) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", si.Type()) }
542func (si stringIterable) Iterate() Iterator { return &stringIterator{si, 0} }
543
544type stringIterator struct {
545 si stringIterable
546 i int
547}
548
549func (it *stringIterator) Next(p *Value) bool {
550 s := it.si.s[it.i:]
551 if s == "" {
552 return false
553 }
554 if it.si.codepoints {
555 r, sz := utf8.DecodeRuneInString(string(s))
alandonovan0569d1c2018-03-29 14:47:42 -0400556 if !it.si.ords {
Alan Donovan312d1a52017-10-02 10:10:28 -0400557 *p = s[:sz]
558 } else {
559 *p = MakeInt(int(r))
560 }
561 it.i += sz
562 } else {
563 b := int(s[0])
alandonovan0569d1c2018-03-29 14:47:42 -0400564 if !it.si.ords {
Alan Donovan312d1a52017-10-02 10:10:28 -0400565 *p = s[:1]
566 } else {
567 *p = MakeInt(b)
568 }
569 it.i += 1
570 }
571 return true
572}
573
574func (*stringIterator) Done() {}
575
Alan Donovane3deafe2018-10-23 11:05:09 -0400576// A Function is a function defined by a Starlark def statement or lambda expression.
577// The initialization behavior of a Starlark module is also represented by a Function.
Alan Donovan312d1a52017-10-02 10:10:28 -0400578type Function struct {
alandonovan8c4023c2018-04-02 13:08:46 -0400579 funcode *compile.Funcode
alandonovan3ee16852019-05-28 15:56:13 -0400580 module *module
alandonovan8c4023c2018-04-02 13:08:46 -0400581 defaults Tuple
582 freevars Tuple
alandonovan3ee16852019-05-28 15:56:13 -0400583}
alandonovan8c4023c2018-04-02 13:08:46 -0400584
alandonovan3ee16852019-05-28 15:56:13 -0400585// A module is the dynamic counterpart to a Program.
586// All functions in the same program share a module.
587type module struct {
588 program *compile.Program
alandonovan8c4023c2018-04-02 13:08:46 -0400589 predeclared StringDict
590 globals []Value
591 constants []Value
Alan Donovan312d1a52017-10-02 10:10:28 -0400592}
593
alandonovan3ee16852019-05-28 15:56:13 -0400594// makeGlobalDict returns a new, unfrozen StringDict containing all global
595// variables so far defined in the module.
596func (m *module) makeGlobalDict() StringDict {
597 r := make(StringDict, len(m.program.Globals))
598 for i, id := range m.program.Globals {
599 if v := m.globals[i]; v != nil {
600 r[id.Name] = v
601 }
602 }
603 return r
604}
605
alandonovan93f3e0c2018-03-30 10:42:28 -0400606func (fn *Function) Name() string { return fn.funcode.Name } // "lambda" for anonymous functions
Alessandro Arzilli3b628ff2018-12-05 15:04:35 +0100607func (fn *Function) Doc() string { return fn.funcode.Doc }
alandonovan93f3e0c2018-03-30 10:42:28 -0400608func (fn *Function) Hash() (uint32, error) { return hashString(fn.funcode.Name), nil }
Alan Donovan312d1a52017-10-02 10:10:28 -0400609func (fn *Function) Freeze() { fn.defaults.Freeze(); fn.freevars.Freeze() }
610func (fn *Function) String() string { return toString(fn) }
611func (fn *Function) Type() string { return "function" }
612func (fn *Function) Truth() Bool { return true }
613
alandonovan93f3e0c2018-03-30 10:42:28 -0400614// Globals returns a new, unfrozen StringDict containing all global
615// variables so far defined in the function's module.
alandonovan3ee16852019-05-28 15:56:13 -0400616func (fn *Function) Globals() StringDict { return fn.module.makeGlobalDict() }
alandonovan93f3e0c2018-03-30 10:42:28 -0400617
618func (fn *Function) Position() syntax.Position { return fn.funcode.Pos }
619func (fn *Function) NumParams() int { return fn.funcode.NumParams }
Alan Donovan52153852019-02-13 19:18:15 -0500620func (fn *Function) NumKwonlyParams() int { return fn.funcode.NumKwonlyParams }
alandonovan9b055552018-11-02 14:29:51 -0400621
622// Param returns the name and position of the ith parameter,
623// where 0 <= i < NumParams().
Alan Donovan52153852019-02-13 19:18:15 -0500624// The *args and **kwargs parameters are at the end
625// even if there were optional parameters after *args.
alandonovan93f3e0c2018-03-30 10:42:28 -0400626func (fn *Function) Param(i int) (string, syntax.Position) {
alandonovanfc7a7f42019-07-16 22:31:58 -0400627 if i >= fn.NumParams() {
628 panic(i)
629 }
alandonovan93f3e0c2018-03-30 10:42:28 -0400630 id := fn.funcode.Locals[i]
631 return id.Name, id.Pos
632}
633func (fn *Function) HasVarargs() bool { return fn.funcode.HasVarargs }
634func (fn *Function) HasKwargs() bool { return fn.funcode.HasKwargs }
Alan Donovan312d1a52017-10-02 10:10:28 -0400635
636// A Builtin is a function implemented in Go.
637type Builtin struct {
638 name string
639 fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error)
640 recv Value // for bound methods (e.g. "".startswith)
641}
642
643func (b *Builtin) Name() string { return b.name }
644func (b *Builtin) Freeze() {
645 if b.recv != nil {
646 b.recv.Freeze()
647 }
648}
649func (b *Builtin) Hash() (uint32, error) {
650 h := hashString(b.name)
651 if b.recv != nil {
652 h ^= 5521
653 }
654 return h, nil
655}
656func (b *Builtin) Receiver() Value { return b.recv }
657func (b *Builtin) String() string { return toString(b) }
alandonovan4cbd8962017-10-19 13:18:36 -0400658func (b *Builtin) Type() string { return "builtin_function_or_method" }
alandonovanaeec83f2018-10-22 13:24:13 -0400659func (b *Builtin) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) {
660 return b.fn(thread, b, args, kwargs)
Alan Donovan312d1a52017-10-02 10:10:28 -0400661}
662func (b *Builtin) Truth() Bool { return true }
663
alandonovan4cbd8962017-10-19 13:18:36 -0400664// NewBuiltin returns a new 'builtin_function_or_method' value with the specified name
Alan Donovan312d1a52017-10-02 10:10:28 -0400665// and implementation. It compares unequal with all other values.
666func NewBuiltin(name string, fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error)) *Builtin {
667 return &Builtin{name: name, fn: fn}
668}
669
670// BindReceiver returns a new Builtin value representing a method
671// closure, that is, a built-in function bound to a receiver value.
672//
alandonovan4cbd8962017-10-19 13:18:36 -0400673// In the example below, the value of f is the string.index
674// built-in method bound to the receiver value "abc":
Alan Donovan312d1a52017-10-02 10:10:28 -0400675//
676// f = "abc".index; f("a"); f("b")
677//
678// In the common case, the receiver is bound only during the call,
679// but this still results in the creation of a temporary method closure:
680//
681// "abc".index("a")
682//
683func (b *Builtin) BindReceiver(recv Value) *Builtin {
684 return &Builtin{name: b.name, fn: b.fn, recv: recv}
685}
686
Alan Donovane3deafe2018-10-23 11:05:09 -0400687// A *Dict represents a Starlark dictionary.
alandonovanf83458d2019-04-02 20:34:11 -0400688// The zero value of Dict is a valid empty dictionary.
689// If you know the exact final number of entries,
690// it is more efficient to call NewDict.
Alan Donovan312d1a52017-10-02 10:10:28 -0400691type Dict struct {
692 ht hashtable
693}
694
alandonovanf83458d2019-04-02 20:34:11 -0400695// NewDict returns a set with initial space for
696// at least size insertions before rehashing.
697func NewDict(size int) *Dict {
698 dict := new(Dict)
699 dict.ht.init(size)
700 return dict
701}
702
Alan Donovan312d1a52017-10-02 10:10:28 -0400703func (d *Dict) Clear() error { return d.ht.clear() }
704func (d *Dict) Delete(k Value) (v Value, found bool, err error) { return d.ht.delete(k) }
705func (d *Dict) Get(k Value) (v Value, found bool, err error) { return d.ht.lookup(k) }
706func (d *Dict) Items() []Tuple { return d.ht.items() }
707func (d *Dict) Keys() []Value { return d.ht.keys() }
708func (d *Dict) Len() int { return int(d.ht.len) }
709func (d *Dict) Iterate() Iterator { return d.ht.iterate() }
jmillikin-stripe3ccab942018-10-05 07:09:12 -0700710func (d *Dict) SetKey(k, v Value) error { return d.ht.insert(k, v) }
Alan Donovan312d1a52017-10-02 10:10:28 -0400711func (d *Dict) String() string { return toString(d) }
712func (d *Dict) Type() string { return "dict" }
713func (d *Dict) Freeze() { d.ht.freeze() }
714func (d *Dict) Truth() Bool { return d.Len() > 0 }
715func (d *Dict) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: dict") }
716
717func (d *Dict) Attr(name string) (Value, error) { return builtinAttr(d, name, dictMethods) }
718func (d *Dict) AttrNames() []string { return builtinAttrNames(dictMethods) }
719
720func (x *Dict) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
721 y := y_.(*Dict)
722 switch op {
723 case syntax.EQL:
724 ok, err := dictsEqual(x, y, depth)
725 return ok, err
726 case syntax.NEQ:
727 ok, err := dictsEqual(x, y, depth)
728 return !ok, err
729 default:
730 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
731 }
732}
733
734func dictsEqual(x, y *Dict, depth int) (bool, error) {
735 if x.Len() != y.Len() {
736 return false, nil
737 }
738 for _, xitem := range x.Items() {
739 key, xval := xitem[0], xitem[1]
740
741 if yval, found, _ := y.Get(key); !found {
742 return false, nil
743 } else if eq, err := EqualDepth(xval, yval, depth-1); err != nil {
744 return false, err
745 } else if !eq {
746 return false, nil
747 }
748 }
749 return true, nil
750}
751
Alan Donovane3deafe2018-10-23 11:05:09 -0400752// A *List represents a Starlark list value.
Alan Donovan312d1a52017-10-02 10:10:28 -0400753type List struct {
754 elems []Value
755 frozen bool
756 itercount uint32 // number of active iterators (ignored if frozen)
757}
758
759// NewList returns a list containing the specified elements.
760// Callers should not subsequently modify elems.
761func NewList(elems []Value) *List { return &List{elems: elems} }
762
763func (l *List) Freeze() {
764 if !l.frozen {
765 l.frozen = true
766 for _, elem := range l.elems {
767 elem.Freeze()
768 }
769 }
770}
771
772// checkMutable reports an error if the list should not be mutated.
773// verb+" list" should describe the operation.
alandonovan7c0e5a32018-11-02 15:38:05 -0400774func (l *List) checkMutable(verb string) error {
Alan Donovan312d1a52017-10-02 10:10:28 -0400775 if l.frozen {
776 return fmt.Errorf("cannot %s frozen list", verb)
777 }
alandonovan7c0e5a32018-11-02 15:38:05 -0400778 if l.itercount > 0 {
Alan Donovan312d1a52017-10-02 10:10:28 -0400779 return fmt.Errorf("cannot %s list during iteration", verb)
780 }
781 return nil
782}
783
784func (l *List) String() string { return toString(l) }
785func (l *List) Type() string { return "list" }
786func (l *List) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: list") }
787func (l *List) Truth() Bool { return l.Len() > 0 }
788func (l *List) Len() int { return len(l.elems) }
789func (l *List) Index(i int) Value { return l.elems[i] }
790
Nick Santosd3cd7362018-05-18 12:58:53 -0400791func (l *List) Slice(start, end, step int) Value {
792 if step == 1 {
793 elems := append([]Value{}, l.elems[start:end]...)
794 return NewList(elems)
795 }
796
797 sign := signum(step)
798 var list []Value
799 for i := start; signum(end-i) == sign; i += step {
800 list = append(list, l.elems[i])
801 }
802 return NewList(list)
803}
804
Alan Donovan312d1a52017-10-02 10:10:28 -0400805func (l *List) Attr(name string) (Value, error) { return builtinAttr(l, name, listMethods) }
806func (l *List) AttrNames() []string { return builtinAttrNames(listMethods) }
807
808func (l *List) Iterate() Iterator {
809 if !l.frozen {
810 l.itercount++
811 }
812 return &listIterator{l: l}
813}
814
815func (x *List) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
816 y := y_.(*List)
817 // It's tempting to check x == y as an optimization here,
818 // but wrong because a list containing NaN is not equal to itself.
819 return sliceCompare(op, x.elems, y.elems, depth)
820}
821
822func sliceCompare(op syntax.Token, x, y []Value, depth int) (bool, error) {
823 // Fast path: check length.
824 if len(x) != len(y) && (op == syntax.EQL || op == syntax.NEQ) {
825 return op == syntax.NEQ, nil
826 }
827
828 // Find first element that is not equal in both lists.
829 for i := 0; i < len(x) && i < len(y); i++ {
830 if eq, err := EqualDepth(x[i], y[i], depth-1); err != nil {
831 return false, err
832 } else if !eq {
833 switch op {
834 case syntax.EQL:
835 return false, nil
836 case syntax.NEQ:
837 return true, nil
838 default:
839 return CompareDepth(op, x[i], y[i], depth-1)
840 }
841 }
842 }
843
844 return threeway(op, len(x)-len(y)), nil
845}
846
847type listIterator struct {
848 l *List
849 i int
850}
851
852func (it *listIterator) Next(p *Value) bool {
853 if it.i < it.l.Len() {
854 *p = it.l.elems[it.i]
855 it.i++
856 return true
857 }
858 return false
859}
860
861func (it *listIterator) Done() {
862 if !it.l.frozen {
863 it.l.itercount--
864 }
865}
866
867func (l *List) SetIndex(i int, v Value) error {
alandonovan7c0e5a32018-11-02 15:38:05 -0400868 if err := l.checkMutable("assign to element of"); err != nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400869 return err
870 }
871 l.elems[i] = v
872 return nil
873}
874
875func (l *List) Append(v Value) error {
alandonovan7c0e5a32018-11-02 15:38:05 -0400876 if err := l.checkMutable("append to"); err != nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400877 return err
878 }
879 l.elems = append(l.elems, v)
880 return nil
881}
882
883func (l *List) Clear() error {
alandonovan7c0e5a32018-11-02 15:38:05 -0400884 if err := l.checkMutable("clear"); err != nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400885 return err
886 }
887 for i := range l.elems {
888 l.elems[i] = nil // aid GC
889 }
890 l.elems = l.elems[:0]
891 return nil
892}
893
Alan Donovane3deafe2018-10-23 11:05:09 -0400894// A Tuple represents a Starlark tuple value.
Alan Donovan312d1a52017-10-02 10:10:28 -0400895type Tuple []Value
896
897func (t Tuple) Len() int { return len(t) }
898func (t Tuple) Index(i int) Value { return t[i] }
Nick Santosd3cd7362018-05-18 12:58:53 -0400899
900func (t Tuple) Slice(start, end, step int) Value {
901 if step == 1 {
902 return t[start:end]
903 }
904
905 sign := signum(step)
906 var tuple Tuple
907 for i := start; signum(end-i) == sign; i += step {
908 tuple = append(tuple, t[i])
909 }
910 return tuple
911}
912
Alan Donovan312d1a52017-10-02 10:10:28 -0400913func (t Tuple) Iterate() Iterator { return &tupleIterator{elems: t} }
914func (t Tuple) Freeze() {
915 for _, elem := range t {
916 elem.Freeze()
917 }
918}
919func (t Tuple) String() string { return toString(t) }
920func (t Tuple) Type() string { return "tuple" }
921func (t Tuple) Truth() Bool { return len(t) > 0 }
922
923func (x Tuple) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
924 y := y_.(Tuple)
925 return sliceCompare(op, x, y, depth)
926}
927
928func (t Tuple) Hash() (uint32, error) {
929 // Use same algorithm as Python.
930 var x, mult uint32 = 0x345678, 1000003
931 for _, elem := range t {
932 y, err := elem.Hash()
933 if err != nil {
934 return 0, err
935 }
936 x = x ^ y*mult
937 mult += 82520 + uint32(len(t)+len(t))
938 }
939 return x, nil
940}
941
942type tupleIterator struct{ elems Tuple }
943
944func (it *tupleIterator) Next(p *Value) bool {
945 if len(it.elems) > 0 {
946 *p = it.elems[0]
947 it.elems = it.elems[1:]
948 return true
949 }
950 return false
951}
952
953func (it *tupleIterator) Done() {}
954
Alan Donovane3deafe2018-10-23 11:05:09 -0400955// A Set represents a Starlark set value.
alandonovanf83458d2019-04-02 20:34:11 -0400956// The zero value of Set is a valid empty set.
957// If you know the exact final number of elements,
958// it is more efficient to call NewSet.
Alan Donovan312d1a52017-10-02 10:10:28 -0400959type Set struct {
960 ht hashtable // values are all None
961}
962
alandonovanf83458d2019-04-02 20:34:11 -0400963// NewSet returns a dictionary with initial space for
964// at least size insertions before rehashing.
965func NewSet(size int) *Set {
966 set := new(Set)
967 set.ht.init(size)
968 return set
969}
970
Alan Donovan312d1a52017-10-02 10:10:28 -0400971func (s *Set) Delete(k Value) (found bool, err error) { _, found, err = s.ht.delete(k); return }
972func (s *Set) Clear() error { return s.ht.clear() }
973func (s *Set) Has(k Value) (found bool, err error) { _, found, err = s.ht.lookup(k); return }
974func (s *Set) Insert(k Value) error { return s.ht.insert(k, None) }
975func (s *Set) Len() int { return int(s.ht.len) }
976func (s *Set) Iterate() Iterator { return s.ht.iterate() }
977func (s *Set) String() string { return toString(s) }
978func (s *Set) Type() string { return "set" }
979func (s *Set) elems() []Value { return s.ht.keys() }
980func (s *Set) Freeze() { s.ht.freeze() }
981func (s *Set) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: set") }
982func (s *Set) Truth() Bool { return s.Len() > 0 }
983
984func (s *Set) Attr(name string) (Value, error) { return builtinAttr(s, name, setMethods) }
985func (s *Set) AttrNames() []string { return builtinAttrNames(setMethods) }
986
987func (x *Set) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
988 y := y_.(*Set)
989 switch op {
990 case syntax.EQL:
991 ok, err := setsEqual(x, y, depth)
992 return ok, err
993 case syntax.NEQ:
994 ok, err := setsEqual(x, y, depth)
995 return !ok, err
996 default:
997 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
998 }
999}
1000
1001func setsEqual(x, y *Set, depth int) (bool, error) {
1002 if x.Len() != y.Len() {
1003 return false, nil
1004 }
1005 for _, elem := range x.elems() {
1006 if found, _ := y.Has(elem); !found {
1007 return false, nil
1008 }
1009 }
1010 return true, nil
1011}
1012
1013func (s *Set) Union(iter Iterator) (Value, error) {
1014 set := new(Set)
1015 for _, elem := range s.elems() {
1016 set.Insert(elem) // can't fail
1017 }
1018 var x Value
1019 for iter.Next(&x) {
1020 if err := set.Insert(x); err != nil {
1021 return nil, err
1022 }
1023 }
1024 return set, nil
1025}
1026
1027// toString returns the string form of value v.
1028// It may be more efficient than v.String() for larger values.
1029func toString(v Value) string {
Josh Bleecher Snyder8cb25c82019-03-01 14:24:35 -08001030 buf := new(strings.Builder)
1031 writeValue(buf, v, nil)
Alan Donovan312d1a52017-10-02 10:10:28 -04001032 return buf.String()
1033}
1034
alandonovan0ed7e5b2019-01-03 16:11:58 -05001035// writeValue writes x to out.
1036//
1037// path is used to detect cycles.
1038// It contains the list of *List and *Dict values we're currently printing.
Alan Donovan312d1a52017-10-02 10:10:28 -04001039// (These are the only potentially cyclic structures.)
Josh Bleecher Snyder81e440d2019-03-02 07:02:02 -08001040// Callers should generally pass nil for path.
alandonovan0ed7e5b2019-01-03 16:11:58 -05001041// It is safe to re-use the same path slice for multiple calls.
Josh Bleecher Snyder8cb25c82019-03-01 14:24:35 -08001042func writeValue(out *strings.Builder, x Value, path []Value) {
Alan Donovan312d1a52017-10-02 10:10:28 -04001043 switch x := x.(type) {
alandonovan15a68dc2018-03-05 16:23:41 -05001044 case nil:
1045 out.WriteString("<nil>") // indicates a bug
1046
Alan Donovan312d1a52017-10-02 10:10:28 -04001047 case NoneType:
1048 out.WriteString("None")
1049
1050 case Int:
1051 out.WriteString(x.String())
1052
1053 case Bool:
1054 if x {
1055 out.WriteString("True")
1056 } else {
1057 out.WriteString("False")
1058 }
1059
1060 case String:
1061 fmt.Fprintf(out, "%q", string(x))
1062
1063 case *List:
1064 out.WriteByte('[')
1065 if pathContains(path, x) {
1066 out.WriteString("...") // list contains itself
1067 } else {
1068 for i, elem := range x.elems {
1069 if i > 0 {
1070 out.WriteString(", ")
1071 }
1072 writeValue(out, elem, append(path, x))
1073 }
1074 }
1075 out.WriteByte(']')
1076
1077 case Tuple:
1078 out.WriteByte('(')
1079 for i, elem := range x {
1080 if i > 0 {
1081 out.WriteString(", ")
1082 }
1083 writeValue(out, elem, path)
1084 }
1085 if len(x) == 1 {
1086 out.WriteByte(',')
1087 }
1088 out.WriteByte(')')
1089
1090 case *Function:
1091 fmt.Fprintf(out, "<function %s>", x.Name())
1092
1093 case *Builtin:
1094 if x.recv != nil {
1095 fmt.Fprintf(out, "<built-in method %s of %s value>", x.Name(), x.recv.Type())
1096 } else {
1097 fmt.Fprintf(out, "<built-in function %s>", x.Name())
1098 }
1099
1100 case *Dict:
1101 out.WriteByte('{')
1102 if pathContains(path, x) {
1103 out.WriteString("...") // dict contains itself
1104 } else {
1105 sep := ""
1106 for _, item := range x.Items() {
1107 k, v := item[0], item[1]
1108 out.WriteString(sep)
1109 writeValue(out, k, path)
1110 out.WriteString(": ")
1111 writeValue(out, v, append(path, x)) // cycle check
1112 sep = ", "
1113 }
1114 }
1115 out.WriteByte('}')
1116
1117 case *Set:
1118 out.WriteString("set([")
1119 for i, elem := range x.elems() {
1120 if i > 0 {
1121 out.WriteString(", ")
1122 }
1123 writeValue(out, elem, path)
1124 }
1125 out.WriteString("])")
1126
1127 default:
1128 out.WriteString(x.String())
1129 }
1130}
1131
1132func pathContains(path []Value, x Value) bool {
1133 for _, y := range path {
1134 if x == y {
1135 return true
1136 }
1137 }
1138 return false
1139}
1140
1141const maxdepth = 10
1142
Alan Donovane3deafe2018-10-23 11:05:09 -04001143// Equal reports whether two Starlark values are equal.
Alan Donovan312d1a52017-10-02 10:10:28 -04001144func Equal(x, y Value) (bool, error) {
alandonovan4bb5ab62018-03-06 20:21:45 -05001145 if x, ok := x.(String); ok {
1146 return x == y, nil // fast path for an important special case
1147 }
Alan Donovan312d1a52017-10-02 10:10:28 -04001148 return EqualDepth(x, y, maxdepth)
1149}
1150
Alan Donovane3deafe2018-10-23 11:05:09 -04001151// EqualDepth reports whether two Starlark values are equal.
Alan Donovan312d1a52017-10-02 10:10:28 -04001152//
1153// Recursive comparisons by implementations of Value.CompareSameType
1154// should use EqualDepth to prevent infinite recursion.
1155func EqualDepth(x, y Value, depth int) (bool, error) {
1156 return CompareDepth(syntax.EQL, x, y, depth)
1157}
1158
Alan Donovane3deafe2018-10-23 11:05:09 -04001159// Compare compares two Starlark values.
Alan Donovan312d1a52017-10-02 10:10:28 -04001160// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE.
1161// Compare returns an error if an ordered comparison was
1162// requested for a type that does not support it.
1163//
1164// Recursive comparisons by implementations of Value.CompareSameType
1165// should use CompareDepth to prevent infinite recursion.
1166func Compare(op syntax.Token, x, y Value) (bool, error) {
1167 return CompareDepth(op, x, y, maxdepth)
1168}
1169
Alan Donovane3deafe2018-10-23 11:05:09 -04001170// CompareDepth compares two Starlark values.
Alan Donovan312d1a52017-10-02 10:10:28 -04001171// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE.
1172// CompareDepth returns an error if an ordered comparison was
1173// requested for a pair of values that do not support it.
1174//
1175// The depth parameter limits the maximum depth of recursion
1176// in cyclic data structures.
1177func CompareDepth(op syntax.Token, x, y Value, depth int) (bool, error) {
1178 if depth < 1 {
1179 return false, fmt.Errorf("comparison exceeded maximum recursion depth")
1180 }
1181 if sameType(x, y) {
1182 if xcomp, ok := x.(Comparable); ok {
1183 return xcomp.CompareSameType(op, y, depth)
1184 }
1185
1186 // use identity comparison
1187 switch op {
1188 case syntax.EQL:
1189 return x == y, nil
1190 case syntax.NEQ:
1191 return x != y, nil
1192 }
1193 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
1194 }
1195
1196 // different types
1197
1198 // int/float ordered comparisons
1199 switch x := x.(type) {
1200 case Int:
1201 if y, ok := y.(Float); ok {
1202 if y != y {
1203 return false, nil // y is NaN
1204 }
1205 var cmp int
1206 if !math.IsInf(float64(y), 0) {
1207 cmp = x.rational().Cmp(y.rational()) // y is finite
1208 } else if y > 0 {
1209 cmp = -1 // y is +Inf
1210 } else {
1211 cmp = +1 // y is -Inf
1212 }
1213 return threeway(op, cmp), nil
1214 }
1215 case Float:
1216 if y, ok := y.(Int); ok {
1217 if x != x {
1218 return false, nil // x is NaN
1219 }
1220 var cmp int
1221 if !math.IsInf(float64(x), 0) {
1222 cmp = x.rational().Cmp(y.rational()) // x is finite
1223 } else if x > 0 {
1224 cmp = -1 // x is +Inf
1225 } else {
1226 cmp = +1 // x is -Inf
1227 }
1228 return threeway(op, cmp), nil
1229 }
1230 }
1231
1232 // All other values of different types compare unequal.
1233 switch op {
1234 case syntax.EQL:
1235 return false, nil
1236 case syntax.NEQ:
1237 return true, nil
1238 }
1239 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
1240}
1241
1242func sameType(x, y Value) bool {
1243 return reflect.TypeOf(x) == reflect.TypeOf(y) || x.Type() == y.Type()
1244}
1245
1246// threeway interprets a three-way comparison value cmp (-1, 0, +1)
1247// as a boolean comparison (e.g. x < y).
1248func threeway(op syntax.Token, cmp int) bool {
1249 switch op {
1250 case syntax.EQL:
1251 return cmp == 0
1252 case syntax.NEQ:
1253 return cmp != 0
1254 case syntax.LE:
1255 return cmp <= 0
1256 case syntax.LT:
1257 return cmp < 0
1258 case syntax.GE:
1259 return cmp >= 0
1260 case syntax.GT:
1261 return cmp > 0
1262 }
1263 panic(op)
1264}
1265
1266func b2i(b bool) int {
1267 if b {
1268 return 1
1269 } else {
1270 return 0
1271 }
1272}
1273
1274// Len returns the length of a string or sequence value,
1275// and -1 for all others.
1276//
1277// Warning: Len(x) >= 0 does not imply Iterate(x) != nil.
1278// A string has a known length but is not directly iterable.
1279func Len(x Value) int {
1280 switch x := x.(type) {
1281 case String:
1282 return x.Len()
1283 case Sequence:
1284 return x.Len()
1285 }
1286 return -1
1287}
1288
1289// Iterate return a new iterator for the value if iterable, nil otherwise.
1290// If the result is non-nil, the caller must call Done when finished with it.
1291//
1292// Warning: Iterate(x) != nil does not imply Len(x) >= 0.
1293// Some iterables may have unknown length.
1294func Iterate(x Value) Iterator {
1295 if x, ok := x.(Iterable); ok {
1296 return x.Iterate()
1297 }
1298 return nil
1299}