12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199 |
- 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))
- reflectTypeCtor = reflect.TypeOf((func(ConstructorCall) *Object)(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 class function, returns func(ConstructorCall) *Object. See the note about exceptions below.
- //
- // 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)
- }
- }
|