package goja import ( "fmt" ) func (r *Runtime) builtin_Object(args []Value, proto *Object) *Object { if len(args) > 0 { arg := args[0] if arg != _undefined && arg != _null { return arg.ToObject(r) } } return r.newBaseObject(proto, classObject).val } 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) object_getOwnPropertyDescriptor(call FunctionCall) Value { obj := call.Argument(0).ToObject(r) propName := call.Argument(1) desc := obj.self.getOwnProp(propName) 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() o := ret.self if !accessor { o.putStr("value", value, false) o.putStr("writable", r.toBoolean(writable), false) } else { if get != nil { o.putStr("get", get, false) } else { o.putStr("get", _undefined, false) } if set != nil { o.putStr("set", set, false) } else { o.putStr("set", _undefined, false) } } o.putStr("enumerable", r.toBoolean(enumerable), false) o.putStr("configurable", r.toBoolean(configurable), false) return ret } func (r *Runtime) object_getOwnPropertyNames(call FunctionCall) Value { // ES6 obj := call.Argument(0).ToObject(r) // obj := r.toObject(call.Argument(0)) var values []Value for item, f := obj.self.enumerate(true, false)(); f != nil; item, f = f() { values = append(values, newStringValue(item.name)) } return r.newArrayValues(values) } func (r *Runtime) object_getOwnPropertySymbols(call FunctionCall) Value { obj := call.Argument(0).ToObject(r) return r.newArrayValues(obj.self.getOwnSymbols()) } func (r *Runtime) toPropertyDescr(v Value) (ret propertyDescr) { if o, ok := v.(*Object); ok { descr := o.self ret.Value = descr.getStr("value") if p := descr.getStr("writable"); p != nil { ret.Writable = ToFlag(p.ToBoolean()) } if p := descr.getStr("enumerable"); p != nil { ret.Enumerable = ToFlag(p.ToBoolean()) } if p := descr.getStr("configurable"); p != nil { ret.Configurable = ToFlag(p.ToBoolean()) } ret.Getter = descr.getStr("get") ret.Setter = descr.getStr("set") 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") return } } 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 string prop propertyDescr } props := p.ToObject(r) var list []propItem for item, f := props.self.enumerate(false, false)(); f != nil; item, f = f() { list = append(list, propItem{ name: item.name, prop: r.toPropertyDescr(props.self.getStr(item.name)), }) } for _, prop := range list { o.self.defineOwnProperty(newStringValue(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.toPropertyDescr(call.Argument(2)) obj.self.defineOwnProperty(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 { descr := propertyDescr{ Writable: FLAG_TRUE, Enumerable: FLAG_TRUE, Configurable: FLAG_FALSE, } for item, f := obj.self.enumerate(true, false)(); f != nil; item, f = f() { v := obj.self.getOwnPropStr(item.name) if prop, ok := v.(*valueProperty); ok { if !prop.configurable { continue } prop.configurable = false } else { descr.Value = v obj.self.defineOwnProperty(newStringValue(item.name), descr, true) //obj.self._putProp(item.name, v, true, true, false) } } for _, sym := range obj.self.getOwnSymbols() { v := obj.self.getOwnProp(sym) if prop, ok := v.(*valueProperty); ok { if !prop.configurable { continue } prop.configurable = false } else { descr.Value = v obj.self.defineOwnProperty(sym, descr, true) } } obj.self.preventExtensions() return obj } return arg } func (r *Runtime) object_freeze(call FunctionCall) Value { arg := call.Argument(0) if obj, ok := arg.(*Object); ok { descr := propertyDescr{ Writable: FLAG_FALSE, Enumerable: FLAG_TRUE, Configurable: FLAG_FALSE, } for item, f := obj.self.enumerate(true, false)(); f != nil; item, f = f() { v := obj.self.getOwnPropStr(item.name) if prop, ok := v.(*valueProperty); ok { prop.configurable = false if prop.value != nil { prop.writable = false } } else { descr.Value = v obj.self.defineOwnProperty(newStringValue(item.name), descr, true) } } for _, sym := range obj.self.getOwnSymbols() { v := obj.self.getOwnProp(sym) if prop, ok := v.(*valueProperty); ok { prop.configurable = false if prop.value != nil { prop.writable = false } } else { descr.Value = v obj.self.defineOwnProperty(sym, descr, true) } } obj.self.preventExtensions() 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() return obj } // ES6 //r.typeErrorResult(true, "Object.preventExtensions called on non-object") //panic("Unreachable") 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, f := obj.self.enumerate(true, false)(); f != nil; item, f = f() { prop := obj.self.getOwnPropStr(item.name) if prop, ok := prop.(*valueProperty); ok { if prop.configurable { return valueFalse } } else { return valueFalse } } for _, sym := range obj.self.getOwnSymbols() { prop := obj.self.getOwnProp(sym) if prop, ok := prop.(*valueProperty); ok { if prop.configurable { return valueFalse } } else { return valueFalse } } } else { // ES6 //r.typeErrorResult(true, "Object.isSealed called on non-object") return valueTrue } 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, f := obj.self.enumerate(true, false)(); f != nil; item, f = f() { prop := obj.self.getOwnPropStr(item.name) if prop, ok := prop.(*valueProperty); ok { if prop.configurable || prop.value != nil && prop.writable { return valueFalse } } else { return valueFalse } } for _, sym := range obj.self.getOwnSymbols() { prop := obj.self.getOwnProp(sym) if prop, ok := prop.(*valueProperty); ok { if prop.configurable || prop.value != nil && prop.writable { return valueFalse } } else { return valueFalse } } } else { // ES6 //r.typeErrorResult(true, "Object.isFrozen called on non-object") return valueTrue } 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 { // ES6 obj := call.Argument(0).ToObject(r) //if obj, ok := call.Argument(0).(*valueObject); ok { var keys []Value for item, f := obj.self.enumerate(false, false)(); f != nil; item, f = f() { keys = append(keys, newStringValue(item.name)) } return r.newArrayValues(keys) //} else { // r.typeErrorResult(true, "Object.keys called on non-object") //} //return nil } func (r *Runtime) objectproto_hasOwnProperty(call FunctionCall) Value { p := call.Argument(0) o := call.This.ToObject(r) if o.self.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 := call.Argument(0) o := call.This.ToObject(r) pv := o.self.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) var clsName string if tag := obj.self.get(symToStringTag); tag != nil { if str, ok := tag.assertString(); ok { clsName = str.String() } } if clsName == "" { clsName = obj.self.className() } return newStringValue(fmt.Sprintf("[object %s]", clsName)) } } func (r *Runtime) objectproto_toLocaleString(call FunctionCall) Value { return call.This.ToObject(r).ToString() } func (r *Runtime) objectproto_valueOf(call FunctionCall) Value { return call.This.ToObject(r) } func (r *Runtime) initObject() { o := r.global.ObjectPrototype.self o._putProp("toString", r.newNativeFunc(r.objectproto_toString, nil, "toString", nil, 0), true, false, true) o._putProp("toLocaleString", r.newNativeFunc(r.objectproto_toLocaleString, nil, "toLocaleString", nil, 0), true, false, true) o._putProp("valueOf", r.newNativeFunc(r.objectproto_valueOf, nil, "valueOf", nil, 0), true, false, true) o._putProp("hasOwnProperty", r.newNativeFunc(r.objectproto_hasOwnProperty, nil, "hasOwnProperty", nil, 1), true, false, true) o._putProp("isPrototypeOf", r.newNativeFunc(r.objectproto_isPrototypeOf, nil, "isPrototypeOf", nil, 1), true, false, true) o._putProp("propertyIsEnumerable", r.newNativeFunc(r.objectproto_propertyIsEnumerable, nil, "propertyIsEnumerable", nil, 1), true, false, true) r.global.Object = r.newNativeFuncConstruct(r.builtin_Object, classObject, r.global.ObjectPrototype, 1) o = r.global.Object.self o._putProp("defineProperty", r.newNativeFunc(r.object_defineProperty, nil, "defineProperty", nil, 3), true, false, true) o._putProp("defineProperties", r.newNativeFunc(r.object_defineProperties, nil, "defineProperties", nil, 2), true, false, true) o._putProp("getOwnPropertyDescriptor", r.newNativeFunc(r.object_getOwnPropertyDescriptor, nil, "getOwnPropertyDescriptor", nil, 2), true, false, true) o._putProp("getPrototypeOf", r.newNativeFunc(r.object_getPrototypeOf, nil, "getPrototypeOf", nil, 1), true, false, true) o._putProp("getOwnPropertyNames", r.newNativeFunc(r.object_getOwnPropertyNames, nil, "getOwnPropertyNames", nil, 1), true, false, true) o._putProp("getOwnPropertySymbols", r.newNativeFunc(r.object_getOwnPropertySymbols, nil, "getOwnPropertySymbols", nil, 1), true, false, true) o._putProp("create", r.newNativeFunc(r.object_create, nil, "create", nil, 2), true, false, true) o._putProp("seal", r.newNativeFunc(r.object_seal, nil, "seal", nil, 1), true, false, true) o._putProp("freeze", r.newNativeFunc(r.object_freeze, nil, "freeze", nil, 1), true, false, true) o._putProp("preventExtensions", r.newNativeFunc(r.object_preventExtensions, nil, "preventExtensions", nil, 1), true, false, true) o._putProp("isSealed", r.newNativeFunc(r.object_isSealed, nil, "isSealed", nil, 1), true, false, true) o._putProp("isFrozen", r.newNativeFunc(r.object_isFrozen, nil, "isFrozen", nil, 1), true, false, true) o._putProp("isExtensible", r.newNativeFunc(r.object_isExtensible, nil, "isExtensible", nil, 1), true, false, true) o._putProp("keys", r.newNativeFunc(r.object_keys, nil, "keys", nil, 1), true, false, true) r.addToGlobal("Object", r.global.Object) }