123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- package goja
- import (
- "fmt"
- "sync"
- )
- func (r *Runtime) builtin_Object(args []Value, newTarget *Object) *Object {
- if newTarget != nil && newTarget != r.getObject() {
- proto := r.getPrototypeFromCtor(newTarget, nil, r.global.ObjectPrototype)
- return r.newBaseObject(proto, classObject).val
- }
- if len(args) > 0 {
- arg := args[0]
- if arg != _undefined && arg != _null {
- return arg.ToObject(r)
- }
- }
- return r.NewObject()
- }
- func (r *Runtime) object_getPrototypeOf(call FunctionCall) Value {
- o := call.Argument(0).ToObject(r)
- p := o.self.proto()
- if p == nil {
- return _null
- }
- return p
- }
- func (r *Runtime) valuePropToDescriptorObject(desc Value) Value {
- if desc == nil {
- return _undefined
- }
- var writable, configurable, enumerable, accessor bool
- var get, set *Object
- var value Value
- if v, ok := desc.(*valueProperty); ok {
- writable = v.writable
- configurable = v.configurable
- enumerable = v.enumerable
- accessor = v.accessor
- value = v.value
- get = v.getterFunc
- set = v.setterFunc
- } else {
- writable = true
- configurable = true
- enumerable = true
- value = desc
- }
- ret := r.NewObject()
- obj := ret.self
- if !accessor {
- obj.setOwnStr("value", value, false)
- obj.setOwnStr("writable", r.toBoolean(writable), false)
- } else {
- if get != nil {
- obj.setOwnStr("get", get, false)
- } else {
- obj.setOwnStr("get", _undefined, false)
- }
- if set != nil {
- obj.setOwnStr("set", set, false)
- } else {
- obj.setOwnStr("set", _undefined, false)
- }
- }
- obj.setOwnStr("enumerable", r.toBoolean(enumerable), false)
- obj.setOwnStr("configurable", r.toBoolean(configurable), false)
- return ret
- }
- func (r *Runtime) object_getOwnPropertyDescriptor(call FunctionCall) Value {
- o := call.Argument(0).ToObject(r)
- propName := toPropertyKey(call.Argument(1))
- return r.valuePropToDescriptorObject(o.getOwnProp(propName))
- }
- func (r *Runtime) object_getOwnPropertyDescriptors(call FunctionCall) Value {
- o := call.Argument(0).ToObject(r)
- result := r.newBaseObject(r.global.ObjectPrototype, classObject).val
- for item, next := o.self.iterateKeys()(); next != nil; item, next = next() {
- var prop Value
- if item.value == nil {
- prop = o.getOwnProp(item.name)
- if prop == nil {
- continue
- }
- } else {
- prop = item.value
- }
- descriptor := r.valuePropToDescriptorObject(prop)
- if descriptor != _undefined {
- createDataPropertyOrThrow(result, item.name, descriptor)
- }
- }
- return result
- }
- func (r *Runtime) object_getOwnPropertyNames(call FunctionCall) Value {
- obj := call.Argument(0).ToObject(r)
- return r.newArrayValues(obj.self.stringKeys(true, nil))
- }
- func (r *Runtime) object_getOwnPropertySymbols(call FunctionCall) Value {
- obj := call.Argument(0).ToObject(r)
- return r.newArrayValues(obj.self.symbols(true, nil))
- }
- func (r *Runtime) toValueProp(v Value) *valueProperty {
- if v == nil || v == _undefined {
- return nil
- }
- obj := r.toObject(v)
- getter := obj.self.getStr("get", nil)
- setter := obj.self.getStr("set", nil)
- writable := obj.self.getStr("writable", nil)
- value := obj.self.getStr("value", nil)
- if (getter != nil || setter != nil) && (value != nil || writable != nil) {
- r.typeErrorResult(true, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute")
- }
- ret := &valueProperty{}
- if writable != nil && writable.ToBoolean() {
- ret.writable = true
- }
- if e := obj.self.getStr("enumerable", nil); e != nil && e.ToBoolean() {
- ret.enumerable = true
- }
- if c := obj.self.getStr("configurable", nil); c != nil && c.ToBoolean() {
- ret.configurable = true
- }
- ret.value = value
- if getter != nil && getter != _undefined {
- o := r.toObject(getter)
- if _, ok := o.self.assertCallable(); !ok {
- r.typeErrorResult(true, "getter must be a function")
- }
- ret.getterFunc = o
- }
- if setter != nil && setter != _undefined {
- o := r.toObject(setter)
- if _, ok := o.self.assertCallable(); !ok {
- r.typeErrorResult(true, "setter must be a function")
- }
- ret.setterFunc = o
- }
- if ret.getterFunc != nil || ret.setterFunc != nil {
- ret.accessor = true
- }
- return ret
- }
- func (r *Runtime) toPropertyDescriptor(v Value) (ret PropertyDescriptor) {
- if o, ok := v.(*Object); ok {
- descr := o.self
- // Save the original descriptor for reference
- ret.jsDescriptor = o
- ret.Value = descr.getStr("value", nil)
- if p := descr.getStr("writable", nil); p != nil {
- ret.Writable = ToFlag(p.ToBoolean())
- }
- if p := descr.getStr("enumerable", nil); p != nil {
- ret.Enumerable = ToFlag(p.ToBoolean())
- }
- if p := descr.getStr("configurable", nil); p != nil {
- ret.Configurable = ToFlag(p.ToBoolean())
- }
- ret.Getter = descr.getStr("get", nil)
- ret.Setter = descr.getStr("set", nil)
- if ret.Getter != nil && ret.Getter != _undefined {
- if _, ok := r.toObject(ret.Getter).self.assertCallable(); !ok {
- r.typeErrorResult(true, "getter must be a function")
- }
- }
- if ret.Setter != nil && ret.Setter != _undefined {
- if _, ok := r.toObject(ret.Setter).self.assertCallable(); !ok {
- r.typeErrorResult(true, "setter must be a function")
- }
- }
- if (ret.Getter != nil || ret.Setter != nil) && (ret.Value != nil || ret.Writable != FLAG_NOT_SET) {
- r.typeErrorResult(true, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute")
- }
- } else {
- r.typeErrorResult(true, "Property description must be an object: %s", v.String())
- }
- return
- }
- func (r *Runtime) _defineProperties(o *Object, p Value) {
- type propItem struct {
- name Value
- prop PropertyDescriptor
- }
- props := p.ToObject(r)
- var list []propItem
- for item, next := iterateEnumerableProperties(props)(); next != nil; item, next = next() {
- list = append(list, propItem{
- name: item.name,
- prop: r.toPropertyDescriptor(item.value),
- })
- }
- for _, prop := range list {
- o.defineOwnProperty(prop.name, prop.prop, true)
- }
- }
- func (r *Runtime) object_create(call FunctionCall) Value {
- var proto *Object
- if arg := call.Argument(0); arg != _null {
- if o, ok := arg.(*Object); ok {
- proto = o
- } else {
- r.typeErrorResult(true, "Object prototype may only be an Object or null: %s", arg.String())
- }
- }
- o := r.newBaseObject(proto, classObject).val
- if props := call.Argument(1); props != _undefined {
- r._defineProperties(o, props)
- }
- return o
- }
- func (r *Runtime) object_defineProperty(call FunctionCall) (ret Value) {
- if obj, ok := call.Argument(0).(*Object); ok {
- descr := r.toPropertyDescriptor(call.Argument(2))
- obj.defineOwnProperty(toPropertyKey(call.Argument(1)), descr, true)
- ret = call.Argument(0)
- } else {
- r.typeErrorResult(true, "Object.defineProperty called on non-object")
- }
- return
- }
- func (r *Runtime) object_defineProperties(call FunctionCall) Value {
- obj := r.toObject(call.Argument(0))
- r._defineProperties(obj, call.Argument(1))
- return obj
- }
- func (r *Runtime) object_seal(call FunctionCall) Value {
- // ES6
- arg := call.Argument(0)
- if obj, ok := arg.(*Object); ok {
- obj.self.preventExtensions(true)
- descr := PropertyDescriptor{
- Configurable: FLAG_FALSE,
- }
- for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
- if prop, ok := item.value.(*valueProperty); ok {
- prop.configurable = false
- } else {
- obj.defineOwnProperty(item.name, descr, true)
- }
- }
- return obj
- }
- return arg
- }
- func (r *Runtime) object_freeze(call FunctionCall) Value {
- arg := call.Argument(0)
- if obj, ok := arg.(*Object); ok {
- obj.self.preventExtensions(true)
- for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
- if prop, ok := item.value.(*valueProperty); ok {
- prop.configurable = false
- if !prop.accessor {
- prop.writable = false
- }
- } else {
- prop := obj.getOwnProp(item.name)
- descr := PropertyDescriptor{
- Configurable: FLAG_FALSE,
- }
- if prop, ok := prop.(*valueProperty); ok && prop.accessor {
- // no-op
- } else {
- descr.Writable = FLAG_FALSE
- }
- obj.defineOwnProperty(item.name, descr, true)
- }
- }
- return obj
- } else {
- // ES6 behavior
- return arg
- }
- }
- func (r *Runtime) object_preventExtensions(call FunctionCall) (ret Value) {
- arg := call.Argument(0)
- if obj, ok := arg.(*Object); ok {
- obj.self.preventExtensions(true)
- }
- return arg
- }
- func (r *Runtime) object_isSealed(call FunctionCall) Value {
- if obj, ok := call.Argument(0).(*Object); ok {
- if obj.self.isExtensible() {
- return valueFalse
- }
- for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
- var prop Value
- if item.value == nil {
- prop = obj.getOwnProp(item.name)
- if prop == nil {
- continue
- }
- } else {
- prop = item.value
- }
- if prop, ok := prop.(*valueProperty); ok {
- if prop.configurable {
- return valueFalse
- }
- } else {
- return valueFalse
- }
- }
- }
- return valueTrue
- }
- func (r *Runtime) object_isFrozen(call FunctionCall) Value {
- if obj, ok := call.Argument(0).(*Object); ok {
- if obj.self.isExtensible() {
- return valueFalse
- }
- for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
- var prop Value
- if item.value == nil {
- prop = obj.getOwnProp(item.name)
- if prop == nil {
- continue
- }
- } else {
- prop = item.value
- }
- if prop, ok := prop.(*valueProperty); ok {
- if prop.configurable || prop.value != nil && prop.writable {
- return valueFalse
- }
- } else {
- return valueFalse
- }
- }
- }
- return valueTrue
- }
- func (r *Runtime) object_isExtensible(call FunctionCall) Value {
- if obj, ok := call.Argument(0).(*Object); ok {
- if obj.self.isExtensible() {
- return valueTrue
- }
- return valueFalse
- } else {
- // ES6
- //r.typeErrorResult(true, "Object.isExtensible called on non-object")
- return valueFalse
- }
- }
- func (r *Runtime) object_keys(call FunctionCall) Value {
- obj := call.Argument(0).ToObject(r)
- return r.newArrayValues(obj.self.stringKeys(false, nil))
- }
- func (r *Runtime) object_entries(call FunctionCall) Value {
- obj := call.Argument(0).ToObject(r)
- var values []Value
- for item, next := iterateEnumerableStringProperties(obj)(); next != nil; item, next = next() {
- values = append(values, r.newArrayValues([]Value{item.name, item.value}))
- }
- return r.newArrayValues(values)
- }
- func (r *Runtime) object_values(call FunctionCall) Value {
- obj := call.Argument(0).ToObject(r)
- var values []Value
- for item, next := iterateEnumerableStringProperties(obj)(); next != nil; item, next = next() {
- values = append(values, item.value)
- }
- return r.newArrayValues(values)
- }
- func (r *Runtime) objectproto_hasOwnProperty(call FunctionCall) Value {
- p := toPropertyKey(call.Argument(0))
- o := call.This.ToObject(r)
- if o.hasOwnProperty(p) {
- return valueTrue
- } else {
- return valueFalse
- }
- }
- func (r *Runtime) objectproto_isPrototypeOf(call FunctionCall) Value {
- if v, ok := call.Argument(0).(*Object); ok {
- o := call.This.ToObject(r)
- for {
- v = v.self.proto()
- if v == nil {
- break
- }
- if v == o {
- return valueTrue
- }
- }
- }
- return valueFalse
- }
- func (r *Runtime) objectproto_propertyIsEnumerable(call FunctionCall) Value {
- p := toPropertyKey(call.Argument(0))
- o := call.This.ToObject(r)
- pv := o.getOwnProp(p)
- if pv == nil {
- return valueFalse
- }
- if prop, ok := pv.(*valueProperty); ok {
- if !prop.enumerable {
- return valueFalse
- }
- }
- return valueTrue
- }
- func (r *Runtime) objectproto_toString(call FunctionCall) Value {
- switch o := call.This.(type) {
- case valueNull:
- return stringObjectNull
- case valueUndefined:
- return stringObjectUndefined
- default:
- obj := o.ToObject(r)
- if o, ok := obj.self.(*objectGoReflect); ok {
- if toString := o.toString; toString != nil {
- return toString()
- }
- }
- var clsName string
- if isArray(obj) {
- clsName = classArray
- } else {
- clsName = obj.self.className()
- }
- if tag := obj.self.getSym(SymToStringTag, nil); tag != nil {
- if str, ok := tag.(String); ok {
- clsName = str.String()
- }
- }
- return newStringValue(fmt.Sprintf("[object %s]", clsName))
- }
- }
- func (r *Runtime) objectproto_toLocaleString(call FunctionCall) Value {
- toString := toMethod(r.getVStr(call.This, "toString"))
- return toString(FunctionCall{This: call.This})
- }
- func (r *Runtime) objectproto_getProto(call FunctionCall) Value {
- proto := call.This.ToObject(r).self.proto()
- if proto != nil {
- return proto
- }
- return _null
- }
- func (r *Runtime) setObjectProto(o, arg Value) {
- r.checkObjectCoercible(o)
- var proto *Object
- if arg != _null {
- if obj, ok := arg.(*Object); ok {
- proto = obj
- } else {
- return
- }
- }
- if o, ok := o.(*Object); ok {
- o.self.setProto(proto, true)
- }
- }
- func (r *Runtime) objectproto_setProto(call FunctionCall) Value {
- r.setObjectProto(call.This, call.Argument(0))
- return _undefined
- }
- func (r *Runtime) objectproto_valueOf(call FunctionCall) Value {
- return call.This.ToObject(r)
- }
- func (r *Runtime) object_assign(call FunctionCall) Value {
- to := call.Argument(0).ToObject(r)
- if len(call.Arguments) > 1 {
- for _, arg := range call.Arguments[1:] {
- if arg != _undefined && arg != _null {
- source := arg.ToObject(r)
- for item, next := iterateEnumerableProperties(source)(); next != nil; item, next = next() {
- to.setOwn(item.name, item.value, true)
- }
- }
- }
- }
- return to
- }
- func (r *Runtime) object_is(call FunctionCall) Value {
- return r.toBoolean(call.Argument(0).SameAs(call.Argument(1)))
- }
- func (r *Runtime) toProto(proto Value) *Object {
- if proto != _null {
- if obj, ok := proto.(*Object); ok {
- return obj
- } else {
- panic(r.NewTypeError("Object prototype may only be an Object or null: %s", proto))
- }
- }
- return nil
- }
- func (r *Runtime) object_setPrototypeOf(call FunctionCall) Value {
- o := call.Argument(0)
- r.checkObjectCoercible(o)
- proto := r.toProto(call.Argument(1))
- if o, ok := o.(*Object); ok {
- o.self.setProto(proto, true)
- }
- return o
- }
- func (r *Runtime) object_fromEntries(call FunctionCall) Value {
- o := call.Argument(0)
- r.checkObjectCoercible(o)
- result := r.newBaseObject(r.global.ObjectPrototype, classObject).val
- iter := r.getIterator(o, nil)
- iter.iterate(func(nextValue Value) {
- i0 := valueInt(0)
- i1 := valueInt(1)
- itemObj := r.toObject(nextValue)
- k := itemObj.self.getIdx(i0, nil)
- v := itemObj.self.getIdx(i1, nil)
- key := toPropertyKey(k)
- createDataPropertyOrThrow(result, key, v)
- })
- return result
- }
- func (r *Runtime) object_hasOwn(call FunctionCall) Value {
- o := call.Argument(0)
- obj := o.ToObject(r)
- p := toPropertyKey(call.Argument(1))
- if obj.hasOwnProperty(p) {
- return valueTrue
- } else {
- return valueFalse
- }
- }
- func createObjectTemplate() *objectTemplate {
- t := newObjectTemplate()
- t.protoFactory = func(r *Runtime) *Object {
- return r.getFunctionPrototype()
- }
- t.putStr("length", func(r *Runtime) Value { return valueProp(intToValue(1), false, false, true) })
- t.putStr("name", func(r *Runtime) Value { return valueProp(asciiString("Object"), false, false, true) })
- t.putStr("prototype", func(r *Runtime) Value { return valueProp(r.global.ObjectPrototype, false, false, false) })
- t.putStr("assign", func(r *Runtime) Value { return r.methodProp(r.object_assign, "assign", 2) })
- t.putStr("defineProperty", func(r *Runtime) Value { return r.methodProp(r.object_defineProperty, "defineProperty", 3) })
- t.putStr("defineProperties", func(r *Runtime) Value { return r.methodProp(r.object_defineProperties, "defineProperties", 2) })
- t.putStr("entries", func(r *Runtime) Value { return r.methodProp(r.object_entries, "entries", 1) })
- t.putStr("getOwnPropertyDescriptor", func(r *Runtime) Value {
- return r.methodProp(r.object_getOwnPropertyDescriptor, "getOwnPropertyDescriptor", 2)
- })
- t.putStr("getOwnPropertyDescriptors", func(r *Runtime) Value {
- return r.methodProp(r.object_getOwnPropertyDescriptors, "getOwnPropertyDescriptors", 1)
- })
- t.putStr("getPrototypeOf", func(r *Runtime) Value { return r.methodProp(r.object_getPrototypeOf, "getPrototypeOf", 1) })
- t.putStr("is", func(r *Runtime) Value { return r.methodProp(r.object_is, "is", 2) })
- t.putStr("getOwnPropertyNames", func(r *Runtime) Value { return r.methodProp(r.object_getOwnPropertyNames, "getOwnPropertyNames", 1) })
- t.putStr("getOwnPropertySymbols", func(r *Runtime) Value {
- return r.methodProp(r.object_getOwnPropertySymbols, "getOwnPropertySymbols", 1)
- })
- t.putStr("create", func(r *Runtime) Value { return r.methodProp(r.object_create, "create", 2) })
- t.putStr("seal", func(r *Runtime) Value { return r.methodProp(r.object_seal, "seal", 1) })
- t.putStr("freeze", func(r *Runtime) Value { return r.methodProp(r.object_freeze, "freeze", 1) })
- t.putStr("preventExtensions", func(r *Runtime) Value { return r.methodProp(r.object_preventExtensions, "preventExtensions", 1) })
- t.putStr("isSealed", func(r *Runtime) Value { return r.methodProp(r.object_isSealed, "isSealed", 1) })
- t.putStr("isFrozen", func(r *Runtime) Value { return r.methodProp(r.object_isFrozen, "isFrozen", 1) })
- t.putStr("isExtensible", func(r *Runtime) Value { return r.methodProp(r.object_isExtensible, "isExtensible", 1) })
- t.putStr("keys", func(r *Runtime) Value { return r.methodProp(r.object_keys, "keys", 1) })
- t.putStr("setPrototypeOf", func(r *Runtime) Value { return r.methodProp(r.object_setPrototypeOf, "setPrototypeOf", 2) })
- t.putStr("values", func(r *Runtime) Value { return r.methodProp(r.object_values, "values", 1) })
- t.putStr("fromEntries", func(r *Runtime) Value { return r.methodProp(r.object_fromEntries, "fromEntries", 1) })
- t.putStr("hasOwn", func(r *Runtime) Value { return r.methodProp(r.object_hasOwn, "hasOwn", 2) })
- return t
- }
- var _objectTemplate *objectTemplate
- var objectTemplateOnce sync.Once
- func getObjectTemplate() *objectTemplate {
- objectTemplateOnce.Do(func() {
- _objectTemplate = createObjectTemplate()
- })
- return _objectTemplate
- }
- func (r *Runtime) getObject() *Object {
- ret := r.global.Object
- if ret == nil {
- ret = &Object{runtime: r}
- r.global.Object = ret
- r.newTemplatedFuncObject(getObjectTemplate(), ret, func(call FunctionCall) Value {
- return r.builtin_Object(call.Arguments, nil)
- }, r.builtin_Object)
- }
- return ret
- }
- /*
- func (r *Runtime) getObjectPrototype() *Object {
- ret := r.global.ObjectPrototype
- if ret == nil {
- ret = &Object{runtime: r}
- r.global.ObjectPrototype = ret
- r.newTemplatedObject(getObjectProtoTemplate(), ret)
- }
- return ret
- }
- */
- var objectProtoTemplate *objectTemplate
- var objectProtoTemplateOnce sync.Once
- func getObjectProtoTemplate() *objectTemplate {
- objectProtoTemplateOnce.Do(func() {
- objectProtoTemplate = createObjectProtoTemplate()
- })
- return objectProtoTemplate
- }
- func createObjectProtoTemplate() *objectTemplate {
- t := newObjectTemplate()
- // null prototype
- t.putStr("constructor", func(r *Runtime) Value { return valueProp(r.getObject(), true, false, true) })
- t.putStr("toString", func(r *Runtime) Value { return r.methodProp(r.objectproto_toString, "toString", 0) })
- t.putStr("toLocaleString", func(r *Runtime) Value { return r.methodProp(r.objectproto_toLocaleString, "toLocaleString", 0) })
- t.putStr("valueOf", func(r *Runtime) Value { return r.methodProp(r.objectproto_valueOf, "valueOf", 0) })
- t.putStr("hasOwnProperty", func(r *Runtime) Value { return r.methodProp(r.objectproto_hasOwnProperty, "hasOwnProperty", 1) })
- t.putStr("isPrototypeOf", func(r *Runtime) Value { return r.methodProp(r.objectproto_isPrototypeOf, "isPrototypeOf", 1) })
- t.putStr("propertyIsEnumerable", func(r *Runtime) Value {
- return r.methodProp(r.objectproto_propertyIsEnumerable, "propertyIsEnumerable", 1)
- })
- t.putStr(__proto__, func(r *Runtime) Value {
- return &valueProperty{
- accessor: true,
- getterFunc: r.newNativeFunc(r.objectproto_getProto, "get __proto__", 0),
- setterFunc: r.newNativeFunc(r.objectproto_setProto, "set __proto__", 1),
- configurable: true,
- }
- })
- return t
- }
|