1*4947cdc7SCole Faust// Copyright 2017 The Bazel Authors. All rights reserved. 2*4947cdc7SCole Faust// Use of this source code is governed by a BSD-style 3*4947cdc7SCole Faust// license that can be found in the LICENSE file. 4*4947cdc7SCole Faust 5*4947cdc7SCole Faust// Package starlark provides a Starlark interpreter. 6*4947cdc7SCole Faust// 7*4947cdc7SCole Faust// Starlark values are represented by the Value interface. 8*4947cdc7SCole Faust// The following built-in Value types are known to the evaluator: 9*4947cdc7SCole Faust// 10*4947cdc7SCole Faust// NoneType -- NoneType 11*4947cdc7SCole Faust// Bool -- bool 12*4947cdc7SCole Faust// Int -- int 13*4947cdc7SCole Faust// Float -- float 14*4947cdc7SCole Faust// String -- string 15*4947cdc7SCole Faust// *List -- list 16*4947cdc7SCole Faust// Tuple -- tuple 17*4947cdc7SCole Faust// *Dict -- dict 18*4947cdc7SCole Faust// *Set -- set 19*4947cdc7SCole Faust// *Function -- function (implemented in Starlark) 20*4947cdc7SCole Faust// *Builtin -- builtin_function_or_method (function or method implemented in Go) 21*4947cdc7SCole Faust// 22*4947cdc7SCole Faust// Client applications may define new data types that satisfy at least 23*4947cdc7SCole Faust// the Value interface. Such types may provide additional operations by 24*4947cdc7SCole Faust// implementing any of these optional interfaces: 25*4947cdc7SCole Faust// 26*4947cdc7SCole Faust// Callable -- value is callable like a function 27*4947cdc7SCole Faust// Comparable -- value defines its own comparison operations 28*4947cdc7SCole Faust// Iterable -- value is iterable using 'for' loops 29*4947cdc7SCole Faust// Sequence -- value is iterable sequence of known length 30*4947cdc7SCole Faust// Indexable -- value is sequence with efficient random access 31*4947cdc7SCole Faust// Mapping -- value maps from keys to values, like a dictionary 32*4947cdc7SCole Faust// HasBinary -- value defines binary operations such as * and + 33*4947cdc7SCole Faust// HasAttrs -- value has readable fields or methods x.f 34*4947cdc7SCole Faust// HasSetField -- value has settable fields x.f 35*4947cdc7SCole Faust// HasSetIndex -- value supports element update using x[i]=y 36*4947cdc7SCole Faust// HasSetKey -- value supports map update using x[k]=v 37*4947cdc7SCole Faust// HasUnary -- value defines unary operations such as + and - 38*4947cdc7SCole Faust// 39*4947cdc7SCole Faust// Client applications may also define domain-specific functions in Go 40*4947cdc7SCole Faust// and make them available to Starlark programs. Use NewBuiltin to 41*4947cdc7SCole Faust// construct a built-in value that wraps a Go function. The 42*4947cdc7SCole Faust// implementation of the Go function may use UnpackArgs to make sense of 43*4947cdc7SCole Faust// the positional and keyword arguments provided by the caller. 44*4947cdc7SCole Faust// 45*4947cdc7SCole Faust// Starlark's None value is not equal to Go's nil. Go's nil is not a legal 46*4947cdc7SCole Faust// Starlark value, but the compiler will not stop you from converting nil 47*4947cdc7SCole Faust// to Value. Be careful to avoid allowing Go nil values to leak into 48*4947cdc7SCole Faust// Starlark data structures. 49*4947cdc7SCole Faust// 50*4947cdc7SCole Faust// The Compare operation requires two arguments of the same 51*4947cdc7SCole Faust// type, but this constraint cannot be expressed in Go's type system. 52*4947cdc7SCole Faust// (This is the classic "binary method problem".) 53*4947cdc7SCole Faust// So, each Value type's CompareSameType method is a partial function 54*4947cdc7SCole Faust// that compares a value only against others of the same type. 55*4947cdc7SCole Faust// Use the package's standalone Compare (or Equal) function to compare 56*4947cdc7SCole Faust// an arbitrary pair of values. 57*4947cdc7SCole Faust// 58*4947cdc7SCole Faust// To parse and evaluate a Starlark source file, use ExecFile. The Eval 59*4947cdc7SCole Faust// function evaluates a single expression. All evaluator functions 60*4947cdc7SCole Faust// require a Thread parameter which defines the "thread-local storage" 61*4947cdc7SCole Faust// of a Starlark thread and may be used to plumb application state 62*4947cdc7SCole Faust// through Starlark code and into callbacks. When evaluation fails it 63*4947cdc7SCole Faust// returns an EvalError from which the application may obtain a 64*4947cdc7SCole Faust// backtrace of active Starlark calls. 65*4947cdc7SCole Faust// 66*4947cdc7SCole Faustpackage starlark // import "go.starlark.net/starlark" 67*4947cdc7SCole Faust 68*4947cdc7SCole Faust// This file defines the data types of Starlark and their basic operations. 69*4947cdc7SCole Faust 70*4947cdc7SCole Faustimport ( 71*4947cdc7SCole Faust "fmt" 72*4947cdc7SCole Faust "math" 73*4947cdc7SCole Faust "math/big" 74*4947cdc7SCole Faust "reflect" 75*4947cdc7SCole Faust "strconv" 76*4947cdc7SCole Faust "strings" 77*4947cdc7SCole Faust "unicode/utf8" 78*4947cdc7SCole Faust 79*4947cdc7SCole Faust "go.starlark.net/internal/compile" 80*4947cdc7SCole Faust "go.starlark.net/syntax" 81*4947cdc7SCole Faust) 82*4947cdc7SCole Faust 83*4947cdc7SCole Faust// Value is a value in the Starlark interpreter. 84*4947cdc7SCole Fausttype Value interface { 85*4947cdc7SCole Faust // String returns the string representation of the value. 86*4947cdc7SCole Faust // Starlark string values are quoted as if by Python's repr. 87*4947cdc7SCole Faust String() string 88*4947cdc7SCole Faust 89*4947cdc7SCole Faust // Type returns a short string describing the value's type. 90*4947cdc7SCole Faust Type() string 91*4947cdc7SCole Faust 92*4947cdc7SCole Faust // Freeze causes the value, and all values transitively 93*4947cdc7SCole Faust // reachable from it through collections and closures, to be 94*4947cdc7SCole Faust // marked as frozen. All subsequent mutations to the data 95*4947cdc7SCole Faust // structure through this API will fail dynamically, making the 96*4947cdc7SCole Faust // data structure immutable and safe for publishing to other 97*4947cdc7SCole Faust // Starlark interpreters running concurrently. 98*4947cdc7SCole Faust Freeze() 99*4947cdc7SCole Faust 100*4947cdc7SCole Faust // Truth returns the truth value of an object. 101*4947cdc7SCole Faust Truth() Bool 102*4947cdc7SCole Faust 103*4947cdc7SCole Faust // Hash returns a function of x such that Equals(x, y) => Hash(x) == Hash(y). 104*4947cdc7SCole Faust // Hash may fail if the value's type is not hashable, or if the value 105*4947cdc7SCole Faust // contains a non-hashable value. The hash is used only by dictionaries and 106*4947cdc7SCole Faust // is not exposed to the Starlark program. 107*4947cdc7SCole Faust Hash() (uint32, error) 108*4947cdc7SCole Faust} 109*4947cdc7SCole Faust 110*4947cdc7SCole Faust// A Comparable is a value that defines its own equivalence relation and 111*4947cdc7SCole Faust// perhaps ordered comparisons. 112*4947cdc7SCole Fausttype Comparable interface { 113*4947cdc7SCole Faust Value 114*4947cdc7SCole Faust // CompareSameType compares one value to another of the same Type(). 115*4947cdc7SCole Faust // The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE. 116*4947cdc7SCole Faust // CompareSameType returns an error if an ordered comparison was 117*4947cdc7SCole Faust // requested for a type that does not support it. 118*4947cdc7SCole Faust // 119*4947cdc7SCole Faust // Implementations that recursively compare subcomponents of 120*4947cdc7SCole Faust // the value should use the CompareDepth function, not Compare, to 121*4947cdc7SCole Faust // avoid infinite recursion on cyclic structures. 122*4947cdc7SCole Faust // 123*4947cdc7SCole Faust // The depth parameter is used to bound comparisons of cyclic 124*4947cdc7SCole Faust // data structures. Implementations should decrement depth 125*4947cdc7SCole Faust // before calling CompareDepth and should return an error if depth 126*4947cdc7SCole Faust // < 1. 127*4947cdc7SCole Faust // 128*4947cdc7SCole Faust // Client code should not call this method. Instead, use the 129*4947cdc7SCole Faust // standalone Compare or Equals functions, which are defined for 130*4947cdc7SCole Faust // all pairs of operands. 131*4947cdc7SCole Faust CompareSameType(op syntax.Token, y Value, depth int) (bool, error) 132*4947cdc7SCole Faust} 133*4947cdc7SCole Faust 134*4947cdc7SCole Faustvar ( 135*4947cdc7SCole Faust _ Comparable = Int{} 136*4947cdc7SCole Faust _ Comparable = False 137*4947cdc7SCole Faust _ Comparable = Float(0) 138*4947cdc7SCole Faust _ Comparable = String("") 139*4947cdc7SCole Faust _ Comparable = (*Dict)(nil) 140*4947cdc7SCole Faust _ Comparable = (*List)(nil) 141*4947cdc7SCole Faust _ Comparable = Tuple(nil) 142*4947cdc7SCole Faust _ Comparable = (*Set)(nil) 143*4947cdc7SCole Faust) 144*4947cdc7SCole Faust 145*4947cdc7SCole Faust// A Callable value f may be the operand of a function call, f(x). 146*4947cdc7SCole Faust// 147*4947cdc7SCole Faust// Clients should use the Call function, never the CallInternal method. 148*4947cdc7SCole Fausttype Callable interface { 149*4947cdc7SCole Faust Value 150*4947cdc7SCole Faust Name() string 151*4947cdc7SCole Faust CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) 152*4947cdc7SCole Faust} 153*4947cdc7SCole Faust 154*4947cdc7SCole Fausttype callableWithPosition interface { 155*4947cdc7SCole Faust Callable 156*4947cdc7SCole Faust Position() syntax.Position 157*4947cdc7SCole Faust} 158*4947cdc7SCole Faust 159*4947cdc7SCole Faustvar ( 160*4947cdc7SCole Faust _ Callable = (*Builtin)(nil) 161*4947cdc7SCole Faust _ Callable = (*Function)(nil) 162*4947cdc7SCole Faust _ callableWithPosition = (*Function)(nil) 163*4947cdc7SCole Faust) 164*4947cdc7SCole Faust 165*4947cdc7SCole Faust// An Iterable abstracts a sequence of values. 166*4947cdc7SCole Faust// An iterable value may be iterated over by a 'for' loop or used where 167*4947cdc7SCole Faust// any other Starlark iterable is allowed. Unlike a Sequence, the length 168*4947cdc7SCole Faust// of an Iterable is not necessarily known in advance of iteration. 169*4947cdc7SCole Fausttype Iterable interface { 170*4947cdc7SCole Faust Value 171*4947cdc7SCole Faust Iterate() Iterator // must be followed by call to Iterator.Done 172*4947cdc7SCole Faust} 173*4947cdc7SCole Faust 174*4947cdc7SCole Faust// A Sequence is a sequence of values of known length. 175*4947cdc7SCole Fausttype Sequence interface { 176*4947cdc7SCole Faust Iterable 177*4947cdc7SCole Faust Len() int 178*4947cdc7SCole Faust} 179*4947cdc7SCole Faust 180*4947cdc7SCole Faustvar ( 181*4947cdc7SCole Faust _ Sequence = (*Dict)(nil) 182*4947cdc7SCole Faust _ Sequence = (*Set)(nil) 183*4947cdc7SCole Faust) 184*4947cdc7SCole Faust 185*4947cdc7SCole Faust// An Indexable is a sequence of known length that supports efficient random access. 186*4947cdc7SCole Faust// It is not necessarily iterable. 187*4947cdc7SCole Fausttype Indexable interface { 188*4947cdc7SCole Faust Value 189*4947cdc7SCole Faust Index(i int) Value // requires 0 <= i < Len() 190*4947cdc7SCole Faust Len() int 191*4947cdc7SCole Faust} 192*4947cdc7SCole Faust 193*4947cdc7SCole Faust// A Sliceable is a sequence that can be cut into pieces with the slice operator (x[i:j:step]). 194*4947cdc7SCole Faust// 195*4947cdc7SCole Faust// All native indexable objects are sliceable. 196*4947cdc7SCole Faust// This is a separate interface for backwards-compatibility. 197*4947cdc7SCole Fausttype Sliceable interface { 198*4947cdc7SCole Faust Indexable 199*4947cdc7SCole Faust // For positive strides (step > 0), 0 <= start <= end <= n. 200*4947cdc7SCole Faust // For negative strides (step < 0), -1 <= end <= start < n. 201*4947cdc7SCole Faust // The caller must ensure that the start and end indices are valid 202*4947cdc7SCole Faust // and that step is non-zero. 203*4947cdc7SCole Faust Slice(start, end, step int) Value 204*4947cdc7SCole Faust} 205*4947cdc7SCole Faust 206*4947cdc7SCole Faust// A HasSetIndex is an Indexable value whose elements may be assigned (x[i] = y). 207*4947cdc7SCole Faust// 208*4947cdc7SCole Faust// The implementation should not add Len to a negative index as the 209*4947cdc7SCole Faust// evaluator does this before the call. 210*4947cdc7SCole Fausttype HasSetIndex interface { 211*4947cdc7SCole Faust Indexable 212*4947cdc7SCole Faust SetIndex(index int, v Value) error 213*4947cdc7SCole Faust} 214*4947cdc7SCole Faust 215*4947cdc7SCole Faustvar ( 216*4947cdc7SCole Faust _ HasSetIndex = (*List)(nil) 217*4947cdc7SCole Faust _ Indexable = Tuple(nil) 218*4947cdc7SCole Faust _ Indexable = String("") 219*4947cdc7SCole Faust _ Sliceable = Tuple(nil) 220*4947cdc7SCole Faust _ Sliceable = String("") 221*4947cdc7SCole Faust _ Sliceable = (*List)(nil) 222*4947cdc7SCole Faust) 223*4947cdc7SCole Faust 224*4947cdc7SCole Faust// An Iterator provides a sequence of values to the caller. 225*4947cdc7SCole Faust// 226*4947cdc7SCole Faust// The caller must call Done when the iterator is no longer needed. 227*4947cdc7SCole Faust// Operations that modify a sequence will fail if it has active iterators. 228*4947cdc7SCole Faust// 229*4947cdc7SCole Faust// Example usage: 230*4947cdc7SCole Faust// 231*4947cdc7SCole Faust// iter := iterable.Iterator() 232*4947cdc7SCole Faust// defer iter.Done() 233*4947cdc7SCole Faust// var x Value 234*4947cdc7SCole Faust// for iter.Next(&x) { 235*4947cdc7SCole Faust// ... 236*4947cdc7SCole Faust// } 237*4947cdc7SCole Faust// 238*4947cdc7SCole Fausttype Iterator interface { 239*4947cdc7SCole Faust // If the iterator is exhausted, Next returns false. 240*4947cdc7SCole Faust // Otherwise it sets *p to the current element of the sequence, 241*4947cdc7SCole Faust // advances the iterator, and returns true. 242*4947cdc7SCole Faust Next(p *Value) bool 243*4947cdc7SCole Faust Done() 244*4947cdc7SCole Faust} 245*4947cdc7SCole Faust 246*4947cdc7SCole Faust// A Mapping is a mapping from keys to values, such as a dictionary. 247*4947cdc7SCole Faust// 248*4947cdc7SCole Faust// If a type satisfies both Mapping and Iterable, the iterator yields 249*4947cdc7SCole Faust// the keys of the mapping. 250*4947cdc7SCole Fausttype Mapping interface { 251*4947cdc7SCole Faust Value 252*4947cdc7SCole Faust // Get returns the value corresponding to the specified key, 253*4947cdc7SCole Faust // or !found if the mapping does not contain the key. 254*4947cdc7SCole Faust // 255*4947cdc7SCole Faust // Get also defines the behavior of "v in mapping". 256*4947cdc7SCole Faust // The 'in' operator reports the 'found' component, ignoring errors. 257*4947cdc7SCole Faust Get(Value) (v Value, found bool, err error) 258*4947cdc7SCole Faust} 259*4947cdc7SCole Faust 260*4947cdc7SCole Faust// An IterableMapping is a mapping that supports key enumeration. 261*4947cdc7SCole Fausttype IterableMapping interface { 262*4947cdc7SCole Faust Mapping 263*4947cdc7SCole Faust Iterate() Iterator // see Iterable interface 264*4947cdc7SCole Faust Items() []Tuple // a new slice containing all key/value pairs 265*4947cdc7SCole Faust} 266*4947cdc7SCole Faust 267*4947cdc7SCole Faustvar _ IterableMapping = (*Dict)(nil) 268*4947cdc7SCole Faust 269*4947cdc7SCole Faust// A HasSetKey supports map update using x[k]=v syntax, like a dictionary. 270*4947cdc7SCole Fausttype HasSetKey interface { 271*4947cdc7SCole Faust Mapping 272*4947cdc7SCole Faust SetKey(k, v Value) error 273*4947cdc7SCole Faust} 274*4947cdc7SCole Faust 275*4947cdc7SCole Faustvar _ HasSetKey = (*Dict)(nil) 276*4947cdc7SCole Faust 277*4947cdc7SCole Faust// A HasBinary value may be used as either operand of these binary operators: 278*4947cdc7SCole Faust// + - * / // % in not in | & ^ << >> 279*4947cdc7SCole Faust// 280*4947cdc7SCole Faust// The Side argument indicates whether the receiver is the left or right operand. 281*4947cdc7SCole Faust// 282*4947cdc7SCole Faust// An implementation may decline to handle an operation by returning (nil, nil). 283*4947cdc7SCole Faust// For this reason, clients should always call the standalone Binary(op, x, y) 284*4947cdc7SCole Faust// function rather than calling the method directly. 285*4947cdc7SCole Fausttype HasBinary interface { 286*4947cdc7SCole Faust Value 287*4947cdc7SCole Faust Binary(op syntax.Token, y Value, side Side) (Value, error) 288*4947cdc7SCole Faust} 289*4947cdc7SCole Faust 290*4947cdc7SCole Fausttype Side bool 291*4947cdc7SCole Faust 292*4947cdc7SCole Faustconst ( 293*4947cdc7SCole Faust Left Side = false 294*4947cdc7SCole Faust Right Side = true 295*4947cdc7SCole Faust) 296*4947cdc7SCole Faust 297*4947cdc7SCole Faust// A HasUnary value may be used as the operand of these unary operators: 298*4947cdc7SCole Faust// + - ~ 299*4947cdc7SCole Faust// 300*4947cdc7SCole Faust// An implementation may decline to handle an operation by returning (nil, nil). 301*4947cdc7SCole Faust// For this reason, clients should always call the standalone Unary(op, x) 302*4947cdc7SCole Faust// function rather than calling the method directly. 303*4947cdc7SCole Fausttype HasUnary interface { 304*4947cdc7SCole Faust Value 305*4947cdc7SCole Faust Unary(op syntax.Token) (Value, error) 306*4947cdc7SCole Faust} 307*4947cdc7SCole Faust 308*4947cdc7SCole Faust// A HasAttrs value has fields or methods that may be read by a dot expression (y = x.f). 309*4947cdc7SCole Faust// Attribute names may be listed using the built-in 'dir' function. 310*4947cdc7SCole Faust// 311*4947cdc7SCole Faust// For implementation convenience, a result of (nil, nil) from Attr is 312*4947cdc7SCole Faust// interpreted as a "no such field or method" error. Implementations are 313*4947cdc7SCole Faust// free to return a more precise error. 314*4947cdc7SCole Fausttype HasAttrs interface { 315*4947cdc7SCole Faust Value 316*4947cdc7SCole Faust Attr(name string) (Value, error) // returns (nil, nil) if attribute not present 317*4947cdc7SCole Faust AttrNames() []string // callers must not modify the result. 318*4947cdc7SCole Faust} 319*4947cdc7SCole Faust 320*4947cdc7SCole Faustvar ( 321*4947cdc7SCole Faust _ HasAttrs = String("") 322*4947cdc7SCole Faust _ HasAttrs = new(List) 323*4947cdc7SCole Faust _ HasAttrs = new(Dict) 324*4947cdc7SCole Faust _ HasAttrs = new(Set) 325*4947cdc7SCole Faust) 326*4947cdc7SCole Faust 327*4947cdc7SCole Faust// A HasSetField value has fields that may be written by a dot expression (x.f = y). 328*4947cdc7SCole Faust// 329*4947cdc7SCole Faust// An implementation of SetField may return a NoSuchAttrError, 330*4947cdc7SCole Faust// in which case the runtime may augment the error message to 331*4947cdc7SCole Faust// warn of possible misspelling. 332*4947cdc7SCole Fausttype HasSetField interface { 333*4947cdc7SCole Faust HasAttrs 334*4947cdc7SCole Faust SetField(name string, val Value) error 335*4947cdc7SCole Faust} 336*4947cdc7SCole Faust 337*4947cdc7SCole Faust// A NoSuchAttrError may be returned by an implementation of 338*4947cdc7SCole Faust// HasAttrs.Attr or HasSetField.SetField to indicate that no such field 339*4947cdc7SCole Faust// exists. In that case the runtime may augment the error message to 340*4947cdc7SCole Faust// warn of possible misspelling. 341*4947cdc7SCole Fausttype NoSuchAttrError string 342*4947cdc7SCole Faust 343*4947cdc7SCole Faustfunc (e NoSuchAttrError) Error() string { return string(e) } 344*4947cdc7SCole Faust 345*4947cdc7SCole Faust// NoneType is the type of None. Its only legal value is None. 346*4947cdc7SCole Faust// (We represent it as a number, not struct{}, so that None may be constant.) 347*4947cdc7SCole Fausttype NoneType byte 348*4947cdc7SCole Faust 349*4947cdc7SCole Faustconst None = NoneType(0) 350*4947cdc7SCole Faust 351*4947cdc7SCole Faustfunc (NoneType) String() string { return "None" } 352*4947cdc7SCole Faustfunc (NoneType) Type() string { return "NoneType" } 353*4947cdc7SCole Faustfunc (NoneType) Freeze() {} // immutable 354*4947cdc7SCole Faustfunc (NoneType) Truth() Bool { return False } 355*4947cdc7SCole Faustfunc (NoneType) Hash() (uint32, error) { return 0, nil } 356*4947cdc7SCole Faust 357*4947cdc7SCole Faust// Bool is the type of a Starlark bool. 358*4947cdc7SCole Fausttype Bool bool 359*4947cdc7SCole Faust 360*4947cdc7SCole Faustconst ( 361*4947cdc7SCole Faust False Bool = false 362*4947cdc7SCole Faust True Bool = true 363*4947cdc7SCole Faust) 364*4947cdc7SCole Faust 365*4947cdc7SCole Faustfunc (b Bool) String() string { 366*4947cdc7SCole Faust if b { 367*4947cdc7SCole Faust return "True" 368*4947cdc7SCole Faust } else { 369*4947cdc7SCole Faust return "False" 370*4947cdc7SCole Faust } 371*4947cdc7SCole Faust} 372*4947cdc7SCole Faustfunc (b Bool) Type() string { return "bool" } 373*4947cdc7SCole Faustfunc (b Bool) Freeze() {} // immutable 374*4947cdc7SCole Faustfunc (b Bool) Truth() Bool { return b } 375*4947cdc7SCole Faustfunc (b Bool) Hash() (uint32, error) { return uint32(b2i(bool(b))), nil } 376*4947cdc7SCole Faustfunc (x Bool) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 377*4947cdc7SCole Faust y := y_.(Bool) 378*4947cdc7SCole Faust return threeway(op, b2i(bool(x))-b2i(bool(y))), nil 379*4947cdc7SCole Faust} 380*4947cdc7SCole Faust 381*4947cdc7SCole Faust// Float is the type of a Starlark float. 382*4947cdc7SCole Fausttype Float float64 383*4947cdc7SCole Faust 384*4947cdc7SCole Faustfunc (f Float) String() string { 385*4947cdc7SCole Faust var buf strings.Builder 386*4947cdc7SCole Faust f.format(&buf, 'g') 387*4947cdc7SCole Faust return buf.String() 388*4947cdc7SCole Faust} 389*4947cdc7SCole Faust 390*4947cdc7SCole Faustfunc (f Float) format(buf *strings.Builder, conv byte) { 391*4947cdc7SCole Faust ff := float64(f) 392*4947cdc7SCole Faust if !isFinite(ff) { 393*4947cdc7SCole Faust if math.IsInf(ff, +1) { 394*4947cdc7SCole Faust buf.WriteString("+inf") 395*4947cdc7SCole Faust } else if math.IsInf(ff, -1) { 396*4947cdc7SCole Faust buf.WriteString("-inf") 397*4947cdc7SCole Faust } else { 398*4947cdc7SCole Faust buf.WriteString("nan") 399*4947cdc7SCole Faust } 400*4947cdc7SCole Faust return 401*4947cdc7SCole Faust } 402*4947cdc7SCole Faust 403*4947cdc7SCole Faust // %g is the default format used by str. 404*4947cdc7SCole Faust // It uses the minimum precision to avoid ambiguity, 405*4947cdc7SCole Faust // and always includes a '.' or an 'e' so that the value 406*4947cdc7SCole Faust // is self-evidently a float, not an int. 407*4947cdc7SCole Faust if conv == 'g' || conv == 'G' { 408*4947cdc7SCole Faust s := strconv.FormatFloat(ff, conv, -1, 64) 409*4947cdc7SCole Faust buf.WriteString(s) 410*4947cdc7SCole Faust // Ensure result always has a decimal point if no exponent. 411*4947cdc7SCole Faust // "123" -> "123.0" 412*4947cdc7SCole Faust if strings.IndexByte(s, conv-'g'+'e') < 0 && strings.IndexByte(s, '.') < 0 { 413*4947cdc7SCole Faust buf.WriteString(".0") 414*4947cdc7SCole Faust } 415*4947cdc7SCole Faust return 416*4947cdc7SCole Faust } 417*4947cdc7SCole Faust 418*4947cdc7SCole Faust // %[eEfF] use 6-digit precision 419*4947cdc7SCole Faust buf.WriteString(strconv.FormatFloat(ff, conv, 6, 64)) 420*4947cdc7SCole Faust} 421*4947cdc7SCole Faust 422*4947cdc7SCole Faustfunc (f Float) Type() string { return "float" } 423*4947cdc7SCole Faustfunc (f Float) Freeze() {} // immutable 424*4947cdc7SCole Faustfunc (f Float) Truth() Bool { return f != 0.0 } 425*4947cdc7SCole Faustfunc (f Float) Hash() (uint32, error) { 426*4947cdc7SCole Faust // Equal float and int values must yield the same hash. 427*4947cdc7SCole Faust // TODO(adonovan): opt: if f is non-integral, and thus not equal 428*4947cdc7SCole Faust // to any Int, we can avoid the Int conversion and use a cheaper hash. 429*4947cdc7SCole Faust if isFinite(float64(f)) { 430*4947cdc7SCole Faust return finiteFloatToInt(f).Hash() 431*4947cdc7SCole Faust } 432*4947cdc7SCole Faust return 1618033, nil // NaN, +/-Inf 433*4947cdc7SCole Faust} 434*4947cdc7SCole Faust 435*4947cdc7SCole Faustfunc floor(f Float) Float { return Float(math.Floor(float64(f))) } 436*4947cdc7SCole Faust 437*4947cdc7SCole Faust// isFinite reports whether f represents a finite rational value. 438*4947cdc7SCole Faust// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0). 439*4947cdc7SCole Faustfunc isFinite(f float64) bool { 440*4947cdc7SCole Faust return math.Abs(f) <= math.MaxFloat64 441*4947cdc7SCole Faust} 442*4947cdc7SCole Faust 443*4947cdc7SCole Faustfunc (x Float) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 444*4947cdc7SCole Faust y := y_.(Float) 445*4947cdc7SCole Faust return threeway(op, floatCmp(x, y)), nil 446*4947cdc7SCole Faust} 447*4947cdc7SCole Faust 448*4947cdc7SCole Faust// floatCmp performs a three-valued comparison on floats, 449*4947cdc7SCole Faust// which are totally ordered with NaN > +Inf. 450*4947cdc7SCole Faustfunc floatCmp(x, y Float) int { 451*4947cdc7SCole Faust if x > y { 452*4947cdc7SCole Faust return +1 453*4947cdc7SCole Faust } else if x < y { 454*4947cdc7SCole Faust return -1 455*4947cdc7SCole Faust } else if x == y { 456*4947cdc7SCole Faust return 0 457*4947cdc7SCole Faust } 458*4947cdc7SCole Faust 459*4947cdc7SCole Faust // At least one operand is NaN. 460*4947cdc7SCole Faust if x == x { 461*4947cdc7SCole Faust return -1 // y is NaN 462*4947cdc7SCole Faust } else if y == y { 463*4947cdc7SCole Faust return +1 // x is NaN 464*4947cdc7SCole Faust } 465*4947cdc7SCole Faust return 0 // both NaN 466*4947cdc7SCole Faust} 467*4947cdc7SCole Faust 468*4947cdc7SCole Faustfunc (f Float) rational() *big.Rat { return new(big.Rat).SetFloat64(float64(f)) } 469*4947cdc7SCole Faust 470*4947cdc7SCole Faust// AsFloat returns the float64 value closest to x. 471*4947cdc7SCole Faust// The f result is undefined if x is not a float or Int. 472*4947cdc7SCole Faust// The result may be infinite if x is a very large Int. 473*4947cdc7SCole Faustfunc AsFloat(x Value) (f float64, ok bool) { 474*4947cdc7SCole Faust switch x := x.(type) { 475*4947cdc7SCole Faust case Float: 476*4947cdc7SCole Faust return float64(x), true 477*4947cdc7SCole Faust case Int: 478*4947cdc7SCole Faust return float64(x.Float()), true 479*4947cdc7SCole Faust } 480*4947cdc7SCole Faust return 0, false 481*4947cdc7SCole Faust} 482*4947cdc7SCole Faust 483*4947cdc7SCole Faustfunc (x Float) Mod(y Float) Float { 484*4947cdc7SCole Faust z := Float(math.Mod(float64(x), float64(y))) 485*4947cdc7SCole Faust if (x < 0) != (y < 0) && z != 0 { 486*4947cdc7SCole Faust z += y 487*4947cdc7SCole Faust } 488*4947cdc7SCole Faust return z 489*4947cdc7SCole Faust} 490*4947cdc7SCole Faust 491*4947cdc7SCole Faust// Unary implements the operations +float and -float. 492*4947cdc7SCole Faustfunc (f Float) Unary(op syntax.Token) (Value, error) { 493*4947cdc7SCole Faust switch op { 494*4947cdc7SCole Faust case syntax.MINUS: 495*4947cdc7SCole Faust return -f, nil 496*4947cdc7SCole Faust case syntax.PLUS: 497*4947cdc7SCole Faust return +f, nil 498*4947cdc7SCole Faust } 499*4947cdc7SCole Faust return nil, nil 500*4947cdc7SCole Faust} 501*4947cdc7SCole Faust 502*4947cdc7SCole Faust// String is the type of a Starlark text string. 503*4947cdc7SCole Faust// 504*4947cdc7SCole Faust// A String encapsulates an an immutable sequence of bytes, 505*4947cdc7SCole Faust// but strings are not directly iterable. Instead, iterate 506*4947cdc7SCole Faust// over the result of calling one of these four methods: 507*4947cdc7SCole Faust// codepoints, codepoint_ords, elems, elem_ords. 508*4947cdc7SCole Faust// 509*4947cdc7SCole Faust// Strings typically contain text; use Bytes for binary strings. 510*4947cdc7SCole Faust// The Starlark spec defines text strings as sequences of UTF-k 511*4947cdc7SCole Faust// codes that encode Unicode code points. In this Go implementation, 512*4947cdc7SCole Faust// k=8, whereas in a Java implementation, k=16. For portability, 513*4947cdc7SCole Faust// operations on strings should aim to avoid assumptions about 514*4947cdc7SCole Faust// the value of k. 515*4947cdc7SCole Faust// 516*4947cdc7SCole Faust// Warning: the contract of the Value interface's String method is that 517*4947cdc7SCole Faust// it returns the value printed in Starlark notation, 518*4947cdc7SCole Faust// so s.String() or fmt.Sprintf("%s", s) returns a quoted string. 519*4947cdc7SCole Faust// Use string(s) or s.GoString() or fmt.Sprintf("%#v", s) to obtain the raw contents 520*4947cdc7SCole Faust// of a Starlark string as a Go string. 521*4947cdc7SCole Fausttype String string 522*4947cdc7SCole Faust 523*4947cdc7SCole Faustfunc (s String) String() string { return syntax.Quote(string(s), false) } 524*4947cdc7SCole Faustfunc (s String) GoString() string { return string(s) } 525*4947cdc7SCole Faustfunc (s String) Type() string { return "string" } 526*4947cdc7SCole Faustfunc (s String) Freeze() {} // immutable 527*4947cdc7SCole Faustfunc (s String) Truth() Bool { return len(s) > 0 } 528*4947cdc7SCole Faustfunc (s String) Hash() (uint32, error) { return hashString(string(s)), nil } 529*4947cdc7SCole Faustfunc (s String) Len() int { return len(s) } // bytes 530*4947cdc7SCole Faustfunc (s String) Index(i int) Value { return s[i : i+1] } 531*4947cdc7SCole Faust 532*4947cdc7SCole Faustfunc (s String) Slice(start, end, step int) Value { 533*4947cdc7SCole Faust if step == 1 { 534*4947cdc7SCole Faust return s[start:end] 535*4947cdc7SCole Faust } 536*4947cdc7SCole Faust 537*4947cdc7SCole Faust sign := signum(step) 538*4947cdc7SCole Faust var str []byte 539*4947cdc7SCole Faust for i := start; signum(end-i) == sign; i += step { 540*4947cdc7SCole Faust str = append(str, s[i]) 541*4947cdc7SCole Faust } 542*4947cdc7SCole Faust return String(str) 543*4947cdc7SCole Faust} 544*4947cdc7SCole Faust 545*4947cdc7SCole Faustfunc (s String) Attr(name string) (Value, error) { return builtinAttr(s, name, stringMethods) } 546*4947cdc7SCole Faustfunc (s String) AttrNames() []string { return builtinAttrNames(stringMethods) } 547*4947cdc7SCole Faust 548*4947cdc7SCole Faustfunc (x String) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 549*4947cdc7SCole Faust y := y_.(String) 550*4947cdc7SCole Faust return threeway(op, strings.Compare(string(x), string(y))), nil 551*4947cdc7SCole Faust} 552*4947cdc7SCole Faust 553*4947cdc7SCole Faustfunc AsString(x Value) (string, bool) { v, ok := x.(String); return string(v), ok } 554*4947cdc7SCole Faust 555*4947cdc7SCole Faust// A stringElems is an iterable whose iterator yields a sequence of 556*4947cdc7SCole Faust// elements (bytes), either numerically or as successive substrings. 557*4947cdc7SCole Faust// It is an indexable sequence. 558*4947cdc7SCole Fausttype stringElems struct { 559*4947cdc7SCole Faust s String 560*4947cdc7SCole Faust ords bool 561*4947cdc7SCole Faust} 562*4947cdc7SCole Faust 563*4947cdc7SCole Faustvar ( 564*4947cdc7SCole Faust _ Iterable = (*stringElems)(nil) 565*4947cdc7SCole Faust _ Indexable = (*stringElems)(nil) 566*4947cdc7SCole Faust) 567*4947cdc7SCole Faust 568*4947cdc7SCole Faustfunc (si stringElems) String() string { 569*4947cdc7SCole Faust if si.ords { 570*4947cdc7SCole Faust return si.s.String() + ".elem_ords()" 571*4947cdc7SCole Faust } else { 572*4947cdc7SCole Faust return si.s.String() + ".elems()" 573*4947cdc7SCole Faust } 574*4947cdc7SCole Faust} 575*4947cdc7SCole Faustfunc (si stringElems) Type() string { return "string.elems" } 576*4947cdc7SCole Faustfunc (si stringElems) Freeze() {} // immutable 577*4947cdc7SCole Faustfunc (si stringElems) Truth() Bool { return True } 578*4947cdc7SCole Faustfunc (si stringElems) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", si.Type()) } 579*4947cdc7SCole Faustfunc (si stringElems) Iterate() Iterator { return &stringElemsIterator{si, 0} } 580*4947cdc7SCole Faustfunc (si stringElems) Len() int { return len(si.s) } 581*4947cdc7SCole Faustfunc (si stringElems) Index(i int) Value { 582*4947cdc7SCole Faust if si.ords { 583*4947cdc7SCole Faust return MakeInt(int(si.s[i])) 584*4947cdc7SCole Faust } else { 585*4947cdc7SCole Faust // TODO(adonovan): opt: preallocate canonical 1-byte strings 586*4947cdc7SCole Faust // to avoid interface allocation. 587*4947cdc7SCole Faust return si.s[i : i+1] 588*4947cdc7SCole Faust } 589*4947cdc7SCole Faust} 590*4947cdc7SCole Faust 591*4947cdc7SCole Fausttype stringElemsIterator struct { 592*4947cdc7SCole Faust si stringElems 593*4947cdc7SCole Faust i int 594*4947cdc7SCole Faust} 595*4947cdc7SCole Faust 596*4947cdc7SCole Faustfunc (it *stringElemsIterator) Next(p *Value) bool { 597*4947cdc7SCole Faust if it.i == len(it.si.s) { 598*4947cdc7SCole Faust return false 599*4947cdc7SCole Faust } 600*4947cdc7SCole Faust *p = it.si.Index(it.i) 601*4947cdc7SCole Faust it.i++ 602*4947cdc7SCole Faust return true 603*4947cdc7SCole Faust} 604*4947cdc7SCole Faust 605*4947cdc7SCole Faustfunc (*stringElemsIterator) Done() {} 606*4947cdc7SCole Faust 607*4947cdc7SCole Faust// A stringCodepoints is an iterable whose iterator yields a sequence of 608*4947cdc7SCole Faust// Unicode code points, either numerically or as successive substrings. 609*4947cdc7SCole Faust// It is not indexable. 610*4947cdc7SCole Fausttype stringCodepoints struct { 611*4947cdc7SCole Faust s String 612*4947cdc7SCole Faust ords bool 613*4947cdc7SCole Faust} 614*4947cdc7SCole Faust 615*4947cdc7SCole Faustvar _ Iterable = (*stringCodepoints)(nil) 616*4947cdc7SCole Faust 617*4947cdc7SCole Faustfunc (si stringCodepoints) String() string { 618*4947cdc7SCole Faust if si.ords { 619*4947cdc7SCole Faust return si.s.String() + ".codepoint_ords()" 620*4947cdc7SCole Faust } else { 621*4947cdc7SCole Faust return si.s.String() + ".codepoints()" 622*4947cdc7SCole Faust } 623*4947cdc7SCole Faust} 624*4947cdc7SCole Faustfunc (si stringCodepoints) Type() string { return "string.codepoints" } 625*4947cdc7SCole Faustfunc (si stringCodepoints) Freeze() {} // immutable 626*4947cdc7SCole Faustfunc (si stringCodepoints) Truth() Bool { return True } 627*4947cdc7SCole Faustfunc (si stringCodepoints) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", si.Type()) } 628*4947cdc7SCole Faustfunc (si stringCodepoints) Iterate() Iterator { return &stringCodepointsIterator{si, 0} } 629*4947cdc7SCole Faust 630*4947cdc7SCole Fausttype stringCodepointsIterator struct { 631*4947cdc7SCole Faust si stringCodepoints 632*4947cdc7SCole Faust i int 633*4947cdc7SCole Faust} 634*4947cdc7SCole Faust 635*4947cdc7SCole Faustfunc (it *stringCodepointsIterator) Next(p *Value) bool { 636*4947cdc7SCole Faust s := it.si.s[it.i:] 637*4947cdc7SCole Faust if s == "" { 638*4947cdc7SCole Faust return false 639*4947cdc7SCole Faust } 640*4947cdc7SCole Faust r, sz := utf8.DecodeRuneInString(string(s)) 641*4947cdc7SCole Faust if !it.si.ords { 642*4947cdc7SCole Faust if r == utf8.RuneError { 643*4947cdc7SCole Faust *p = String(r) 644*4947cdc7SCole Faust } else { 645*4947cdc7SCole Faust *p = s[:sz] 646*4947cdc7SCole Faust } 647*4947cdc7SCole Faust } else { 648*4947cdc7SCole Faust *p = MakeInt(int(r)) 649*4947cdc7SCole Faust } 650*4947cdc7SCole Faust it.i += sz 651*4947cdc7SCole Faust return true 652*4947cdc7SCole Faust} 653*4947cdc7SCole Faust 654*4947cdc7SCole Faustfunc (*stringCodepointsIterator) Done() {} 655*4947cdc7SCole Faust 656*4947cdc7SCole Faust// A Function is a function defined by a Starlark def statement or lambda expression. 657*4947cdc7SCole Faust// The initialization behavior of a Starlark module is also represented by a Function. 658*4947cdc7SCole Fausttype Function struct { 659*4947cdc7SCole Faust funcode *compile.Funcode 660*4947cdc7SCole Faust module *module 661*4947cdc7SCole Faust defaults Tuple 662*4947cdc7SCole Faust freevars Tuple 663*4947cdc7SCole Faust} 664*4947cdc7SCole Faust 665*4947cdc7SCole Faust// A module is the dynamic counterpart to a Program. 666*4947cdc7SCole Faust// All functions in the same program share a module. 667*4947cdc7SCole Fausttype module struct { 668*4947cdc7SCole Faust program *compile.Program 669*4947cdc7SCole Faust predeclared StringDict 670*4947cdc7SCole Faust globals []Value 671*4947cdc7SCole Faust constants []Value 672*4947cdc7SCole Faust} 673*4947cdc7SCole Faust 674*4947cdc7SCole Faust// makeGlobalDict returns a new, unfrozen StringDict containing all global 675*4947cdc7SCole Faust// variables so far defined in the module. 676*4947cdc7SCole Faustfunc (m *module) makeGlobalDict() StringDict { 677*4947cdc7SCole Faust r := make(StringDict, len(m.program.Globals)) 678*4947cdc7SCole Faust for i, id := range m.program.Globals { 679*4947cdc7SCole Faust if v := m.globals[i]; v != nil { 680*4947cdc7SCole Faust r[id.Name] = v 681*4947cdc7SCole Faust } 682*4947cdc7SCole Faust } 683*4947cdc7SCole Faust return r 684*4947cdc7SCole Faust} 685*4947cdc7SCole Faust 686*4947cdc7SCole Faustfunc (fn *Function) Name() string { return fn.funcode.Name } // "lambda" for anonymous functions 687*4947cdc7SCole Faustfunc (fn *Function) Doc() string { return fn.funcode.Doc } 688*4947cdc7SCole Faustfunc (fn *Function) Hash() (uint32, error) { return hashString(fn.funcode.Name), nil } 689*4947cdc7SCole Faustfunc (fn *Function) Freeze() { fn.defaults.Freeze(); fn.freevars.Freeze() } 690*4947cdc7SCole Faustfunc (fn *Function) String() string { return toString(fn) } 691*4947cdc7SCole Faustfunc (fn *Function) Type() string { return "function" } 692*4947cdc7SCole Faustfunc (fn *Function) Truth() Bool { return true } 693*4947cdc7SCole Faust 694*4947cdc7SCole Faust// Globals returns a new, unfrozen StringDict containing all global 695*4947cdc7SCole Faust// variables so far defined in the function's module. 696*4947cdc7SCole Faustfunc (fn *Function) Globals() StringDict { return fn.module.makeGlobalDict() } 697*4947cdc7SCole Faust 698*4947cdc7SCole Faustfunc (fn *Function) Position() syntax.Position { return fn.funcode.Pos } 699*4947cdc7SCole Faustfunc (fn *Function) NumParams() int { return fn.funcode.NumParams } 700*4947cdc7SCole Faustfunc (fn *Function) NumKwonlyParams() int { return fn.funcode.NumKwonlyParams } 701*4947cdc7SCole Faust 702*4947cdc7SCole Faust// Param returns the name and position of the ith parameter, 703*4947cdc7SCole Faust// where 0 <= i < NumParams(). 704*4947cdc7SCole Faust// The *args and **kwargs parameters are at the end 705*4947cdc7SCole Faust// even if there were optional parameters after *args. 706*4947cdc7SCole Faustfunc (fn *Function) Param(i int) (string, syntax.Position) { 707*4947cdc7SCole Faust if i >= fn.NumParams() { 708*4947cdc7SCole Faust panic(i) 709*4947cdc7SCole Faust } 710*4947cdc7SCole Faust id := fn.funcode.Locals[i] 711*4947cdc7SCole Faust return id.Name, id.Pos 712*4947cdc7SCole Faust} 713*4947cdc7SCole Faustfunc (fn *Function) HasVarargs() bool { return fn.funcode.HasVarargs } 714*4947cdc7SCole Faustfunc (fn *Function) HasKwargs() bool { return fn.funcode.HasKwargs } 715*4947cdc7SCole Faust 716*4947cdc7SCole Faust// A Builtin is a function implemented in Go. 717*4947cdc7SCole Fausttype Builtin struct { 718*4947cdc7SCole Faust name string 719*4947cdc7SCole Faust fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error) 720*4947cdc7SCole Faust recv Value // for bound methods (e.g. "".startswith) 721*4947cdc7SCole Faust} 722*4947cdc7SCole Faust 723*4947cdc7SCole Faustfunc (b *Builtin) Name() string { return b.name } 724*4947cdc7SCole Faustfunc (b *Builtin) Freeze() { 725*4947cdc7SCole Faust if b.recv != nil { 726*4947cdc7SCole Faust b.recv.Freeze() 727*4947cdc7SCole Faust } 728*4947cdc7SCole Faust} 729*4947cdc7SCole Faustfunc (b *Builtin) Hash() (uint32, error) { 730*4947cdc7SCole Faust h := hashString(b.name) 731*4947cdc7SCole Faust if b.recv != nil { 732*4947cdc7SCole Faust h ^= 5521 733*4947cdc7SCole Faust } 734*4947cdc7SCole Faust return h, nil 735*4947cdc7SCole Faust} 736*4947cdc7SCole Faustfunc (b *Builtin) Receiver() Value { return b.recv } 737*4947cdc7SCole Faustfunc (b *Builtin) String() string { return toString(b) } 738*4947cdc7SCole Faustfunc (b *Builtin) Type() string { return "builtin_function_or_method" } 739*4947cdc7SCole Faustfunc (b *Builtin) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) { 740*4947cdc7SCole Faust return b.fn(thread, b, args, kwargs) 741*4947cdc7SCole Faust} 742*4947cdc7SCole Faustfunc (b *Builtin) Truth() Bool { return true } 743*4947cdc7SCole Faust 744*4947cdc7SCole Faust// NewBuiltin returns a new 'builtin_function_or_method' value with the specified name 745*4947cdc7SCole Faust// and implementation. It compares unequal with all other values. 746*4947cdc7SCole Faustfunc NewBuiltin(name string, fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error)) *Builtin { 747*4947cdc7SCole Faust return &Builtin{name: name, fn: fn} 748*4947cdc7SCole Faust} 749*4947cdc7SCole Faust 750*4947cdc7SCole Faust// BindReceiver returns a new Builtin value representing a method 751*4947cdc7SCole Faust// closure, that is, a built-in function bound to a receiver value. 752*4947cdc7SCole Faust// 753*4947cdc7SCole Faust// In the example below, the value of f is the string.index 754*4947cdc7SCole Faust// built-in method bound to the receiver value "abc": 755*4947cdc7SCole Faust// 756*4947cdc7SCole Faust// f = "abc".index; f("a"); f("b") 757*4947cdc7SCole Faust// 758*4947cdc7SCole Faust// In the common case, the receiver is bound only during the call, 759*4947cdc7SCole Faust// but this still results in the creation of a temporary method closure: 760*4947cdc7SCole Faust// 761*4947cdc7SCole Faust// "abc".index("a") 762*4947cdc7SCole Faust// 763*4947cdc7SCole Faustfunc (b *Builtin) BindReceiver(recv Value) *Builtin { 764*4947cdc7SCole Faust return &Builtin{name: b.name, fn: b.fn, recv: recv} 765*4947cdc7SCole Faust} 766*4947cdc7SCole Faust 767*4947cdc7SCole Faust// A *Dict represents a Starlark dictionary. 768*4947cdc7SCole Faust// The zero value of Dict is a valid empty dictionary. 769*4947cdc7SCole Faust// If you know the exact final number of entries, 770*4947cdc7SCole Faust// it is more efficient to call NewDict. 771*4947cdc7SCole Fausttype Dict struct { 772*4947cdc7SCole Faust ht hashtable 773*4947cdc7SCole Faust} 774*4947cdc7SCole Faust 775*4947cdc7SCole Faust// NewDict returns a set with initial space for 776*4947cdc7SCole Faust// at least size insertions before rehashing. 777*4947cdc7SCole Faustfunc NewDict(size int) *Dict { 778*4947cdc7SCole Faust dict := new(Dict) 779*4947cdc7SCole Faust dict.ht.init(size) 780*4947cdc7SCole Faust return dict 781*4947cdc7SCole Faust} 782*4947cdc7SCole Faust 783*4947cdc7SCole Faustfunc (d *Dict) Clear() error { return d.ht.clear() } 784*4947cdc7SCole Faustfunc (d *Dict) Delete(k Value) (v Value, found bool, err error) { return d.ht.delete(k) } 785*4947cdc7SCole Faustfunc (d *Dict) Get(k Value) (v Value, found bool, err error) { return d.ht.lookup(k) } 786*4947cdc7SCole Faustfunc (d *Dict) Items() []Tuple { return d.ht.items() } 787*4947cdc7SCole Faustfunc (d *Dict) Keys() []Value { return d.ht.keys() } 788*4947cdc7SCole Faustfunc (d *Dict) Len() int { return int(d.ht.len) } 789*4947cdc7SCole Faustfunc (d *Dict) Iterate() Iterator { return d.ht.iterate() } 790*4947cdc7SCole Faustfunc (d *Dict) SetKey(k, v Value) error { return d.ht.insert(k, v) } 791*4947cdc7SCole Faustfunc (d *Dict) String() string { return toString(d) } 792*4947cdc7SCole Faustfunc (d *Dict) Type() string { return "dict" } 793*4947cdc7SCole Faustfunc (d *Dict) Freeze() { d.ht.freeze() } 794*4947cdc7SCole Faustfunc (d *Dict) Truth() Bool { return d.Len() > 0 } 795*4947cdc7SCole Faustfunc (d *Dict) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: dict") } 796*4947cdc7SCole Faust 797*4947cdc7SCole Faustfunc (d *Dict) Attr(name string) (Value, error) { return builtinAttr(d, name, dictMethods) } 798*4947cdc7SCole Faustfunc (d *Dict) AttrNames() []string { return builtinAttrNames(dictMethods) } 799*4947cdc7SCole Faust 800*4947cdc7SCole Faustfunc (x *Dict) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 801*4947cdc7SCole Faust y := y_.(*Dict) 802*4947cdc7SCole Faust switch op { 803*4947cdc7SCole Faust case syntax.EQL: 804*4947cdc7SCole Faust ok, err := dictsEqual(x, y, depth) 805*4947cdc7SCole Faust return ok, err 806*4947cdc7SCole Faust case syntax.NEQ: 807*4947cdc7SCole Faust ok, err := dictsEqual(x, y, depth) 808*4947cdc7SCole Faust return !ok, err 809*4947cdc7SCole Faust default: 810*4947cdc7SCole Faust return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) 811*4947cdc7SCole Faust } 812*4947cdc7SCole Faust} 813*4947cdc7SCole Faust 814*4947cdc7SCole Faustfunc dictsEqual(x, y *Dict, depth int) (bool, error) { 815*4947cdc7SCole Faust if x.Len() != y.Len() { 816*4947cdc7SCole Faust return false, nil 817*4947cdc7SCole Faust } 818*4947cdc7SCole Faust for _, xitem := range x.Items() { 819*4947cdc7SCole Faust key, xval := xitem[0], xitem[1] 820*4947cdc7SCole Faust 821*4947cdc7SCole Faust if yval, found, _ := y.Get(key); !found { 822*4947cdc7SCole Faust return false, nil 823*4947cdc7SCole Faust } else if eq, err := EqualDepth(xval, yval, depth-1); err != nil { 824*4947cdc7SCole Faust return false, err 825*4947cdc7SCole Faust } else if !eq { 826*4947cdc7SCole Faust return false, nil 827*4947cdc7SCole Faust } 828*4947cdc7SCole Faust } 829*4947cdc7SCole Faust return true, nil 830*4947cdc7SCole Faust} 831*4947cdc7SCole Faust 832*4947cdc7SCole Faust// A *List represents a Starlark list value. 833*4947cdc7SCole Fausttype List struct { 834*4947cdc7SCole Faust elems []Value 835*4947cdc7SCole Faust frozen bool 836*4947cdc7SCole Faust itercount uint32 // number of active iterators (ignored if frozen) 837*4947cdc7SCole Faust} 838*4947cdc7SCole Faust 839*4947cdc7SCole Faust// NewList returns a list containing the specified elements. 840*4947cdc7SCole Faust// Callers should not subsequently modify elems. 841*4947cdc7SCole Faustfunc NewList(elems []Value) *List { return &List{elems: elems} } 842*4947cdc7SCole Faust 843*4947cdc7SCole Faustfunc (l *List) Freeze() { 844*4947cdc7SCole Faust if !l.frozen { 845*4947cdc7SCole Faust l.frozen = true 846*4947cdc7SCole Faust for _, elem := range l.elems { 847*4947cdc7SCole Faust elem.Freeze() 848*4947cdc7SCole Faust } 849*4947cdc7SCole Faust } 850*4947cdc7SCole Faust} 851*4947cdc7SCole Faust 852*4947cdc7SCole Faust// checkMutable reports an error if the list should not be mutated. 853*4947cdc7SCole Faust// verb+" list" should describe the operation. 854*4947cdc7SCole Faustfunc (l *List) checkMutable(verb string) error { 855*4947cdc7SCole Faust if l.frozen { 856*4947cdc7SCole Faust return fmt.Errorf("cannot %s frozen list", verb) 857*4947cdc7SCole Faust } 858*4947cdc7SCole Faust if l.itercount > 0 { 859*4947cdc7SCole Faust return fmt.Errorf("cannot %s list during iteration", verb) 860*4947cdc7SCole Faust } 861*4947cdc7SCole Faust return nil 862*4947cdc7SCole Faust} 863*4947cdc7SCole Faust 864*4947cdc7SCole Faustfunc (l *List) String() string { return toString(l) } 865*4947cdc7SCole Faustfunc (l *List) Type() string { return "list" } 866*4947cdc7SCole Faustfunc (l *List) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: list") } 867*4947cdc7SCole Faustfunc (l *List) Truth() Bool { return l.Len() > 0 } 868*4947cdc7SCole Faustfunc (l *List) Len() int { return len(l.elems) } 869*4947cdc7SCole Faustfunc (l *List) Index(i int) Value { return l.elems[i] } 870*4947cdc7SCole Faust 871*4947cdc7SCole Faustfunc (l *List) Slice(start, end, step int) Value { 872*4947cdc7SCole Faust if step == 1 { 873*4947cdc7SCole Faust elems := append([]Value{}, l.elems[start:end]...) 874*4947cdc7SCole Faust return NewList(elems) 875*4947cdc7SCole Faust } 876*4947cdc7SCole Faust 877*4947cdc7SCole Faust sign := signum(step) 878*4947cdc7SCole Faust var list []Value 879*4947cdc7SCole Faust for i := start; signum(end-i) == sign; i += step { 880*4947cdc7SCole Faust list = append(list, l.elems[i]) 881*4947cdc7SCole Faust } 882*4947cdc7SCole Faust return NewList(list) 883*4947cdc7SCole Faust} 884*4947cdc7SCole Faust 885*4947cdc7SCole Faustfunc (l *List) Attr(name string) (Value, error) { return builtinAttr(l, name, listMethods) } 886*4947cdc7SCole Faustfunc (l *List) AttrNames() []string { return builtinAttrNames(listMethods) } 887*4947cdc7SCole Faust 888*4947cdc7SCole Faustfunc (l *List) Iterate() Iterator { 889*4947cdc7SCole Faust if !l.frozen { 890*4947cdc7SCole Faust l.itercount++ 891*4947cdc7SCole Faust } 892*4947cdc7SCole Faust return &listIterator{l: l} 893*4947cdc7SCole Faust} 894*4947cdc7SCole Faust 895*4947cdc7SCole Faustfunc (x *List) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 896*4947cdc7SCole Faust y := y_.(*List) 897*4947cdc7SCole Faust // It's tempting to check x == y as an optimization here, 898*4947cdc7SCole Faust // but wrong because a list containing NaN is not equal to itself. 899*4947cdc7SCole Faust return sliceCompare(op, x.elems, y.elems, depth) 900*4947cdc7SCole Faust} 901*4947cdc7SCole Faust 902*4947cdc7SCole Faustfunc sliceCompare(op syntax.Token, x, y []Value, depth int) (bool, error) { 903*4947cdc7SCole Faust // Fast path: check length. 904*4947cdc7SCole Faust if len(x) != len(y) && (op == syntax.EQL || op == syntax.NEQ) { 905*4947cdc7SCole Faust return op == syntax.NEQ, nil 906*4947cdc7SCole Faust } 907*4947cdc7SCole Faust 908*4947cdc7SCole Faust // Find first element that is not equal in both lists. 909*4947cdc7SCole Faust for i := 0; i < len(x) && i < len(y); i++ { 910*4947cdc7SCole Faust if eq, err := EqualDepth(x[i], y[i], depth-1); err != nil { 911*4947cdc7SCole Faust return false, err 912*4947cdc7SCole Faust } else if !eq { 913*4947cdc7SCole Faust switch op { 914*4947cdc7SCole Faust case syntax.EQL: 915*4947cdc7SCole Faust return false, nil 916*4947cdc7SCole Faust case syntax.NEQ: 917*4947cdc7SCole Faust return true, nil 918*4947cdc7SCole Faust default: 919*4947cdc7SCole Faust return CompareDepth(op, x[i], y[i], depth-1) 920*4947cdc7SCole Faust } 921*4947cdc7SCole Faust } 922*4947cdc7SCole Faust } 923*4947cdc7SCole Faust 924*4947cdc7SCole Faust return threeway(op, len(x)-len(y)), nil 925*4947cdc7SCole Faust} 926*4947cdc7SCole Faust 927*4947cdc7SCole Fausttype listIterator struct { 928*4947cdc7SCole Faust l *List 929*4947cdc7SCole Faust i int 930*4947cdc7SCole Faust} 931*4947cdc7SCole Faust 932*4947cdc7SCole Faustfunc (it *listIterator) Next(p *Value) bool { 933*4947cdc7SCole Faust if it.i < it.l.Len() { 934*4947cdc7SCole Faust *p = it.l.elems[it.i] 935*4947cdc7SCole Faust it.i++ 936*4947cdc7SCole Faust return true 937*4947cdc7SCole Faust } 938*4947cdc7SCole Faust return false 939*4947cdc7SCole Faust} 940*4947cdc7SCole Faust 941*4947cdc7SCole Faustfunc (it *listIterator) Done() { 942*4947cdc7SCole Faust if !it.l.frozen { 943*4947cdc7SCole Faust it.l.itercount-- 944*4947cdc7SCole Faust } 945*4947cdc7SCole Faust} 946*4947cdc7SCole Faust 947*4947cdc7SCole Faustfunc (l *List) SetIndex(i int, v Value) error { 948*4947cdc7SCole Faust if err := l.checkMutable("assign to element of"); err != nil { 949*4947cdc7SCole Faust return err 950*4947cdc7SCole Faust } 951*4947cdc7SCole Faust l.elems[i] = v 952*4947cdc7SCole Faust return nil 953*4947cdc7SCole Faust} 954*4947cdc7SCole Faust 955*4947cdc7SCole Faustfunc (l *List) Append(v Value) error { 956*4947cdc7SCole Faust if err := l.checkMutable("append to"); err != nil { 957*4947cdc7SCole Faust return err 958*4947cdc7SCole Faust } 959*4947cdc7SCole Faust l.elems = append(l.elems, v) 960*4947cdc7SCole Faust return nil 961*4947cdc7SCole Faust} 962*4947cdc7SCole Faust 963*4947cdc7SCole Faustfunc (l *List) Clear() error { 964*4947cdc7SCole Faust if err := l.checkMutable("clear"); err != nil { 965*4947cdc7SCole Faust return err 966*4947cdc7SCole Faust } 967*4947cdc7SCole Faust for i := range l.elems { 968*4947cdc7SCole Faust l.elems[i] = nil // aid GC 969*4947cdc7SCole Faust } 970*4947cdc7SCole Faust l.elems = l.elems[:0] 971*4947cdc7SCole Faust return nil 972*4947cdc7SCole Faust} 973*4947cdc7SCole Faust 974*4947cdc7SCole Faust// A Tuple represents a Starlark tuple value. 975*4947cdc7SCole Fausttype Tuple []Value 976*4947cdc7SCole Faust 977*4947cdc7SCole Faustfunc (t Tuple) Len() int { return len(t) } 978*4947cdc7SCole Faustfunc (t Tuple) Index(i int) Value { return t[i] } 979*4947cdc7SCole Faust 980*4947cdc7SCole Faustfunc (t Tuple) Slice(start, end, step int) Value { 981*4947cdc7SCole Faust if step == 1 { 982*4947cdc7SCole Faust return t[start:end] 983*4947cdc7SCole Faust } 984*4947cdc7SCole Faust 985*4947cdc7SCole Faust sign := signum(step) 986*4947cdc7SCole Faust var tuple Tuple 987*4947cdc7SCole Faust for i := start; signum(end-i) == sign; i += step { 988*4947cdc7SCole Faust tuple = append(tuple, t[i]) 989*4947cdc7SCole Faust } 990*4947cdc7SCole Faust return tuple 991*4947cdc7SCole Faust} 992*4947cdc7SCole Faust 993*4947cdc7SCole Faustfunc (t Tuple) Iterate() Iterator { return &tupleIterator{elems: t} } 994*4947cdc7SCole Faustfunc (t Tuple) Freeze() { 995*4947cdc7SCole Faust for _, elem := range t { 996*4947cdc7SCole Faust elem.Freeze() 997*4947cdc7SCole Faust } 998*4947cdc7SCole Faust} 999*4947cdc7SCole Faustfunc (t Tuple) String() string { return toString(t) } 1000*4947cdc7SCole Faustfunc (t Tuple) Type() string { return "tuple" } 1001*4947cdc7SCole Faustfunc (t Tuple) Truth() Bool { return len(t) > 0 } 1002*4947cdc7SCole Faust 1003*4947cdc7SCole Faustfunc (x Tuple) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 1004*4947cdc7SCole Faust y := y_.(Tuple) 1005*4947cdc7SCole Faust return sliceCompare(op, x, y, depth) 1006*4947cdc7SCole Faust} 1007*4947cdc7SCole Faust 1008*4947cdc7SCole Faustfunc (t Tuple) Hash() (uint32, error) { 1009*4947cdc7SCole Faust // Use same algorithm as Python. 1010*4947cdc7SCole Faust var x, mult uint32 = 0x345678, 1000003 1011*4947cdc7SCole Faust for _, elem := range t { 1012*4947cdc7SCole Faust y, err := elem.Hash() 1013*4947cdc7SCole Faust if err != nil { 1014*4947cdc7SCole Faust return 0, err 1015*4947cdc7SCole Faust } 1016*4947cdc7SCole Faust x = x ^ y*mult 1017*4947cdc7SCole Faust mult += 82520 + uint32(len(t)+len(t)) 1018*4947cdc7SCole Faust } 1019*4947cdc7SCole Faust return x, nil 1020*4947cdc7SCole Faust} 1021*4947cdc7SCole Faust 1022*4947cdc7SCole Fausttype tupleIterator struct{ elems Tuple } 1023*4947cdc7SCole Faust 1024*4947cdc7SCole Faustfunc (it *tupleIterator) Next(p *Value) bool { 1025*4947cdc7SCole Faust if len(it.elems) > 0 { 1026*4947cdc7SCole Faust *p = it.elems[0] 1027*4947cdc7SCole Faust it.elems = it.elems[1:] 1028*4947cdc7SCole Faust return true 1029*4947cdc7SCole Faust } 1030*4947cdc7SCole Faust return false 1031*4947cdc7SCole Faust} 1032*4947cdc7SCole Faust 1033*4947cdc7SCole Faustfunc (it *tupleIterator) Done() {} 1034*4947cdc7SCole Faust 1035*4947cdc7SCole Faust// A Set represents a Starlark set value. 1036*4947cdc7SCole Faust// The zero value of Set is a valid empty set. 1037*4947cdc7SCole Faust// If you know the exact final number of elements, 1038*4947cdc7SCole Faust// it is more efficient to call NewSet. 1039*4947cdc7SCole Fausttype Set struct { 1040*4947cdc7SCole Faust ht hashtable // values are all None 1041*4947cdc7SCole Faust} 1042*4947cdc7SCole Faust 1043*4947cdc7SCole Faust// NewSet returns a dictionary with initial space for 1044*4947cdc7SCole Faust// at least size insertions before rehashing. 1045*4947cdc7SCole Faustfunc NewSet(size int) *Set { 1046*4947cdc7SCole Faust set := new(Set) 1047*4947cdc7SCole Faust set.ht.init(size) 1048*4947cdc7SCole Faust return set 1049*4947cdc7SCole Faust} 1050*4947cdc7SCole Faust 1051*4947cdc7SCole Faustfunc (s *Set) Delete(k Value) (found bool, err error) { _, found, err = s.ht.delete(k); return } 1052*4947cdc7SCole Faustfunc (s *Set) Clear() error { return s.ht.clear() } 1053*4947cdc7SCole Faustfunc (s *Set) Has(k Value) (found bool, err error) { _, found, err = s.ht.lookup(k); return } 1054*4947cdc7SCole Faustfunc (s *Set) Insert(k Value) error { return s.ht.insert(k, None) } 1055*4947cdc7SCole Faustfunc (s *Set) Len() int { return int(s.ht.len) } 1056*4947cdc7SCole Faustfunc (s *Set) Iterate() Iterator { return s.ht.iterate() } 1057*4947cdc7SCole Faustfunc (s *Set) String() string { return toString(s) } 1058*4947cdc7SCole Faustfunc (s *Set) Type() string { return "set" } 1059*4947cdc7SCole Faustfunc (s *Set) elems() []Value { return s.ht.keys() } 1060*4947cdc7SCole Faustfunc (s *Set) Freeze() { s.ht.freeze() } 1061*4947cdc7SCole Faustfunc (s *Set) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: set") } 1062*4947cdc7SCole Faustfunc (s *Set) Truth() Bool { return s.Len() > 0 } 1063*4947cdc7SCole Faust 1064*4947cdc7SCole Faustfunc (s *Set) Attr(name string) (Value, error) { return builtinAttr(s, name, setMethods) } 1065*4947cdc7SCole Faustfunc (s *Set) AttrNames() []string { return builtinAttrNames(setMethods) } 1066*4947cdc7SCole Faust 1067*4947cdc7SCole Faustfunc (x *Set) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 1068*4947cdc7SCole Faust y := y_.(*Set) 1069*4947cdc7SCole Faust switch op { 1070*4947cdc7SCole Faust case syntax.EQL: 1071*4947cdc7SCole Faust ok, err := setsEqual(x, y, depth) 1072*4947cdc7SCole Faust return ok, err 1073*4947cdc7SCole Faust case syntax.NEQ: 1074*4947cdc7SCole Faust ok, err := setsEqual(x, y, depth) 1075*4947cdc7SCole Faust return !ok, err 1076*4947cdc7SCole Faust default: 1077*4947cdc7SCole Faust return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) 1078*4947cdc7SCole Faust } 1079*4947cdc7SCole Faust} 1080*4947cdc7SCole Faust 1081*4947cdc7SCole Faustfunc setsEqual(x, y *Set, depth int) (bool, error) { 1082*4947cdc7SCole Faust if x.Len() != y.Len() { 1083*4947cdc7SCole Faust return false, nil 1084*4947cdc7SCole Faust } 1085*4947cdc7SCole Faust for _, elem := range x.elems() { 1086*4947cdc7SCole Faust if found, _ := y.Has(elem); !found { 1087*4947cdc7SCole Faust return false, nil 1088*4947cdc7SCole Faust } 1089*4947cdc7SCole Faust } 1090*4947cdc7SCole Faust return true, nil 1091*4947cdc7SCole Faust} 1092*4947cdc7SCole Faust 1093*4947cdc7SCole Faustfunc (s *Set) Union(iter Iterator) (Value, error) { 1094*4947cdc7SCole Faust set := new(Set) 1095*4947cdc7SCole Faust for _, elem := range s.elems() { 1096*4947cdc7SCole Faust set.Insert(elem) // can't fail 1097*4947cdc7SCole Faust } 1098*4947cdc7SCole Faust var x Value 1099*4947cdc7SCole Faust for iter.Next(&x) { 1100*4947cdc7SCole Faust if err := set.Insert(x); err != nil { 1101*4947cdc7SCole Faust return nil, err 1102*4947cdc7SCole Faust } 1103*4947cdc7SCole Faust } 1104*4947cdc7SCole Faust return set, nil 1105*4947cdc7SCole Faust} 1106*4947cdc7SCole Faust 1107*4947cdc7SCole Faust// toString returns the string form of value v. 1108*4947cdc7SCole Faust// It may be more efficient than v.String() for larger values. 1109*4947cdc7SCole Faustfunc toString(v Value) string { 1110*4947cdc7SCole Faust buf := new(strings.Builder) 1111*4947cdc7SCole Faust writeValue(buf, v, nil) 1112*4947cdc7SCole Faust return buf.String() 1113*4947cdc7SCole Faust} 1114*4947cdc7SCole Faust 1115*4947cdc7SCole Faust// writeValue writes x to out. 1116*4947cdc7SCole Faust// 1117*4947cdc7SCole Faust// path is used to detect cycles. 1118*4947cdc7SCole Faust// It contains the list of *List and *Dict values we're currently printing. 1119*4947cdc7SCole Faust// (These are the only potentially cyclic structures.) 1120*4947cdc7SCole Faust// Callers should generally pass nil for path. 1121*4947cdc7SCole Faust// It is safe to re-use the same path slice for multiple calls. 1122*4947cdc7SCole Faustfunc writeValue(out *strings.Builder, x Value, path []Value) { 1123*4947cdc7SCole Faust switch x := x.(type) { 1124*4947cdc7SCole Faust case nil: 1125*4947cdc7SCole Faust out.WriteString("<nil>") // indicates a bug 1126*4947cdc7SCole Faust 1127*4947cdc7SCole Faust // These four cases are duplicates of T.String(), for efficiency. 1128*4947cdc7SCole Faust case NoneType: 1129*4947cdc7SCole Faust out.WriteString("None") 1130*4947cdc7SCole Faust 1131*4947cdc7SCole Faust case Int: 1132*4947cdc7SCole Faust out.WriteString(x.String()) 1133*4947cdc7SCole Faust 1134*4947cdc7SCole Faust case Bool: 1135*4947cdc7SCole Faust if x { 1136*4947cdc7SCole Faust out.WriteString("True") 1137*4947cdc7SCole Faust } else { 1138*4947cdc7SCole Faust out.WriteString("False") 1139*4947cdc7SCole Faust } 1140*4947cdc7SCole Faust 1141*4947cdc7SCole Faust case String: 1142*4947cdc7SCole Faust out.WriteString(syntax.Quote(string(x), false)) 1143*4947cdc7SCole Faust 1144*4947cdc7SCole Faust case *List: 1145*4947cdc7SCole Faust out.WriteByte('[') 1146*4947cdc7SCole Faust if pathContains(path, x) { 1147*4947cdc7SCole Faust out.WriteString("...") // list contains itself 1148*4947cdc7SCole Faust } else { 1149*4947cdc7SCole Faust for i, elem := range x.elems { 1150*4947cdc7SCole Faust if i > 0 { 1151*4947cdc7SCole Faust out.WriteString(", ") 1152*4947cdc7SCole Faust } 1153*4947cdc7SCole Faust writeValue(out, elem, append(path, x)) 1154*4947cdc7SCole Faust } 1155*4947cdc7SCole Faust } 1156*4947cdc7SCole Faust out.WriteByte(']') 1157*4947cdc7SCole Faust 1158*4947cdc7SCole Faust case Tuple: 1159*4947cdc7SCole Faust out.WriteByte('(') 1160*4947cdc7SCole Faust for i, elem := range x { 1161*4947cdc7SCole Faust if i > 0 { 1162*4947cdc7SCole Faust out.WriteString(", ") 1163*4947cdc7SCole Faust } 1164*4947cdc7SCole Faust writeValue(out, elem, path) 1165*4947cdc7SCole Faust } 1166*4947cdc7SCole Faust if len(x) == 1 { 1167*4947cdc7SCole Faust out.WriteByte(',') 1168*4947cdc7SCole Faust } 1169*4947cdc7SCole Faust out.WriteByte(')') 1170*4947cdc7SCole Faust 1171*4947cdc7SCole Faust case *Function: 1172*4947cdc7SCole Faust fmt.Fprintf(out, "<function %s>", x.Name()) 1173*4947cdc7SCole Faust 1174*4947cdc7SCole Faust case *Builtin: 1175*4947cdc7SCole Faust if x.recv != nil { 1176*4947cdc7SCole Faust fmt.Fprintf(out, "<built-in method %s of %s value>", x.Name(), x.recv.Type()) 1177*4947cdc7SCole Faust } else { 1178*4947cdc7SCole Faust fmt.Fprintf(out, "<built-in function %s>", x.Name()) 1179*4947cdc7SCole Faust } 1180*4947cdc7SCole Faust 1181*4947cdc7SCole Faust case *Dict: 1182*4947cdc7SCole Faust out.WriteByte('{') 1183*4947cdc7SCole Faust if pathContains(path, x) { 1184*4947cdc7SCole Faust out.WriteString("...") // dict contains itself 1185*4947cdc7SCole Faust } else { 1186*4947cdc7SCole Faust sep := "" 1187*4947cdc7SCole Faust for _, item := range x.Items() { 1188*4947cdc7SCole Faust k, v := item[0], item[1] 1189*4947cdc7SCole Faust out.WriteString(sep) 1190*4947cdc7SCole Faust writeValue(out, k, path) 1191*4947cdc7SCole Faust out.WriteString(": ") 1192*4947cdc7SCole Faust writeValue(out, v, append(path, x)) // cycle check 1193*4947cdc7SCole Faust sep = ", " 1194*4947cdc7SCole Faust } 1195*4947cdc7SCole Faust } 1196*4947cdc7SCole Faust out.WriteByte('}') 1197*4947cdc7SCole Faust 1198*4947cdc7SCole Faust case *Set: 1199*4947cdc7SCole Faust out.WriteString("set([") 1200*4947cdc7SCole Faust for i, elem := range x.elems() { 1201*4947cdc7SCole Faust if i > 0 { 1202*4947cdc7SCole Faust out.WriteString(", ") 1203*4947cdc7SCole Faust } 1204*4947cdc7SCole Faust writeValue(out, elem, path) 1205*4947cdc7SCole Faust } 1206*4947cdc7SCole Faust out.WriteString("])") 1207*4947cdc7SCole Faust 1208*4947cdc7SCole Faust default: 1209*4947cdc7SCole Faust out.WriteString(x.String()) 1210*4947cdc7SCole Faust } 1211*4947cdc7SCole Faust} 1212*4947cdc7SCole Faust 1213*4947cdc7SCole Faustfunc pathContains(path []Value, x Value) bool { 1214*4947cdc7SCole Faust for _, y := range path { 1215*4947cdc7SCole Faust if x == y { 1216*4947cdc7SCole Faust return true 1217*4947cdc7SCole Faust } 1218*4947cdc7SCole Faust } 1219*4947cdc7SCole Faust return false 1220*4947cdc7SCole Faust} 1221*4947cdc7SCole Faust 1222*4947cdc7SCole Faustconst maxdepth = 10 1223*4947cdc7SCole Faust 1224*4947cdc7SCole Faust// Equal reports whether two Starlark values are equal. 1225*4947cdc7SCole Faustfunc Equal(x, y Value) (bool, error) { 1226*4947cdc7SCole Faust if x, ok := x.(String); ok { 1227*4947cdc7SCole Faust return x == y, nil // fast path for an important special case 1228*4947cdc7SCole Faust } 1229*4947cdc7SCole Faust return EqualDepth(x, y, maxdepth) 1230*4947cdc7SCole Faust} 1231*4947cdc7SCole Faust 1232*4947cdc7SCole Faust// EqualDepth reports whether two Starlark values are equal. 1233*4947cdc7SCole Faust// 1234*4947cdc7SCole Faust// Recursive comparisons by implementations of Value.CompareSameType 1235*4947cdc7SCole Faust// should use EqualDepth to prevent infinite recursion. 1236*4947cdc7SCole Faustfunc EqualDepth(x, y Value, depth int) (bool, error) { 1237*4947cdc7SCole Faust return CompareDepth(syntax.EQL, x, y, depth) 1238*4947cdc7SCole Faust} 1239*4947cdc7SCole Faust 1240*4947cdc7SCole Faust// Compare compares two Starlark values. 1241*4947cdc7SCole Faust// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE. 1242*4947cdc7SCole Faust// Compare returns an error if an ordered comparison was 1243*4947cdc7SCole Faust// requested for a type that does not support it. 1244*4947cdc7SCole Faust// 1245*4947cdc7SCole Faust// Recursive comparisons by implementations of Value.CompareSameType 1246*4947cdc7SCole Faust// should use CompareDepth to prevent infinite recursion. 1247*4947cdc7SCole Faustfunc Compare(op syntax.Token, x, y Value) (bool, error) { 1248*4947cdc7SCole Faust return CompareDepth(op, x, y, maxdepth) 1249*4947cdc7SCole Faust} 1250*4947cdc7SCole Faust 1251*4947cdc7SCole Faust// CompareDepth compares two Starlark values. 1252*4947cdc7SCole Faust// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE. 1253*4947cdc7SCole Faust// CompareDepth returns an error if an ordered comparison was 1254*4947cdc7SCole Faust// requested for a pair of values that do not support it. 1255*4947cdc7SCole Faust// 1256*4947cdc7SCole Faust// The depth parameter limits the maximum depth of recursion 1257*4947cdc7SCole Faust// in cyclic data structures. 1258*4947cdc7SCole Faustfunc CompareDepth(op syntax.Token, x, y Value, depth int) (bool, error) { 1259*4947cdc7SCole Faust if depth < 1 { 1260*4947cdc7SCole Faust return false, fmt.Errorf("comparison exceeded maximum recursion depth") 1261*4947cdc7SCole Faust } 1262*4947cdc7SCole Faust if sameType(x, y) { 1263*4947cdc7SCole Faust if xcomp, ok := x.(Comparable); ok { 1264*4947cdc7SCole Faust return xcomp.CompareSameType(op, y, depth) 1265*4947cdc7SCole Faust } 1266*4947cdc7SCole Faust 1267*4947cdc7SCole Faust // use identity comparison 1268*4947cdc7SCole Faust switch op { 1269*4947cdc7SCole Faust case syntax.EQL: 1270*4947cdc7SCole Faust return x == y, nil 1271*4947cdc7SCole Faust case syntax.NEQ: 1272*4947cdc7SCole Faust return x != y, nil 1273*4947cdc7SCole Faust } 1274*4947cdc7SCole Faust return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) 1275*4947cdc7SCole Faust } 1276*4947cdc7SCole Faust 1277*4947cdc7SCole Faust // different types 1278*4947cdc7SCole Faust 1279*4947cdc7SCole Faust // int/float ordered comparisons 1280*4947cdc7SCole Faust switch x := x.(type) { 1281*4947cdc7SCole Faust case Int: 1282*4947cdc7SCole Faust if y, ok := y.(Float); ok { 1283*4947cdc7SCole Faust var cmp int 1284*4947cdc7SCole Faust if y != y { 1285*4947cdc7SCole Faust cmp = -1 // y is NaN 1286*4947cdc7SCole Faust } else if !math.IsInf(float64(y), 0) { 1287*4947cdc7SCole Faust cmp = x.rational().Cmp(y.rational()) // y is finite 1288*4947cdc7SCole Faust } else if y > 0 { 1289*4947cdc7SCole Faust cmp = -1 // y is +Inf 1290*4947cdc7SCole Faust } else { 1291*4947cdc7SCole Faust cmp = +1 // y is -Inf 1292*4947cdc7SCole Faust } 1293*4947cdc7SCole Faust return threeway(op, cmp), nil 1294*4947cdc7SCole Faust } 1295*4947cdc7SCole Faust case Float: 1296*4947cdc7SCole Faust if y, ok := y.(Int); ok { 1297*4947cdc7SCole Faust var cmp int 1298*4947cdc7SCole Faust if x != x { 1299*4947cdc7SCole Faust cmp = +1 // x is NaN 1300*4947cdc7SCole Faust } else if !math.IsInf(float64(x), 0) { 1301*4947cdc7SCole Faust cmp = x.rational().Cmp(y.rational()) // x is finite 1302*4947cdc7SCole Faust } else if x > 0 { 1303*4947cdc7SCole Faust cmp = +1 // x is +Inf 1304*4947cdc7SCole Faust } else { 1305*4947cdc7SCole Faust cmp = -1 // x is -Inf 1306*4947cdc7SCole Faust } 1307*4947cdc7SCole Faust return threeway(op, cmp), nil 1308*4947cdc7SCole Faust } 1309*4947cdc7SCole Faust } 1310*4947cdc7SCole Faust 1311*4947cdc7SCole Faust // All other values of different types compare unequal. 1312*4947cdc7SCole Faust switch op { 1313*4947cdc7SCole Faust case syntax.EQL: 1314*4947cdc7SCole Faust return false, nil 1315*4947cdc7SCole Faust case syntax.NEQ: 1316*4947cdc7SCole Faust return true, nil 1317*4947cdc7SCole Faust } 1318*4947cdc7SCole Faust return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) 1319*4947cdc7SCole Faust} 1320*4947cdc7SCole Faust 1321*4947cdc7SCole Faustfunc sameType(x, y Value) bool { 1322*4947cdc7SCole Faust return reflect.TypeOf(x) == reflect.TypeOf(y) || x.Type() == y.Type() 1323*4947cdc7SCole Faust} 1324*4947cdc7SCole Faust 1325*4947cdc7SCole Faust// threeway interprets a three-way comparison value cmp (-1, 0, +1) 1326*4947cdc7SCole Faust// as a boolean comparison (e.g. x < y). 1327*4947cdc7SCole Faustfunc threeway(op syntax.Token, cmp int) bool { 1328*4947cdc7SCole Faust switch op { 1329*4947cdc7SCole Faust case syntax.EQL: 1330*4947cdc7SCole Faust return cmp == 0 1331*4947cdc7SCole Faust case syntax.NEQ: 1332*4947cdc7SCole Faust return cmp != 0 1333*4947cdc7SCole Faust case syntax.LE: 1334*4947cdc7SCole Faust return cmp <= 0 1335*4947cdc7SCole Faust case syntax.LT: 1336*4947cdc7SCole Faust return cmp < 0 1337*4947cdc7SCole Faust case syntax.GE: 1338*4947cdc7SCole Faust return cmp >= 0 1339*4947cdc7SCole Faust case syntax.GT: 1340*4947cdc7SCole Faust return cmp > 0 1341*4947cdc7SCole Faust } 1342*4947cdc7SCole Faust panic(op) 1343*4947cdc7SCole Faust} 1344*4947cdc7SCole Faust 1345*4947cdc7SCole Faustfunc b2i(b bool) int { 1346*4947cdc7SCole Faust if b { 1347*4947cdc7SCole Faust return 1 1348*4947cdc7SCole Faust } else { 1349*4947cdc7SCole Faust return 0 1350*4947cdc7SCole Faust } 1351*4947cdc7SCole Faust} 1352*4947cdc7SCole Faust 1353*4947cdc7SCole Faust// Len returns the length of a string or sequence value, 1354*4947cdc7SCole Faust// and -1 for all others. 1355*4947cdc7SCole Faust// 1356*4947cdc7SCole Faust// Warning: Len(x) >= 0 does not imply Iterate(x) != nil. 1357*4947cdc7SCole Faust// A string has a known length but is not directly iterable. 1358*4947cdc7SCole Faustfunc Len(x Value) int { 1359*4947cdc7SCole Faust switch x := x.(type) { 1360*4947cdc7SCole Faust case String: 1361*4947cdc7SCole Faust return x.Len() 1362*4947cdc7SCole Faust case Indexable: 1363*4947cdc7SCole Faust return x.Len() 1364*4947cdc7SCole Faust case Sequence: 1365*4947cdc7SCole Faust return x.Len() 1366*4947cdc7SCole Faust } 1367*4947cdc7SCole Faust return -1 1368*4947cdc7SCole Faust} 1369*4947cdc7SCole Faust 1370*4947cdc7SCole Faust// Iterate return a new iterator for the value if iterable, nil otherwise. 1371*4947cdc7SCole Faust// If the result is non-nil, the caller must call Done when finished with it. 1372*4947cdc7SCole Faust// 1373*4947cdc7SCole Faust// Warning: Iterate(x) != nil does not imply Len(x) >= 0. 1374*4947cdc7SCole Faust// Some iterables may have unknown length. 1375*4947cdc7SCole Faustfunc Iterate(x Value) Iterator { 1376*4947cdc7SCole Faust if x, ok := x.(Iterable); ok { 1377*4947cdc7SCole Faust return x.Iterate() 1378*4947cdc7SCole Faust } 1379*4947cdc7SCole Faust return nil 1380*4947cdc7SCole Faust} 1381*4947cdc7SCole Faust 1382*4947cdc7SCole Faust// Bytes is the type of a Starlark binary string. 1383*4947cdc7SCole Faust// 1384*4947cdc7SCole Faust// A Bytes encapsulates an immutable sequence of bytes. 1385*4947cdc7SCole Faust// It is comparable, indexable, and sliceable, but not direcly iterable; 1386*4947cdc7SCole Faust// use bytes.elems() for an iterable view. 1387*4947cdc7SCole Faust// 1388*4947cdc7SCole Faust// In this Go implementation, the elements of 'string' and 'bytes' are 1389*4947cdc7SCole Faust// both bytes, but in other implementations, notably Java, the elements 1390*4947cdc7SCole Faust// of a 'string' are UTF-16 codes (Java chars). The spec abstracts text 1391*4947cdc7SCole Faust// strings as sequences of UTF-k codes that encode Unicode code points, 1392*4947cdc7SCole Faust// and operations that convert from text to binary incur UTF-k-to-UTF-8 1393*4947cdc7SCole Faust// transcoding; conversely, conversion from binary to text incurs 1394*4947cdc7SCole Faust// UTF-8-to-UTF-k transcoding. Because k=8 for Go, these operations 1395*4947cdc7SCole Faust// are the identity function, at least for valid encodings of text. 1396*4947cdc7SCole Fausttype Bytes string 1397*4947cdc7SCole Faust 1398*4947cdc7SCole Faustvar ( 1399*4947cdc7SCole Faust _ Comparable = Bytes("") 1400*4947cdc7SCole Faust _ Sliceable = Bytes("") 1401*4947cdc7SCole Faust _ Indexable = Bytes("") 1402*4947cdc7SCole Faust) 1403*4947cdc7SCole Faust 1404*4947cdc7SCole Faustfunc (b Bytes) String() string { return syntax.Quote(string(b), true) } 1405*4947cdc7SCole Faustfunc (b Bytes) Type() string { return "bytes" } 1406*4947cdc7SCole Faustfunc (b Bytes) Freeze() {} // immutable 1407*4947cdc7SCole Faustfunc (b Bytes) Truth() Bool { return len(b) > 0 } 1408*4947cdc7SCole Faustfunc (b Bytes) Hash() (uint32, error) { return String(b).Hash() } 1409*4947cdc7SCole Faustfunc (b Bytes) Len() int { return len(b) } 1410*4947cdc7SCole Faustfunc (b Bytes) Index(i int) Value { return b[i : i+1] } 1411*4947cdc7SCole Faust 1412*4947cdc7SCole Faustfunc (b Bytes) Attr(name string) (Value, error) { return builtinAttr(b, name, bytesMethods) } 1413*4947cdc7SCole Faustfunc (b Bytes) AttrNames() []string { return builtinAttrNames(bytesMethods) } 1414*4947cdc7SCole Faust 1415*4947cdc7SCole Faustfunc (b Bytes) Slice(start, end, step int) Value { 1416*4947cdc7SCole Faust if step == 1 { 1417*4947cdc7SCole Faust return b[start:end] 1418*4947cdc7SCole Faust } 1419*4947cdc7SCole Faust 1420*4947cdc7SCole Faust sign := signum(step) 1421*4947cdc7SCole Faust var str []byte 1422*4947cdc7SCole Faust for i := start; signum(end-i) == sign; i += step { 1423*4947cdc7SCole Faust str = append(str, b[i]) 1424*4947cdc7SCole Faust } 1425*4947cdc7SCole Faust return Bytes(str) 1426*4947cdc7SCole Faust} 1427*4947cdc7SCole Faust 1428*4947cdc7SCole Faustfunc (x Bytes) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { 1429*4947cdc7SCole Faust y := y_.(Bytes) 1430*4947cdc7SCole Faust return threeway(op, strings.Compare(string(x), string(y))), nil 1431*4947cdc7SCole Faust} 1432