package goja import ( "fmt" "hash/maphash" "math" "math/big" "reflect" "strconv" "unsafe" "github.com/dop251/goja/ftoa" "github.com/dop251/goja/unistring" ) var ( // Not goroutine-safe, do not use for anything other than package level init pkgHasher maphash.Hash hashFalse = randomHash() hashTrue = randomHash() hashNull = randomHash() hashUndef = randomHash() ) // Not goroutine-safe, do not use for anything other than package level init func randomHash() uint64 { pkgHasher.WriteByte(0) return pkgHasher.Sum64() } var ( valueFalse Value = valueBool(false) valueTrue Value = valueBool(true) _null Value = valueNull{} _NaN Value = valueFloat(math.NaN()) _positiveInf Value = valueFloat(math.Inf(+1)) _negativeInf Value = valueFloat(math.Inf(-1)) _positiveZero Value = valueInt(0) negativeZero = math.Float64frombits(0 | (1 << 63)) _negativeZero Value = valueFloat(negativeZero) _epsilon = valueFloat(2.2204460492503130808472633361816e-16) _undefined Value = valueUndefined{} ) var ( reflectTypeInt = reflect.TypeOf(int64(0)) reflectTypeBool = reflect.TypeOf(false) reflectTypeNil = reflect.TypeOf(nil) reflectTypeFloat = reflect.TypeOf(float64(0)) reflectTypeMap = reflect.TypeOf(map[string]interface{}{}) reflectTypeArray = reflect.TypeOf([]interface{}{}) reflectTypeArrayPtr = reflect.TypeOf((*[]interface{})(nil)) reflectTypeString = reflect.TypeOf("") reflectTypeFunc = reflect.TypeOf((func(FunctionCall) Value)(nil)) reflectTypeError = reflect.TypeOf((*error)(nil)).Elem() ) var intCache [256]Value // Value represents an ECMAScript value. // // Export returns a "plain" Go value which type depends on the type of the Value. // // For integer numbers it's int64. // // For any other numbers (including Infinities, NaN and negative zero) it's float64. // // For string it's a string. Note that unicode strings are converted into UTF-8 with invalid code points replaced with utf8.RuneError. // // For boolean it's bool. // // For null and undefined it's nil. // // For Object it depends on the Object type, see Object.Export() for more details. type Value interface { ToInteger() int64 toString() String string() unistring.String ToString() Value String() string ToFloat() float64 ToNumber() Value ToBoolean() bool ToObject(*Runtime) *Object SameAs(Value) bool Equals(Value) bool StrictEquals(Value) bool Export() interface{} ExportType() reflect.Type baseObject(r *Runtime) *Object hash(hasher *maphash.Hash) uint64 } type valueContainer interface { toValue(*Runtime) Value } type typeError string type rangeError string type referenceError string type syntaxError string type valueInt int64 type valueFloat float64 type valueBool bool type valueNull struct{} type valueUndefined struct { valueNull } // *Symbol is a Value containing ECMAScript Symbol primitive. Symbols must only be created // using NewSymbol(). Zero values and copying of values (i.e. *s1 = *s2) are not permitted. // Well-known Symbols can be accessed using Sym* package variables (SymIterator, etc...) // Symbols can be shared by multiple Runtimes. type Symbol struct { h uintptr desc String } type valueUnresolved struct { r *Runtime ref unistring.String } type memberUnresolved struct { valueUnresolved } type valueProperty struct { value Value writable bool configurable bool enumerable bool accessor bool getterFunc *Object setterFunc *Object } var ( errAccessBeforeInit = referenceError("Cannot access a variable before initialization") errAssignToConst = typeError("Assignment to constant variable.") errMixBigIntType = typeError("Cannot mix BigInt and other types, use explicit conversions") ) func propGetter(o Value, v Value, r *Runtime) *Object { if v == _undefined { return nil } if obj, ok := v.(*Object); ok { if _, ok := obj.self.assertCallable(); ok { return obj } } r.typeErrorResult(true, "Getter must be a function: %s", v.toString()) return nil } func propSetter(o Value, v Value, r *Runtime) *Object { if v == _undefined { return nil } if obj, ok := v.(*Object); ok { if _, ok := obj.self.assertCallable(); ok { return obj } } r.typeErrorResult(true, "Setter must be a function: %s", v.toString()) return nil } func fToStr(num float64, mode ftoa.FToStrMode, prec int) string { var buf1 [128]byte return string(ftoa.FToStr(num, mode, prec, buf1[:0])) } func (i valueInt) ToInteger() int64 { return int64(i) } func (i valueInt) toString() String { return asciiString(i.String()) } func (i valueInt) string() unistring.String { return unistring.String(i.String()) } func (i valueInt) ToString() Value { return i } func (i valueInt) String() string { return strconv.FormatInt(int64(i), 10) } func (i valueInt) ToFloat() float64 { return float64(i) } func (i valueInt) ToBoolean() bool { return i != 0 } func (i valueInt) ToObject(r *Runtime) *Object { return r.newPrimitiveObject(i, r.getNumberPrototype(), classNumber) } func (i valueInt) ToNumber() Value { return i } func (i valueInt) SameAs(other Value) bool { return i == other } func (i valueInt) Equals(other Value) bool { switch o := other.(type) { case valueInt: return i == o case *valueBigInt: return (*big.Int)(o).Cmp(big.NewInt(int64(i))) == 0 case valueFloat: return float64(i) == float64(o) case String: return o.ToNumber().Equals(i) case valueBool: return int64(i) == o.ToInteger() case *Object: return i.Equals(o.toPrimitive()) } return false } func (i valueInt) StrictEquals(other Value) bool { switch o := other.(type) { case valueInt: return i == o case valueFloat: return float64(i) == float64(o) } return false } func (i valueInt) baseObject(r *Runtime) *Object { return r.getNumberPrototype() } func (i valueInt) Export() interface{} { return int64(i) } func (i valueInt) ExportType() reflect.Type { return reflectTypeInt } func (i valueInt) hash(*maphash.Hash) uint64 { return uint64(i) } func (b valueBool) ToInteger() int64 { if b { return 1 } return 0 } func (b valueBool) toString() String { if b { return stringTrue } return stringFalse } func (b valueBool) ToString() Value { return b } func (b valueBool) String() string { if b { return "true" } return "false" } func (b valueBool) string() unistring.String { return unistring.String(b.String()) } func (b valueBool) ToFloat() float64 { if b { return 1.0 } return 0 } func (b valueBool) ToBoolean() bool { return bool(b) } func (b valueBool) ToObject(r *Runtime) *Object { return r.newPrimitiveObject(b, r.getBooleanPrototype(), "Boolean") } func (b valueBool) ToNumber() Value { if b { return valueInt(1) } return valueInt(0) } func (b valueBool) SameAs(other Value) bool { if other, ok := other.(valueBool); ok { return b == other } return false } func (b valueBool) Equals(other Value) bool { if o, ok := other.(valueBool); ok { return b == o } if b { return other.Equals(intToValue(1)) } else { return other.Equals(intToValue(0)) } } func (b valueBool) StrictEquals(other Value) bool { if other, ok := other.(valueBool); ok { return b == other } return false } func (b valueBool) baseObject(r *Runtime) *Object { return r.getBooleanPrototype() } func (b valueBool) Export() interface{} { return bool(b) } func (b valueBool) ExportType() reflect.Type { return reflectTypeBool } func (b valueBool) hash(*maphash.Hash) uint64 { if b { return hashTrue } return hashFalse } func (n valueNull) ToInteger() int64 { return 0 } func (n valueNull) toString() String { return stringNull } func (n valueNull) string() unistring.String { return stringNull.string() } func (n valueNull) ToString() Value { return n } func (n valueNull) String() string { return "null" } func (u valueUndefined) toString() String { return stringUndefined } func (u valueUndefined) ToString() Value { return u } func (u valueUndefined) String() string { return "undefined" } func (u valueUndefined) string() unistring.String { return "undefined" } func (u valueUndefined) ToNumber() Value { return _NaN } func (u valueUndefined) SameAs(other Value) bool { _, same := other.(valueUndefined) return same } func (u valueUndefined) StrictEquals(other Value) bool { _, same := other.(valueUndefined) return same } func (u valueUndefined) ToFloat() float64 { return math.NaN() } func (u valueUndefined) hash(*maphash.Hash) uint64 { return hashUndef } func (n valueNull) ToFloat() float64 { return 0 } func (n valueNull) ToBoolean() bool { return false } func (n valueNull) ToObject(r *Runtime) *Object { r.typeErrorResult(true, "Cannot convert undefined or null to object") return nil //return r.newObject() } func (n valueNull) ToNumber() Value { return intToValue(0) } func (n valueNull) SameAs(other Value) bool { _, same := other.(valueNull) return same } func (n valueNull) Equals(other Value) bool { switch other.(type) { case valueUndefined, valueNull: return true } return false } func (n valueNull) StrictEquals(other Value) bool { _, same := other.(valueNull) return same } func (n valueNull) baseObject(*Runtime) *Object { return nil } func (n valueNull) Export() interface{} { return nil } func (n valueNull) ExportType() reflect.Type { return reflectTypeNil } func (n valueNull) hash(*maphash.Hash) uint64 { return hashNull } func (p *valueProperty) ToInteger() int64 { return 0 } func (p *valueProperty) toString() String { return stringEmpty } func (p *valueProperty) string() unistring.String { return "" } func (p *valueProperty) ToString() Value { return _undefined } func (p *valueProperty) String() string { return "" } func (p *valueProperty) ToFloat() float64 { return math.NaN() } func (p *valueProperty) ToBoolean() bool { return false } func (p *valueProperty) ToObject(*Runtime) *Object { return nil } func (p *valueProperty) ToNumber() Value { return nil } func (p *valueProperty) isWritable() bool { return p.writable || p.setterFunc != nil } func (p *valueProperty) get(this Value) Value { if p.getterFunc == nil { if p.value != nil { return p.value } return _undefined } call, _ := p.getterFunc.self.assertCallable() return call(FunctionCall{ This: this, }) } func (p *valueProperty) set(this, v Value) { if p.setterFunc == nil { p.value = v return } call, _ := p.setterFunc.self.assertCallable() call(FunctionCall{ This: this, Arguments: []Value{v}, }) } func (p *valueProperty) SameAs(other Value) bool { if otherProp, ok := other.(*valueProperty); ok { return p == otherProp } return false } func (p *valueProperty) Equals(Value) bool { return false } func (p *valueProperty) StrictEquals(Value) bool { return false } func (p *valueProperty) baseObject(r *Runtime) *Object { r.typeErrorResult(true, "BUG: baseObject() is called on valueProperty") // TODO error message return nil } func (p *valueProperty) Export() interface{} { panic("Cannot export valueProperty") } func (p *valueProperty) ExportType() reflect.Type { panic("Cannot export valueProperty") } func (p *valueProperty) hash(*maphash.Hash) uint64 { panic("valueProperty should never be used in maps or sets") } func floatToIntClip(n float64) int64 { switch { case math.IsNaN(n): return 0 case n >= math.MaxInt64: return math.MaxInt64 case n <= math.MinInt64: return math.MinInt64 } return int64(n) } func (f valueFloat) ToInteger() int64 { return floatToIntClip(float64(f)) } func (f valueFloat) toString() String { return asciiString(f.String()) } func (f valueFloat) string() unistring.String { return unistring.String(f.String()) } func (f valueFloat) ToString() Value { return f } func (f valueFloat) String() string { return fToStr(float64(f), ftoa.ModeStandard, 0) } func (f valueFloat) ToFloat() float64 { return float64(f) } func (f valueFloat) ToBoolean() bool { return float64(f) != 0.0 && !math.IsNaN(float64(f)) } func (f valueFloat) ToObject(r *Runtime) *Object { return r.newPrimitiveObject(f, r.getNumberPrototype(), "Number") } func (f valueFloat) ToNumber() Value { return f } func (f valueFloat) SameAs(other Value) bool { switch o := other.(type) { case valueFloat: this := float64(f) o1 := float64(o) if math.IsNaN(this) && math.IsNaN(o1) { return true } else { ret := this == o1 if ret && this == 0 { ret = math.Signbit(this) == math.Signbit(o1) } return ret } case valueInt: this := float64(f) ret := this == float64(o) if ret && this == 0 { ret = !math.Signbit(this) } return ret } return false } func (f valueFloat) Equals(other Value) bool { switch o := other.(type) { case valueFloat: return f == o case valueInt: return float64(f) == float64(o) case *valueBigInt: if IsInfinity(f) || math.IsNaN(float64(f)) { return false } if f := big.NewFloat(float64(f)); f.IsInt() { i, _ := f.Int(nil) return (*big.Int)(o).Cmp(i) == 0 } return false case String, valueBool: return float64(f) == o.ToFloat() case *Object: return f.Equals(o.toPrimitive()) } return false } func (f valueFloat) StrictEquals(other Value) bool { switch o := other.(type) { case valueFloat: return f == o case valueInt: return float64(f) == float64(o) } return false } func (f valueFloat) baseObject(r *Runtime) *Object { return r.getNumberPrototype() } func (f valueFloat) Export() interface{} { return float64(f) } func (f valueFloat) ExportType() reflect.Type { return reflectTypeFloat } func (f valueFloat) hash(*maphash.Hash) uint64 { if f == _negativeZero { return 0 } return math.Float64bits(float64(f)) } func (o *Object) ToInteger() int64 { return o.toPrimitiveNumber().ToNumber().ToInteger() } func (o *Object) toString() String { return o.toPrimitiveString().toString() } func (o *Object) string() unistring.String { return o.toPrimitiveString().string() } func (o *Object) ToString() Value { return o.toPrimitiveString().ToString() } func (o *Object) String() string { return o.toPrimitiveString().String() } func (o *Object) ToFloat() float64 { return o.toPrimitiveNumber().ToFloat() } func (o *Object) ToBoolean() bool { return true } func (o *Object) ToObject(*Runtime) *Object { return o } func (o *Object) ToNumber() Value { return o.toPrimitiveNumber().ToNumber() } func (o *Object) SameAs(other Value) bool { return o.StrictEquals(other) } func (o *Object) Equals(other Value) bool { if other, ok := other.(*Object); ok { return o == other || o.self.equal(other.self) } switch o1 := other.(type) { case valueInt, valueFloat, *valueBigInt, String, *Symbol: return o.toPrimitive().Equals(other) case valueBool: return o.Equals(o1.ToNumber()) } return false } func (o *Object) StrictEquals(other Value) bool { if other, ok := other.(*Object); ok { return o == other || o != nil && other != nil && o.self.equal(other.self) } return false } func (o *Object) baseObject(*Runtime) *Object { return o } // Export the Object to a plain Go type. // If the Object is a wrapped Go value (created using ToValue()) returns the original value. // // If the Object is a function, returns func(FunctionCall) Value. Note that exceptions thrown inside the function // result in panics, which can also leave the Runtime in an unusable state. Therefore, these values should only // be used inside another ES function implemented in Go. For calling a function from Go, use AssertFunction() or // Runtime.ExportTo() as described in the README. // // For a Map, returns the list of entries as [][2]interface{}. // // For a Set, returns the list of elements as []interface{}. // // For a Proxy, returns Proxy. // // For a Promise, returns Promise. // // For a DynamicObject or a DynamicArray, returns the underlying handler. // // For typed arrays it returns a slice of the corresponding type backed by the original data (i.e. it does not copy). // // For an untyped array, returns its items exported into a newly created []interface{}. // // In all other cases returns own enumerable non-symbol properties as map[string]interface{}. // // This method will panic with an *Exception if a JavaScript exception is thrown in the process. Use Runtime.Try to catch these. func (o *Object) Export() interface{} { return o.self.export(&objectExportCtx{}) } // ExportType returns the type of the value that is returned by Export(). func (o *Object) ExportType() reflect.Type { return o.self.exportType() } func (o *Object) hash(*maphash.Hash) uint64 { return o.getId() } // Get an object's property by name. // This method will panic with an *Exception if a JavaScript exception is thrown in the process. Use Runtime.Try to catch these. func (o *Object) Get(name string) Value { return o.self.getStr(unistring.NewFromString(name), nil) } // GetSymbol returns the value of a symbol property. Use one of the Sym* values for well-known // symbols (such as SymIterator, SymToStringTag, etc...). // This method will panic with an *Exception if a JavaScript exception is thrown in the process. Use Runtime.Try to catch these. func (o *Object) GetSymbol(sym *Symbol) Value { return o.self.getSym(sym, nil) } // Keys returns a list of Object's enumerable keys. // This method will panic with an *Exception if a JavaScript exception is thrown in the process. Use Runtime.Try to catch these. func (o *Object) Keys() (keys []string) { iter := &enumerableIter{ o: o, wrapped: o.self.iterateStringKeys(), } for item, next := iter.next(); next != nil; item, next = next() { keys = append(keys, item.name.String()) } return } // GetOwnPropertyNames returns a list of all own string properties of the Object, similar to Object.getOwnPropertyNames() // This method will panic with an *Exception if a JavaScript exception is thrown in the process. Use Runtime.Try to catch these. func (o *Object) GetOwnPropertyNames() (keys []string) { for item, next := o.self.iterateStringKeys()(); next != nil; item, next = next() { keys = append(keys, item.name.String()) } return } // Symbols returns a list of Object's enumerable symbol properties. // This method will panic with an *Exception if a JavaScript exception is thrown in the process. Use Runtime.Try to catch these. func (o *Object) Symbols() []*Symbol { symbols := o.self.symbols(false, nil) ret := make([]*Symbol, len(symbols)) for i, sym := range symbols { ret[i], _ = sym.(*Symbol) } return ret } // DefineDataProperty is a Go equivalent of Object.defineProperty(o, name, {value: value, writable: writable, // configurable: configurable, enumerable: enumerable}) func (o *Object) DefineDataProperty(name string, value Value, writable, configurable, enumerable Flag) error { return o.runtime.try(func() { o.self.defineOwnPropertyStr(unistring.NewFromString(name), PropertyDescriptor{ Value: value, Writable: writable, Configurable: configurable, Enumerable: enumerable, }, true) }) } // DefineAccessorProperty is a Go equivalent of Object.defineProperty(o, name, {get: getter, set: setter, // configurable: configurable, enumerable: enumerable}) func (o *Object) DefineAccessorProperty(name string, getter, setter Value, configurable, enumerable Flag) error { return o.runtime.try(func() { o.self.defineOwnPropertyStr(unistring.NewFromString(name), PropertyDescriptor{ Getter: getter, Setter: setter, Configurable: configurable, Enumerable: enumerable, }, true) }) } // DefineDataPropertySymbol is a Go equivalent of Object.defineProperty(o, name, {value: value, writable: writable, // configurable: configurable, enumerable: enumerable}) func (o *Object) DefineDataPropertySymbol(name *Symbol, value Value, writable, configurable, enumerable Flag) error { return o.runtime.try(func() { o.self.defineOwnPropertySym(name, PropertyDescriptor{ Value: value, Writable: writable, Configurable: configurable, Enumerable: enumerable, }, true) }) } // DefineAccessorPropertySymbol is a Go equivalent of Object.defineProperty(o, name, {get: getter, set: setter, // configurable: configurable, enumerable: enumerable}) func (o *Object) DefineAccessorPropertySymbol(name *Symbol, getter, setter Value, configurable, enumerable Flag) error { return o.runtime.try(func() { o.self.defineOwnPropertySym(name, PropertyDescriptor{ Getter: getter, Setter: setter, Configurable: configurable, Enumerable: enumerable, }, true) }) } func (o *Object) Set(name string, value interface{}) error { return o.runtime.try(func() { o.self.setOwnStr(unistring.NewFromString(name), o.runtime.ToValue(value), true) }) } func (o *Object) SetSymbol(name *Symbol, value interface{}) error { return o.runtime.try(func() { o.self.setOwnSym(name, o.runtime.ToValue(value), true) }) } func (o *Object) Delete(name string) error { return o.runtime.try(func() { o.self.deleteStr(unistring.NewFromString(name), true) }) } func (o *Object) DeleteSymbol(name *Symbol) error { return o.runtime.try(func() { o.self.deleteSym(name, true) }) } // Prototype returns the Object's prototype, same as Object.getPrototypeOf(). If the prototype is null // returns nil. func (o *Object) Prototype() *Object { return o.self.proto() } // SetPrototype sets the Object's prototype, same as Object.setPrototypeOf(). Setting proto to nil // is an equivalent of Object.setPrototypeOf(null). func (o *Object) SetPrototype(proto *Object) error { return o.runtime.try(func() { o.self.setProto(proto, true) }) } // MarshalJSON returns JSON representation of the Object. It is equivalent to JSON.stringify(o). // Note, this implements json.Marshaler so that json.Marshal() can be used without the need to Export(). func (o *Object) MarshalJSON() ([]byte, error) { ctx := _builtinJSON_stringifyContext{ r: o.runtime, } ex := o.runtime.vm.try(func() { if !ctx.do(o) { ctx.buf.WriteString("null") } }) if ex != nil { return nil, ex } return ctx.buf.Bytes(), nil } // UnmarshalJSON implements the json.Unmarshaler interface. It is added to compliment MarshalJSON, because // some alternative JSON encoders refuse to use MarshalJSON unless UnmarshalJSON is also present. // It is a no-op and always returns nil. func (o *Object) UnmarshalJSON([]byte) error { return nil } // ClassName returns the class name func (o *Object) ClassName() string { return o.self.className() } func (o valueUnresolved) throw() { o.r.throwReferenceError(o.ref) } func (o valueUnresolved) ToInteger() int64 { o.throw() return 0 } func (o valueUnresolved) toString() String { o.throw() return nil } func (o valueUnresolved) string() unistring.String { o.throw() return "" } func (o valueUnresolved) ToString() Value { o.throw() return nil } func (o valueUnresolved) String() string { o.throw() return "" } func (o valueUnresolved) ToFloat() float64 { o.throw() return 0 } func (o valueUnresolved) ToBoolean() bool { o.throw() return false } func (o valueUnresolved) ToObject(*Runtime) *Object { o.throw() return nil } func (o valueUnresolved) ToNumber() Value { o.throw() return nil } func (o valueUnresolved) SameAs(Value) bool { o.throw() return false } func (o valueUnresolved) Equals(Value) bool { o.throw() return false } func (o valueUnresolved) StrictEquals(Value) bool { o.throw() return false } func (o valueUnresolved) baseObject(*Runtime) *Object { o.throw() return nil } func (o valueUnresolved) Export() interface{} { o.throw() return nil } func (o valueUnresolved) ExportType() reflect.Type { o.throw() return nil } func (o valueUnresolved) hash(*maphash.Hash) uint64 { o.throw() return 0 } func (s *Symbol) ToInteger() int64 { panic(typeError("Cannot convert a Symbol value to a number")) } func (s *Symbol) toString() String { panic(typeError("Cannot convert a Symbol value to a string")) } func (s *Symbol) ToString() Value { return s } func (s *Symbol) String() string { if s.desc != nil { return s.desc.String() } return "" } func (s *Symbol) string() unistring.String { if s.desc != nil { return s.desc.string() } return "" } func (s *Symbol) ToFloat() float64 { panic(typeError("Cannot convert a Symbol value to a number")) } func (s *Symbol) ToNumber() Value { panic(typeError("Cannot convert a Symbol value to a number")) } func (s *Symbol) ToBoolean() bool { return true } func (s *Symbol) ToObject(r *Runtime) *Object { return s.baseObject(r) } func (s *Symbol) SameAs(other Value) bool { if s1, ok := other.(*Symbol); ok { return s == s1 } return false } func (s *Symbol) Equals(o Value) bool { switch o := o.(type) { case *Object: return s.Equals(o.toPrimitive()) } return s.SameAs(o) } func (s *Symbol) StrictEquals(o Value) bool { return s.SameAs(o) } func (s *Symbol) Export() interface{} { return s.String() } func (s *Symbol) ExportType() reflect.Type { return reflectTypeString } func (s *Symbol) baseObject(r *Runtime) *Object { return r.newPrimitiveObject(s, r.getSymbolPrototype(), classObject) } func (s *Symbol) hash(*maphash.Hash) uint64 { return uint64(s.h) } func exportValue(v Value, ctx *objectExportCtx) interface{} { if obj, ok := v.(*Object); ok { return obj.self.export(ctx) } return v.Export() } func newSymbol(s String) *Symbol { r := &Symbol{ desc: s, } // This may need to be reconsidered in the future. // Depending on changes in Go's allocation policy and/or introduction of a compacting GC // this may no longer provide sufficient dispersion. The alternative, however, is a globally // synchronised random generator/hasher/sequencer and I don't want to go down that route just yet. r.h = uintptr(unsafe.Pointer(r)) return r } func NewSymbol(s string) *Symbol { return newSymbol(newStringValue(s)) } func (s *Symbol) descriptiveString() String { desc := s.desc if desc == nil { desc = stringEmpty } return asciiString("Symbol(").Concat(desc).Concat(asciiString(")")) } func funcName(prefix string, n Value) String { var b StringBuilder b.WriteString(asciiString(prefix)) if sym, ok := n.(*Symbol); ok { if sym.desc != nil { b.WriteRune('[') b.WriteString(sym.desc) b.WriteRune(']') } } else { b.WriteString(n.toString()) } return b.String() } func newTypeError(args ...interface{}) typeError { msg := "" if len(args) > 0 { f, _ := args[0].(string) msg = fmt.Sprintf(f, args[1:]...) } return typeError(msg) } func typeErrorResult(throw bool, args ...interface{}) { if throw { panic(newTypeError(args...)) } } func init() { for i := 0; i < 256; i++ { intCache[i] = valueInt(i - 256) } }