blob: b5a4aed529377eca2ea6977aa4d04f6d327a37cc [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//
Alan Donovane3deafe2018-10-23 11:05:09 -040045// Starlark's None value is not equal to Go's nil, but nil may be
46// assigned to a Starlark Value. Be careful to avoid allowing Go nil
47// values to leak into Starlark data structures.
Alan Donovan312d1a52017-10-02 10:10:28 -040048//
49// The Compare operation requires two arguments of the same
50// type, but this constraint cannot be expressed in Go's type system.
51// (This is the classic "binary method problem".)
52// So, each Value type's CompareSameType method is a partial function
53// that compares a value only against others of the same type.
54// Use the package's standalone Compare (or Equal) function to compare
55// an arbitrary pair of values.
56//
Alan Donovane3deafe2018-10-23 11:05:09 -040057// To parse and evaluate a Starlark source file, use ExecFile. The Eval
Alan Donovan312d1a52017-10-02 10:10:28 -040058// function evaluates a single expression. All evaluator functions
59// require a Thread parameter which defines the "thread-local storage"
Alan Donovane3deafe2018-10-23 11:05:09 -040060// of a Starlark thread and may be used to plumb application state
Alan Donovan312d1a52017-10-02 10:10:28 -040061// through Sklyark code and into callbacks. When evaluation fails it
62// returns an EvalError from which the application may obtain a
Alan Donovane3deafe2018-10-23 11:05:09 -040063// backtrace of active Starlark calls.
Alan Donovan312d1a52017-10-02 10:10:28 -040064//
Alan Donovan6beab7e2018-10-31 17:53:09 -040065package starlark // import "go.starlark.net/starlark"
Alan Donovan312d1a52017-10-02 10:10:28 -040066
Alan Donovane3deafe2018-10-23 11:05:09 -040067// This file defines the data types of Starlark and their basic operations.
Alan Donovan312d1a52017-10-02 10:10:28 -040068
69import (
70 "bytes"
71 "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
105 // contains a non-hashable value.
106 Hash() (uint32, error)
107}
108
109// A Comparable is a value that defines its own equivalence relation and
110// perhaps ordered comparisons.
111type Comparable interface {
112 Value
113 // CompareSameType compares one value to another of the same Type().
114 // The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE.
115 // CompareSameType returns an error if an ordered comparison was
116 // requested for a type that does not support it.
117 //
118 // Implementations that recursively compare subcomponents of
119 // the value should use the CompareDepth function, not Compare, to
120 // avoid infinite recursion on cyclic structures.
121 //
122 // The depth parameter is used to bound comparisons of cyclic
123 // data structures. Implementations should decrement depth
124 // before calling CompareDepth and should return an error if depth
125 // < 1.
126 //
127 // Client code should not call this method. Instead, use the
128 // standalone Compare or Equals functions, which are defined for
129 // all pairs of operands.
130 CompareSameType(op syntax.Token, y Value, depth int) (bool, error)
131}
132
133var (
134 _ Comparable = None
135 _ Comparable = Int{}
136 _ Comparable = False
137 _ Comparable = Float(0)
138 _ Comparable = String("")
139 _ Comparable = (*Dict)(nil)
140 _ Comparable = (*List)(nil)
141 _ Comparable = Tuple(nil)
142 _ Comparable = (*Set)(nil)
143)
144
145// A Callable value f may be the operand of a function call, f(x).
alandonovanaeec83f2018-10-22 13:24:13 -0400146//
147// Clients should use the Call function, never the CallInternal method.
Alan Donovan312d1a52017-10-02 10:10:28 -0400148type Callable interface {
149 Value
150 Name() string
alandonovanaeec83f2018-10-22 13:24:13 -0400151 CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error)
Alan Donovan312d1a52017-10-02 10:10:28 -0400152}
153
154var (
155 _ Callable = (*Builtin)(nil)
156 _ Callable = (*Function)(nil)
157)
158
159// An Iterable abstracts a sequence of values.
160// An iterable value may be iterated over by a 'for' loop or used where
Alan Donovane3deafe2018-10-23 11:05:09 -0400161// any other Starlark iterable is allowed. Unlike a Sequence, the length
Alan Donovan312d1a52017-10-02 10:10:28 -0400162// of an Iterable is not necessarily known in advance of iteration.
163type Iterable interface {
164 Value
165 Iterate() Iterator // must be followed by call to Iterator.Done
166}
167
168// A Sequence is a sequence of values of known length.
169type Sequence interface {
170 Iterable
171 Len() int
172}
173
174var (
175 _ Sequence = (*Dict)(nil)
176 _ Sequence = (*Set)(nil)
177)
178
179// An Indexable is a sequence of known length that supports efficient random access.
180// It is not necessarily iterable.
181type Indexable interface {
182 Value
183 Index(i int) Value // requires 0 <= i < Len()
184 Len() int
185}
186
Nick Santosd3cd7362018-05-18 12:58:53 -0400187// A Sliceable is a sequence that can be cut into pieces with the slice operator (x[i:j:step]).
188//
189// All native indexable objects are sliceable.
190// This is a separate interface for backwards-compatibility.
191type Sliceable interface {
192 Indexable
193 // For positive strides (step > 0), 0 <= start <= end <= n.
194 // For negative strides (step < 0), -1 <= end <= start < n.
Josh Bleecher Snyderd5c553a2019-01-16 12:51:06 -0800195 // The caller must ensure that the start and end indices are valid
196 // and that step is non-zero.
Nick Santosd3cd7362018-05-18 12:58:53 -0400197 Slice(start, end, step int) Value
198}
199
Alan Donovan312d1a52017-10-02 10:10:28 -0400200// A HasSetIndex is an Indexable value whose elements may be assigned (x[i] = y).
201//
202// The implementation should not add Len to a negative index as the
203// evaluator does this before the call.
204type HasSetIndex interface {
205 Indexable
206 SetIndex(index int, v Value) error
207}
208
209var (
210 _ HasSetIndex = (*List)(nil)
211 _ Indexable = Tuple(nil)
212 _ Indexable = String("")
Nick Santosd3cd7362018-05-18 12:58:53 -0400213 _ Sliceable = Tuple(nil)
214 _ Sliceable = String("")
215 _ Sliceable = (*List)(nil)
Alan Donovan312d1a52017-10-02 10:10:28 -0400216)
217
218// An Iterator provides a sequence of values to the caller.
219//
220// The caller must call Done when the iterator is no longer needed.
221// Operations that modify a sequence will fail if it has active iterators.
222//
223// Example usage:
224//
225// iter := iterable.Iterator()
226// defer iter.Done()
227// var x Value
228// for iter.Next(&x) {
229// ...
230// }
231//
232type Iterator interface {
233 // If the iterator is exhausted, Next returns false.
234 // Otherwise it sets *p to the current element of the sequence,
235 // advances the iterator, and returns true.
236 Next(p *Value) bool
237 Done()
238}
239
jmillikin-stripe3ccab942018-10-05 07:09:12 -0700240// A Mapping is a mapping from keys to values, such as a dictionary.
alandonovan1ed64972019-01-04 13:04:39 -0500241//
242// If a type satisfies both Mapping and Iterable, the iterator yields
243// the keys of the mapping.
Alan Donovan312d1a52017-10-02 10:10:28 -0400244type Mapping interface {
245 Value
246 // Get returns the value corresponding to the specified key,
247 // or !found if the mapping does not contain the key.
alandonovan7f065b62018-03-19 14:58:49 -0400248 //
249 // Get also defines the behavior of "v in mapping".
250 // The 'in' operator reports the 'found' component, ignoring errors.
Alan Donovan312d1a52017-10-02 10:10:28 -0400251 Get(Value) (v Value, found bool, err error)
252}
253
alandonovan1ed64972019-01-04 13:04:39 -0500254// An IterableMapping is a mapping that supports key enumeration.
255type IterableMapping interface {
256 Mapping
257 Iterate() Iterator // see Iterable interface
258 Items() []Tuple // a new slice containing all key/value pairs
259}
260
261var _ IterableMapping = (*Dict)(nil)
Alan Donovan312d1a52017-10-02 10:10:28 -0400262
jmillikin-stripe3ccab942018-10-05 07:09:12 -0700263// A HasSetKey supports map update using x[k]=v syntax, like a dictionary.
264type HasSetKey interface {
265 Mapping
266 SetKey(k, v Value) error
267}
268
269var _ HasSetKey = (*Dict)(nil)
270
Alan Donovan312d1a52017-10-02 10:10:28 -0400271// A HasBinary value may be used as either operand of these binary operators:
alandonovan93b8d142019-01-06 11:57:29 -0500272// + - * / // % in not in | & ^ << >>
273//
Alan Donovan312d1a52017-10-02 10:10:28 -0400274// The Side argument indicates whether the receiver is the left or right operand.
275//
276// An implementation may decline to handle an operation by returning (nil, nil).
277// For this reason, clients should always call the standalone Binary(op, x, y)
278// function rather than calling the method directly.
279type HasBinary interface {
280 Value
281 Binary(op syntax.Token, y Value, side Side) (Value, error)
282}
283
284type Side bool
285
286const (
287 Left Side = false
288 Right Side = true
289)
290
alandonovan58f91012019-01-03 16:32:47 -0500291// A HasUnary value may be used as the operand of these unary operators:
292// + - ~
293//
294// An implementation may decline to handle an operation by returning (nil, nil).
295// For this reason, clients should always call the standalone Unary(op, x)
296// function rather than calling the method directly.
297type HasUnary interface {
298 Value
299 Unary(op syntax.Token) (Value, error)
300}
301
Alan Donovan312d1a52017-10-02 10:10:28 -0400302// A HasAttrs value has fields or methods that may be read by a dot expression (y = x.f).
303// Attribute names may be listed using the built-in 'dir' function.
304//
305// For implementation convenience, a result of (nil, nil) from Attr is
306// interpreted as a "no such field or method" error. Implementations are
307// free to return a more precise error.
308type HasAttrs interface {
309 Value
310 Attr(name string) (Value, error) // returns (nil, nil) if attribute not present
311 AttrNames() []string // callers must not modify the result.
312}
313
314var (
315 _ HasAttrs = String("")
316 _ HasAttrs = new(List)
317 _ HasAttrs = new(Dict)
318 _ HasAttrs = new(Set)
319)
320
321// A HasSetField value has fields that may be written by a dot expression (x.f = y).
Alan Donovan557c1f12019-02-04 16:12:53 -0500322//
alandonovan6afa1bb2019-02-06 17:49:05 -0500323// An implementation of SetField may return a NoSuchAttrError,
324// in which case the runtime may augment the error message to
325// warn of possible misspelling.
Alan Donovan312d1a52017-10-02 10:10:28 -0400326type HasSetField interface {
327 HasAttrs
328 SetField(name string, val Value) error
329}
330
alandonovan6afa1bb2019-02-06 17:49:05 -0500331// A NoSuchAttrError may be returned by an implementation of
332// HasAttrs.Attr or HasSetField.SetField to indicate that no such field
333// exists. In that case the runtime may augment the error message to
334// warn of possible misspelling.
335type NoSuchAttrError string
336
337func (e NoSuchAttrError) Error() string { return string(e) }
Alan Donovan557c1f12019-02-04 16:12:53 -0500338
Alan Donovan312d1a52017-10-02 10:10:28 -0400339// NoneType is the type of None. Its only legal value is None.
340// (We represent it as a number, not struct{}, so that None may be constant.)
341type NoneType byte
342
343const None = NoneType(0)
344
345func (NoneType) String() string { return "None" }
346func (NoneType) Type() string { return "NoneType" }
347func (NoneType) Freeze() {} // immutable
348func (NoneType) Truth() Bool { return False }
349func (NoneType) Hash() (uint32, error) { return 0, nil }
350func (NoneType) CompareSameType(op syntax.Token, y Value, depth int) (bool, error) {
351 return threeway(op, 0), nil
352}
353
Alan Donovane3deafe2018-10-23 11:05:09 -0400354// Bool is the type of a Starlark bool.
Alan Donovan312d1a52017-10-02 10:10:28 -0400355type Bool bool
356
357const (
358 False Bool = false
359 True Bool = true
360)
361
362func (b Bool) String() string {
363 if b {
364 return "True"
365 } else {
366 return "False"
367 }
368}
369func (b Bool) Type() string { return "bool" }
370func (b Bool) Freeze() {} // immutable
371func (b Bool) Truth() Bool { return b }
372func (b Bool) Hash() (uint32, error) { return uint32(b2i(bool(b))), nil }
373func (x Bool) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
374 y := y_.(Bool)
375 return threeway(op, b2i(bool(x))-b2i(bool(y))), nil
376}
377
Alan Donovane3deafe2018-10-23 11:05:09 -0400378// Float is the type of a Starlark float.
Alan Donovan312d1a52017-10-02 10:10:28 -0400379type Float float64
380
381func (f Float) String() string { return strconv.FormatFloat(float64(f), 'g', 6, 64) }
382func (f Float) Type() string { return "float" }
383func (f Float) Freeze() {} // immutable
384func (f Float) Truth() Bool { return f != 0.0 }
385func (f Float) Hash() (uint32, error) {
386 // Equal float and int values must yield the same hash.
387 // TODO(adonovan): opt: if f is non-integral, and thus not equal
388 // to any Int, we can avoid the Int conversion and use a cheaper hash.
389 if isFinite(float64(f)) {
390 return finiteFloatToInt(f).Hash()
391 }
392 return 1618033, nil // NaN, +/-Inf
393}
394
395func floor(f Float) Float { return Float(math.Floor(float64(f))) }
396
397// isFinite reports whether f represents a finite rational value.
398// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
399func isFinite(f float64) bool {
400 return math.Abs(f) <= math.MaxFloat64
401}
402
403func (x Float) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
404 y := y_.(Float)
405 switch op {
406 case syntax.EQL:
407 return x == y, nil
408 case syntax.NEQ:
409 return x != y, nil
410 case syntax.LE:
411 return x <= y, nil
412 case syntax.LT:
413 return x < y, nil
414 case syntax.GE:
415 return x >= y, nil
416 case syntax.GT:
417 return x > y, nil
418 }
419 panic(op)
420}
421
422func (f Float) rational() *big.Rat { return new(big.Rat).SetFloat64(float64(f)) }
423
424// AsFloat returns the float64 value closest to x.
425// The f result is undefined if x is not a float or int.
426func AsFloat(x Value) (f float64, ok bool) {
427 switch x := x.(type) {
428 case Float:
429 return float64(x), true
430 case Int:
431 return float64(x.Float()), true
432 }
433 return 0, false
434}
435
436func (x Float) Mod(y Float) Float { return Float(math.Mod(float64(x), float64(y))) }
437
alandonovan58f91012019-01-03 16:32:47 -0500438// Unary implements the operations +float and -float.
439func (f Float) Unary(op syntax.Token) (Value, error) {
440 switch op {
441 case syntax.MINUS:
442 return -f, nil
443 case syntax.PLUS:
444 return +f, nil
445 }
446 return nil, nil
447}
448
Alan Donovane3deafe2018-10-23 11:05:09 -0400449// String is the type of a Starlark string.
Alan Donovan312d1a52017-10-02 10:10:28 -0400450//
alandonovana21eb0f2018-06-25 15:30:48 -0400451// A String encapsulates an an immutable sequence of bytes,
452// but strings are not directly iterable. Instead, iterate
453// over the result of calling one of these four methods:
454// codepoints, codepoint_ords, elems, elem_ords.
alandonovanc996ede2018-10-12 13:53:43 -0400455//
456// Warning: the contract of the Value interface's String method is that
Alan Donovane3deafe2018-10-23 11:05:09 -0400457// it returns the value printed in Starlark notation,
alandonovanc996ede2018-10-12 13:53:43 -0400458// so s.String() or fmt.Sprintf("%s", s) returns a quoted string.
459// Use string(s) or s.GoString() or fmt.Sprintf("%#v", s) to obtain the raw contents
Alan Donovane3deafe2018-10-23 11:05:09 -0400460// of a Starlark string as a Go string.
Alan Donovan312d1a52017-10-02 10:10:28 -0400461type String string
462
463func (s String) String() string { return strconv.Quote(string(s)) }
alandonovanc996ede2018-10-12 13:53:43 -0400464func (s String) GoString() string { return string(s) }
Alan Donovan312d1a52017-10-02 10:10:28 -0400465func (s String) Type() string { return "string" }
466func (s String) Freeze() {} // immutable
467func (s String) Truth() Bool { return len(s) > 0 }
468func (s String) Hash() (uint32, error) { return hashString(string(s)), nil }
469func (s String) Len() int { return len(s) } // bytes
470func (s String) Index(i int) Value { return s[i : i+1] }
471
Nick Santosd3cd7362018-05-18 12:58:53 -0400472func (s String) Slice(start, end, step int) Value {
473 if step == 1 {
alandonovan5c7d5aa2018-12-03 17:05:15 -0500474 return s[start:end]
Nick Santosd3cd7362018-05-18 12:58:53 -0400475 }
476
477 sign := signum(step)
478 var str []byte
479 for i := start; signum(end-i) == sign; i += step {
480 str = append(str, s[i])
481 }
482 return String(str)
483}
484
Alan Donovan312d1a52017-10-02 10:10:28 -0400485func (s String) Attr(name string) (Value, error) { return builtinAttr(s, name, stringMethods) }
486func (s String) AttrNames() []string { return builtinAttrNames(stringMethods) }
487
488func (x String) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
489 y := y_.(String)
490 return threeway(op, strings.Compare(string(x), string(y))), nil
491}
492
493func AsString(x Value) (string, bool) { v, ok := x.(String); return string(v), ok }
494
495// A stringIterable is an iterable whose iterator yields a sequence of
alandonovanfa00d7b2018-03-05 14:40:59 -0500496// either Unicode code points or elements (bytes),
Alan Donovan312d1a52017-10-02 10:10:28 -0400497// either numerically or as successive substrings.
498type stringIterable struct {
499 s String
alandonovan0569d1c2018-03-29 14:47:42 -0400500 ords bool
Alan Donovan312d1a52017-10-02 10:10:28 -0400501 codepoints bool
502}
503
504var _ Iterable = (*stringIterable)(nil)
505
506func (si stringIterable) String() string {
alandonovan0569d1c2018-03-29 14:47:42 -0400507 var etype string
508 if si.codepoints {
509 etype = "codepoint"
Alan Donovan312d1a52017-10-02 10:10:28 -0400510 } else {
alandonovan0569d1c2018-03-29 14:47:42 -0400511 etype = "elem"
512 }
513 if si.ords {
514 return si.s.String() + "." + etype + "_ords()"
515 } else {
516 return si.s.String() + "." + etype + "s()"
Alan Donovan312d1a52017-10-02 10:10:28 -0400517 }
518}
519func (si stringIterable) Type() string {
520 if si.codepoints {
521 return "codepoints"
522 } else {
alandonovanfa00d7b2018-03-05 14:40:59 -0500523 return "elems"
Alan Donovan312d1a52017-10-02 10:10:28 -0400524 }
525}
526func (si stringIterable) Freeze() {} // immutable
527func (si stringIterable) Truth() Bool { return True }
528func (si stringIterable) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", si.Type()) }
529func (si stringIterable) Iterate() Iterator { return &stringIterator{si, 0} }
530
531type stringIterator struct {
532 si stringIterable
533 i int
534}
535
536func (it *stringIterator) Next(p *Value) bool {
537 s := it.si.s[it.i:]
538 if s == "" {
539 return false
540 }
541 if it.si.codepoints {
542 r, sz := utf8.DecodeRuneInString(string(s))
alandonovan0569d1c2018-03-29 14:47:42 -0400543 if !it.si.ords {
Alan Donovan312d1a52017-10-02 10:10:28 -0400544 *p = s[:sz]
545 } else {
546 *p = MakeInt(int(r))
547 }
548 it.i += sz
549 } else {
550 b := int(s[0])
alandonovan0569d1c2018-03-29 14:47:42 -0400551 if !it.si.ords {
Alan Donovan312d1a52017-10-02 10:10:28 -0400552 *p = s[:1]
553 } else {
554 *p = MakeInt(b)
555 }
556 it.i += 1
557 }
558 return true
559}
560
561func (*stringIterator) Done() {}
562
Alan Donovane3deafe2018-10-23 11:05:09 -0400563// A Function is a function defined by a Starlark def statement or lambda expression.
564// The initialization behavior of a Starlark module is also represented by a Function.
Alan Donovan312d1a52017-10-02 10:10:28 -0400565type Function struct {
alandonovan8c4023c2018-04-02 13:08:46 -0400566 funcode *compile.Funcode
567 defaults Tuple
568 freevars Tuple
569
570 // These fields are shared by all functions in a module.
571 predeclared StringDict
572 globals []Value
573 constants []Value
Alan Donovan312d1a52017-10-02 10:10:28 -0400574}
575
alandonovan93f3e0c2018-03-30 10:42:28 -0400576func (fn *Function) Name() string { return fn.funcode.Name } // "lambda" for anonymous functions
Alessandro Arzilli3b628ff2018-12-05 15:04:35 +0100577func (fn *Function) Doc() string { return fn.funcode.Doc }
alandonovan93f3e0c2018-03-30 10:42:28 -0400578func (fn *Function) Hash() (uint32, error) { return hashString(fn.funcode.Name), nil }
Alan Donovan312d1a52017-10-02 10:10:28 -0400579func (fn *Function) Freeze() { fn.defaults.Freeze(); fn.freevars.Freeze() }
580func (fn *Function) String() string { return toString(fn) }
581func (fn *Function) Type() string { return "function" }
582func (fn *Function) Truth() Bool { return true }
583
alandonovan93f3e0c2018-03-30 10:42:28 -0400584// Globals returns a new, unfrozen StringDict containing all global
585// variables so far defined in the function's module.
586func (fn *Function) Globals() StringDict {
587 m := make(StringDict, len(fn.funcode.Prog.Globals))
588 for i, id := range fn.funcode.Prog.Globals {
589 if v := fn.globals[i]; v != nil {
590 m[id.Name] = v
591 }
592 }
593 return m
alandonovanf11011f2018-03-23 15:38:44 -0400594}
alandonovan93f3e0c2018-03-30 10:42:28 -0400595
596func (fn *Function) Position() syntax.Position { return fn.funcode.Pos }
597func (fn *Function) NumParams() int { return fn.funcode.NumParams }
alandonovan9b055552018-11-02 14:29:51 -0400598
599// Param returns the name and position of the ith parameter,
600// where 0 <= i < NumParams().
alandonovan93f3e0c2018-03-30 10:42:28 -0400601func (fn *Function) Param(i int) (string, syntax.Position) {
602 id := fn.funcode.Locals[i]
603 return id.Name, id.Pos
604}
605func (fn *Function) HasVarargs() bool { return fn.funcode.HasVarargs }
606func (fn *Function) HasKwargs() bool { return fn.funcode.HasKwargs }
Alan Donovan312d1a52017-10-02 10:10:28 -0400607
608// A Builtin is a function implemented in Go.
609type Builtin struct {
610 name string
611 fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error)
612 recv Value // for bound methods (e.g. "".startswith)
613}
614
615func (b *Builtin) Name() string { return b.name }
616func (b *Builtin) Freeze() {
617 if b.recv != nil {
618 b.recv.Freeze()
619 }
620}
621func (b *Builtin) Hash() (uint32, error) {
622 h := hashString(b.name)
623 if b.recv != nil {
624 h ^= 5521
625 }
626 return h, nil
627}
628func (b *Builtin) Receiver() Value { return b.recv }
629func (b *Builtin) String() string { return toString(b) }
alandonovan4cbd8962017-10-19 13:18:36 -0400630func (b *Builtin) Type() string { return "builtin_function_or_method" }
alandonovanaeec83f2018-10-22 13:24:13 -0400631func (b *Builtin) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) {
632 return b.fn(thread, b, args, kwargs)
Alan Donovan312d1a52017-10-02 10:10:28 -0400633}
634func (b *Builtin) Truth() Bool { return true }
635
alandonovan4cbd8962017-10-19 13:18:36 -0400636// NewBuiltin returns a new 'builtin_function_or_method' value with the specified name
Alan Donovan312d1a52017-10-02 10:10:28 -0400637// and implementation. It compares unequal with all other values.
638func NewBuiltin(name string, fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error)) *Builtin {
639 return &Builtin{name: name, fn: fn}
640}
641
642// BindReceiver returns a new Builtin value representing a method
643// closure, that is, a built-in function bound to a receiver value.
644//
alandonovan4cbd8962017-10-19 13:18:36 -0400645// In the example below, the value of f is the string.index
646// built-in method bound to the receiver value "abc":
Alan Donovan312d1a52017-10-02 10:10:28 -0400647//
648// f = "abc".index; f("a"); f("b")
649//
650// In the common case, the receiver is bound only during the call,
651// but this still results in the creation of a temporary method closure:
652//
653// "abc".index("a")
654//
655func (b *Builtin) BindReceiver(recv Value) *Builtin {
656 return &Builtin{name: b.name, fn: b.fn, recv: recv}
657}
658
Alan Donovane3deafe2018-10-23 11:05:09 -0400659// A *Dict represents a Starlark dictionary.
Alan Donovan312d1a52017-10-02 10:10:28 -0400660type Dict struct {
661 ht hashtable
662}
663
664func (d *Dict) Clear() error { return d.ht.clear() }
665func (d *Dict) Delete(k Value) (v Value, found bool, err error) { return d.ht.delete(k) }
666func (d *Dict) Get(k Value) (v Value, found bool, err error) { return d.ht.lookup(k) }
667func (d *Dict) Items() []Tuple { return d.ht.items() }
668func (d *Dict) Keys() []Value { return d.ht.keys() }
669func (d *Dict) Len() int { return int(d.ht.len) }
670func (d *Dict) Iterate() Iterator { return d.ht.iterate() }
jmillikin-stripe3ccab942018-10-05 07:09:12 -0700671func (d *Dict) SetKey(k, v Value) error { return d.ht.insert(k, v) }
Alan Donovan312d1a52017-10-02 10:10:28 -0400672func (d *Dict) String() string { return toString(d) }
673func (d *Dict) Type() string { return "dict" }
674func (d *Dict) Freeze() { d.ht.freeze() }
675func (d *Dict) Truth() Bool { return d.Len() > 0 }
676func (d *Dict) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: dict") }
677
678func (d *Dict) Attr(name string) (Value, error) { return builtinAttr(d, name, dictMethods) }
679func (d *Dict) AttrNames() []string { return builtinAttrNames(dictMethods) }
680
681func (x *Dict) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
682 y := y_.(*Dict)
683 switch op {
684 case syntax.EQL:
685 ok, err := dictsEqual(x, y, depth)
686 return ok, err
687 case syntax.NEQ:
688 ok, err := dictsEqual(x, y, depth)
689 return !ok, err
690 default:
691 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
692 }
693}
694
695func dictsEqual(x, y *Dict, depth int) (bool, error) {
696 if x.Len() != y.Len() {
697 return false, nil
698 }
699 for _, xitem := range x.Items() {
700 key, xval := xitem[0], xitem[1]
701
702 if yval, found, _ := y.Get(key); !found {
703 return false, nil
704 } else if eq, err := EqualDepth(xval, yval, depth-1); err != nil {
705 return false, err
706 } else if !eq {
707 return false, nil
708 }
709 }
710 return true, nil
711}
712
Alan Donovane3deafe2018-10-23 11:05:09 -0400713// A *List represents a Starlark list value.
Alan Donovan312d1a52017-10-02 10:10:28 -0400714type List struct {
715 elems []Value
716 frozen bool
717 itercount uint32 // number of active iterators (ignored if frozen)
718}
719
720// NewList returns a list containing the specified elements.
721// Callers should not subsequently modify elems.
722func NewList(elems []Value) *List { return &List{elems: elems} }
723
724func (l *List) Freeze() {
725 if !l.frozen {
726 l.frozen = true
727 for _, elem := range l.elems {
728 elem.Freeze()
729 }
730 }
731}
732
733// checkMutable reports an error if the list should not be mutated.
734// verb+" list" should describe the operation.
alandonovan7c0e5a32018-11-02 15:38:05 -0400735func (l *List) checkMutable(verb string) error {
Alan Donovan312d1a52017-10-02 10:10:28 -0400736 if l.frozen {
737 return fmt.Errorf("cannot %s frozen list", verb)
738 }
alandonovan7c0e5a32018-11-02 15:38:05 -0400739 if l.itercount > 0 {
Alan Donovan312d1a52017-10-02 10:10:28 -0400740 return fmt.Errorf("cannot %s list during iteration", verb)
741 }
742 return nil
743}
744
745func (l *List) String() string { return toString(l) }
746func (l *List) Type() string { return "list" }
747func (l *List) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: list") }
748func (l *List) Truth() Bool { return l.Len() > 0 }
749func (l *List) Len() int { return len(l.elems) }
750func (l *List) Index(i int) Value { return l.elems[i] }
751
Nick Santosd3cd7362018-05-18 12:58:53 -0400752func (l *List) Slice(start, end, step int) Value {
753 if step == 1 {
754 elems := append([]Value{}, l.elems[start:end]...)
755 return NewList(elems)
756 }
757
758 sign := signum(step)
759 var list []Value
760 for i := start; signum(end-i) == sign; i += step {
761 list = append(list, l.elems[i])
762 }
763 return NewList(list)
764}
765
Alan Donovan312d1a52017-10-02 10:10:28 -0400766func (l *List) Attr(name string) (Value, error) { return builtinAttr(l, name, listMethods) }
767func (l *List) AttrNames() []string { return builtinAttrNames(listMethods) }
768
769func (l *List) Iterate() Iterator {
770 if !l.frozen {
771 l.itercount++
772 }
773 return &listIterator{l: l}
774}
775
776func (x *List) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
777 y := y_.(*List)
778 // It's tempting to check x == y as an optimization here,
779 // but wrong because a list containing NaN is not equal to itself.
780 return sliceCompare(op, x.elems, y.elems, depth)
781}
782
783func sliceCompare(op syntax.Token, x, y []Value, depth int) (bool, error) {
784 // Fast path: check length.
785 if len(x) != len(y) && (op == syntax.EQL || op == syntax.NEQ) {
786 return op == syntax.NEQ, nil
787 }
788
789 // Find first element that is not equal in both lists.
790 for i := 0; i < len(x) && i < len(y); i++ {
791 if eq, err := EqualDepth(x[i], y[i], depth-1); err != nil {
792 return false, err
793 } else if !eq {
794 switch op {
795 case syntax.EQL:
796 return false, nil
797 case syntax.NEQ:
798 return true, nil
799 default:
800 return CompareDepth(op, x[i], y[i], depth-1)
801 }
802 }
803 }
804
805 return threeway(op, len(x)-len(y)), nil
806}
807
808type listIterator struct {
809 l *List
810 i int
811}
812
813func (it *listIterator) Next(p *Value) bool {
814 if it.i < it.l.Len() {
815 *p = it.l.elems[it.i]
816 it.i++
817 return true
818 }
819 return false
820}
821
822func (it *listIterator) Done() {
823 if !it.l.frozen {
824 it.l.itercount--
825 }
826}
827
828func (l *List) SetIndex(i int, v Value) error {
alandonovan7c0e5a32018-11-02 15:38:05 -0400829 if err := l.checkMutable("assign to element of"); err != nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400830 return err
831 }
832 l.elems[i] = v
833 return nil
834}
835
836func (l *List) Append(v Value) error {
alandonovan7c0e5a32018-11-02 15:38:05 -0400837 if err := l.checkMutable("append to"); err != nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400838 return err
839 }
840 l.elems = append(l.elems, v)
841 return nil
842}
843
844func (l *List) Clear() error {
alandonovan7c0e5a32018-11-02 15:38:05 -0400845 if err := l.checkMutable("clear"); err != nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400846 return err
847 }
848 for i := range l.elems {
849 l.elems[i] = nil // aid GC
850 }
851 l.elems = l.elems[:0]
852 return nil
853}
854
Alan Donovane3deafe2018-10-23 11:05:09 -0400855// A Tuple represents a Starlark tuple value.
Alan Donovan312d1a52017-10-02 10:10:28 -0400856type Tuple []Value
857
858func (t Tuple) Len() int { return len(t) }
859func (t Tuple) Index(i int) Value { return t[i] }
Nick Santosd3cd7362018-05-18 12:58:53 -0400860
861func (t Tuple) Slice(start, end, step int) Value {
862 if step == 1 {
863 return t[start:end]
864 }
865
866 sign := signum(step)
867 var tuple Tuple
868 for i := start; signum(end-i) == sign; i += step {
869 tuple = append(tuple, t[i])
870 }
871 return tuple
872}
873
Alan Donovan312d1a52017-10-02 10:10:28 -0400874func (t Tuple) Iterate() Iterator { return &tupleIterator{elems: t} }
875func (t Tuple) Freeze() {
876 for _, elem := range t {
877 elem.Freeze()
878 }
879}
880func (t Tuple) String() string { return toString(t) }
881func (t Tuple) Type() string { return "tuple" }
882func (t Tuple) Truth() Bool { return len(t) > 0 }
883
884func (x Tuple) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
885 y := y_.(Tuple)
886 return sliceCompare(op, x, y, depth)
887}
888
889func (t Tuple) Hash() (uint32, error) {
890 // Use same algorithm as Python.
891 var x, mult uint32 = 0x345678, 1000003
892 for _, elem := range t {
893 y, err := elem.Hash()
894 if err != nil {
895 return 0, err
896 }
897 x = x ^ y*mult
898 mult += 82520 + uint32(len(t)+len(t))
899 }
900 return x, nil
901}
902
903type tupleIterator struct{ elems Tuple }
904
905func (it *tupleIterator) Next(p *Value) bool {
906 if len(it.elems) > 0 {
907 *p = it.elems[0]
908 it.elems = it.elems[1:]
909 return true
910 }
911 return false
912}
913
914func (it *tupleIterator) Done() {}
915
Alan Donovane3deafe2018-10-23 11:05:09 -0400916// A Set represents a Starlark set value.
Alan Donovan312d1a52017-10-02 10:10:28 -0400917type Set struct {
918 ht hashtable // values are all None
919}
920
921func (s *Set) Delete(k Value) (found bool, err error) { _, found, err = s.ht.delete(k); return }
922func (s *Set) Clear() error { return s.ht.clear() }
923func (s *Set) Has(k Value) (found bool, err error) { _, found, err = s.ht.lookup(k); return }
924func (s *Set) Insert(k Value) error { return s.ht.insert(k, None) }
925func (s *Set) Len() int { return int(s.ht.len) }
926func (s *Set) Iterate() Iterator { return s.ht.iterate() }
927func (s *Set) String() string { return toString(s) }
928func (s *Set) Type() string { return "set" }
929func (s *Set) elems() []Value { return s.ht.keys() }
930func (s *Set) Freeze() { s.ht.freeze() }
931func (s *Set) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: set") }
932func (s *Set) Truth() Bool { return s.Len() > 0 }
933
934func (s *Set) Attr(name string) (Value, error) { return builtinAttr(s, name, setMethods) }
935func (s *Set) AttrNames() []string { return builtinAttrNames(setMethods) }
936
937func (x *Set) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
938 y := y_.(*Set)
939 switch op {
940 case syntax.EQL:
941 ok, err := setsEqual(x, y, depth)
942 return ok, err
943 case syntax.NEQ:
944 ok, err := setsEqual(x, y, depth)
945 return !ok, err
946 default:
947 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
948 }
949}
950
951func setsEqual(x, y *Set, depth int) (bool, error) {
952 if x.Len() != y.Len() {
953 return false, nil
954 }
955 for _, elem := range x.elems() {
956 if found, _ := y.Has(elem); !found {
957 return false, nil
958 }
959 }
960 return true, nil
961}
962
963func (s *Set) Union(iter Iterator) (Value, error) {
964 set := new(Set)
965 for _, elem := range s.elems() {
966 set.Insert(elem) // can't fail
967 }
968 var x Value
969 for iter.Next(&x) {
970 if err := set.Insert(x); err != nil {
971 return nil, err
972 }
973 }
974 return set, nil
975}
976
977// toString returns the string form of value v.
978// It may be more efficient than v.String() for larger values.
979func toString(v Value) string {
980 var buf bytes.Buffer
alandonovan0ed7e5b2019-01-03 16:11:58 -0500981 writeValue(&buf, v, nil)
Alan Donovan312d1a52017-10-02 10:10:28 -0400982 return buf.String()
983}
984
alandonovan0ed7e5b2019-01-03 16:11:58 -0500985// writeValue writes x to out.
986//
987// path is used to detect cycles.
988// It contains the list of *List and *Dict values we're currently printing.
Alan Donovan312d1a52017-10-02 10:10:28 -0400989// (These are the only potentially cyclic structures.)
alandonovan0ed7e5b2019-01-03 16:11:58 -0500990// Callers should generally pass a temporary slice of length zero but non-zero capacity.
991// It is safe to re-use the same path slice for multiple calls.
Alan Donovan312d1a52017-10-02 10:10:28 -0400992func writeValue(out *bytes.Buffer, x Value, path []Value) {
993 switch x := x.(type) {
alandonovan15a68dc2018-03-05 16:23:41 -0500994 case nil:
995 out.WriteString("<nil>") // indicates a bug
996
Alan Donovan312d1a52017-10-02 10:10:28 -0400997 case NoneType:
998 out.WriteString("None")
999
1000 case Int:
1001 out.WriteString(x.String())
1002
1003 case Bool:
1004 if x {
1005 out.WriteString("True")
1006 } else {
1007 out.WriteString("False")
1008 }
1009
1010 case String:
1011 fmt.Fprintf(out, "%q", string(x))
1012
1013 case *List:
1014 out.WriteByte('[')
1015 if pathContains(path, x) {
1016 out.WriteString("...") // list contains itself
1017 } else {
1018 for i, elem := range x.elems {
1019 if i > 0 {
1020 out.WriteString(", ")
1021 }
1022 writeValue(out, elem, append(path, x))
1023 }
1024 }
1025 out.WriteByte(']')
1026
1027 case Tuple:
1028 out.WriteByte('(')
1029 for i, elem := range x {
1030 if i > 0 {
1031 out.WriteString(", ")
1032 }
1033 writeValue(out, elem, path)
1034 }
1035 if len(x) == 1 {
1036 out.WriteByte(',')
1037 }
1038 out.WriteByte(')')
1039
1040 case *Function:
1041 fmt.Fprintf(out, "<function %s>", x.Name())
1042
1043 case *Builtin:
1044 if x.recv != nil {
1045 fmt.Fprintf(out, "<built-in method %s of %s value>", x.Name(), x.recv.Type())
1046 } else {
1047 fmt.Fprintf(out, "<built-in function %s>", x.Name())
1048 }
1049
1050 case *Dict:
1051 out.WriteByte('{')
1052 if pathContains(path, x) {
1053 out.WriteString("...") // dict contains itself
1054 } else {
1055 sep := ""
1056 for _, item := range x.Items() {
1057 k, v := item[0], item[1]
1058 out.WriteString(sep)
1059 writeValue(out, k, path)
1060 out.WriteString(": ")
1061 writeValue(out, v, append(path, x)) // cycle check
1062 sep = ", "
1063 }
1064 }
1065 out.WriteByte('}')
1066
1067 case *Set:
1068 out.WriteString("set([")
1069 for i, elem := range x.elems() {
1070 if i > 0 {
1071 out.WriteString(", ")
1072 }
1073 writeValue(out, elem, path)
1074 }
1075 out.WriteString("])")
1076
1077 default:
1078 out.WriteString(x.String())
1079 }
1080}
1081
1082func pathContains(path []Value, x Value) bool {
1083 for _, y := range path {
1084 if x == y {
1085 return true
1086 }
1087 }
1088 return false
1089}
1090
1091const maxdepth = 10
1092
Alan Donovane3deafe2018-10-23 11:05:09 -04001093// Equal reports whether two Starlark values are equal.
Alan Donovan312d1a52017-10-02 10:10:28 -04001094func Equal(x, y Value) (bool, error) {
alandonovan4bb5ab62018-03-06 20:21:45 -05001095 if x, ok := x.(String); ok {
1096 return x == y, nil // fast path for an important special case
1097 }
Alan Donovan312d1a52017-10-02 10:10:28 -04001098 return EqualDepth(x, y, maxdepth)
1099}
1100
Alan Donovane3deafe2018-10-23 11:05:09 -04001101// EqualDepth reports whether two Starlark values are equal.
Alan Donovan312d1a52017-10-02 10:10:28 -04001102//
1103// Recursive comparisons by implementations of Value.CompareSameType
1104// should use EqualDepth to prevent infinite recursion.
1105func EqualDepth(x, y Value, depth int) (bool, error) {
1106 return CompareDepth(syntax.EQL, x, y, depth)
1107}
1108
Alan Donovane3deafe2018-10-23 11:05:09 -04001109// Compare compares two Starlark values.
Alan Donovan312d1a52017-10-02 10:10:28 -04001110// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE.
1111// Compare returns an error if an ordered comparison was
1112// requested for a type that does not support it.
1113//
1114// Recursive comparisons by implementations of Value.CompareSameType
1115// should use CompareDepth to prevent infinite recursion.
1116func Compare(op syntax.Token, x, y Value) (bool, error) {
1117 return CompareDepth(op, x, y, maxdepth)
1118}
1119
Alan Donovane3deafe2018-10-23 11:05:09 -04001120// CompareDepth compares two Starlark values.
Alan Donovan312d1a52017-10-02 10:10:28 -04001121// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE.
1122// CompareDepth returns an error if an ordered comparison was
1123// requested for a pair of values that do not support it.
1124//
1125// The depth parameter limits the maximum depth of recursion
1126// in cyclic data structures.
1127func CompareDepth(op syntax.Token, x, y Value, depth int) (bool, error) {
1128 if depth < 1 {
1129 return false, fmt.Errorf("comparison exceeded maximum recursion depth")
1130 }
1131 if sameType(x, y) {
1132 if xcomp, ok := x.(Comparable); ok {
1133 return xcomp.CompareSameType(op, y, depth)
1134 }
1135
1136 // use identity comparison
1137 switch op {
1138 case syntax.EQL:
1139 return x == y, nil
1140 case syntax.NEQ:
1141 return x != y, nil
1142 }
1143 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
1144 }
1145
1146 // different types
1147
1148 // int/float ordered comparisons
1149 switch x := x.(type) {
1150 case Int:
1151 if y, ok := y.(Float); ok {
1152 if y != y {
1153 return false, nil // y is NaN
1154 }
1155 var cmp int
1156 if !math.IsInf(float64(y), 0) {
1157 cmp = x.rational().Cmp(y.rational()) // y is finite
1158 } else if y > 0 {
1159 cmp = -1 // y is +Inf
1160 } else {
1161 cmp = +1 // y is -Inf
1162 }
1163 return threeway(op, cmp), nil
1164 }
1165 case Float:
1166 if y, ok := y.(Int); ok {
1167 if x != x {
1168 return false, nil // x is NaN
1169 }
1170 var cmp int
1171 if !math.IsInf(float64(x), 0) {
1172 cmp = x.rational().Cmp(y.rational()) // x is finite
1173 } else if x > 0 {
1174 cmp = -1 // x is +Inf
1175 } else {
1176 cmp = +1 // x is -Inf
1177 }
1178 return threeway(op, cmp), nil
1179 }
1180 }
1181
1182 // All other values of different types compare unequal.
1183 switch op {
1184 case syntax.EQL:
1185 return false, nil
1186 case syntax.NEQ:
1187 return true, nil
1188 }
1189 return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
1190}
1191
1192func sameType(x, y Value) bool {
1193 return reflect.TypeOf(x) == reflect.TypeOf(y) || x.Type() == y.Type()
1194}
1195
1196// threeway interprets a three-way comparison value cmp (-1, 0, +1)
1197// as a boolean comparison (e.g. x < y).
1198func threeway(op syntax.Token, cmp int) bool {
1199 switch op {
1200 case syntax.EQL:
1201 return cmp == 0
1202 case syntax.NEQ:
1203 return cmp != 0
1204 case syntax.LE:
1205 return cmp <= 0
1206 case syntax.LT:
1207 return cmp < 0
1208 case syntax.GE:
1209 return cmp >= 0
1210 case syntax.GT:
1211 return cmp > 0
1212 }
1213 panic(op)
1214}
1215
1216func b2i(b bool) int {
1217 if b {
1218 return 1
1219 } else {
1220 return 0
1221 }
1222}
1223
1224// Len returns the length of a string or sequence value,
1225// and -1 for all others.
1226//
1227// Warning: Len(x) >= 0 does not imply Iterate(x) != nil.
1228// A string has a known length but is not directly iterable.
1229func Len(x Value) int {
1230 switch x := x.(type) {
1231 case String:
1232 return x.Len()
1233 case Sequence:
1234 return x.Len()
1235 }
1236 return -1
1237}
1238
1239// Iterate return a new iterator for the value if iterable, nil otherwise.
1240// If the result is non-nil, the caller must call Done when finished with it.
1241//
1242// Warning: Iterate(x) != nil does not imply Len(x) >= 0.
1243// Some iterables may have unknown length.
1244func Iterate(x Value) Iterator {
1245 if x, ok := x.(Iterable); ok {
1246 return x.Iterate()
1247 }
1248 return nil
1249}