1package goja 2 3import ( 4 "fmt" 5) 6 7func (r *Runtime) builtin_Object(args []Value, proto *Object) *Object { 8 if len(args) > 0 { 9 arg := args[0] 10 if arg != _undefined && arg != _null { 11 return arg.ToObject(r) 12 } 13 } 14 return r.newBaseObject(proto, classObject).val 15} 16 17func (r *Runtime) object_getPrototypeOf(call FunctionCall) Value { 18 o := call.Argument(0).ToObject(r) 19 p := o.self.proto() 20 if p == nil { 21 return _null 22 } 23 return p 24} 25 26func (r *Runtime) valuePropToDescriptorObject(desc Value) Value { 27 if desc == nil { 28 return _undefined 29 } 30 var writable, configurable, enumerable, accessor bool 31 var get, set *Object 32 var value Value 33 if v, ok := desc.(*valueProperty); ok { 34 writable = v.writable 35 configurable = v.configurable 36 enumerable = v.enumerable 37 accessor = v.accessor 38 value = v.value 39 get = v.getterFunc 40 set = v.setterFunc 41 } else { 42 writable = true 43 configurable = true 44 enumerable = true 45 value = desc 46 } 47 48 ret := r.NewObject() 49 obj := ret.self 50 if !accessor { 51 obj.setOwnStr("value", value, false) 52 obj.setOwnStr("writable", r.toBoolean(writable), false) 53 } else { 54 if get != nil { 55 obj.setOwnStr("get", get, false) 56 } else { 57 obj.setOwnStr("get", _undefined, false) 58 } 59 if set != nil { 60 obj.setOwnStr("set", set, false) 61 } else { 62 obj.setOwnStr("set", _undefined, false) 63 } 64 } 65 obj.setOwnStr("enumerable", r.toBoolean(enumerable), false) 66 obj.setOwnStr("configurable", r.toBoolean(configurable), false) 67 68 return ret 69} 70 71func (r *Runtime) object_getOwnPropertyDescriptor(call FunctionCall) Value { 72 o := call.Argument(0).ToObject(r) 73 propName := toPropertyKey(call.Argument(1)) 74 return r.valuePropToDescriptorObject(o.getOwnProp(propName)) 75} 76 77func (r *Runtime) object_getOwnPropertyDescriptors(call FunctionCall) Value { 78 o := call.Argument(0).ToObject(r) 79 ownKeys := o.self.ownPropertyKeys(true, nil) 80 result := r.newBaseObject(r.global.ObjectPrototype, classObject).val 81 for _, key := range ownKeys { 82 descriptor := r.valuePropToDescriptorObject(o.getOwnProp(key)) 83 if descriptor != _undefined { 84 createDataPropertyOrThrow(result, key, descriptor) 85 } 86 } 87 return result 88} 89 90func (r *Runtime) object_getOwnPropertyNames(call FunctionCall) Value { 91 obj := call.Argument(0).ToObject(r) 92 93 return r.newArrayValues(obj.self.ownKeys(true, nil)) 94} 95 96func (r *Runtime) object_getOwnPropertySymbols(call FunctionCall) Value { 97 obj := call.Argument(0).ToObject(r) 98 return r.newArrayValues(obj.self.ownSymbols(true, nil)) 99} 100 101func (r *Runtime) toValueProp(v Value) *valueProperty { 102 if v == nil || v == _undefined { 103 return nil 104 } 105 obj := r.toObject(v) 106 getter := obj.self.getStr("get", nil) 107 setter := obj.self.getStr("set", nil) 108 writable := obj.self.getStr("writable", nil) 109 value := obj.self.getStr("value", nil) 110 if (getter != nil || setter != nil) && (value != nil || writable != nil) { 111 r.typeErrorResult(true, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute") 112 } 113 114 ret := &valueProperty{} 115 if writable != nil && writable.ToBoolean() { 116 ret.writable = true 117 } 118 if e := obj.self.getStr("enumerable", nil); e != nil && e.ToBoolean() { 119 ret.enumerable = true 120 } 121 if c := obj.self.getStr("configurable", nil); c != nil && c.ToBoolean() { 122 ret.configurable = true 123 } 124 ret.value = value 125 126 if getter != nil && getter != _undefined { 127 o := r.toObject(getter) 128 if _, ok := o.self.assertCallable(); !ok { 129 r.typeErrorResult(true, "getter must be a function") 130 } 131 ret.getterFunc = o 132 } 133 134 if setter != nil && setter != _undefined { 135 o := r.toObject(v) 136 if _, ok := o.self.assertCallable(); !ok { 137 r.typeErrorResult(true, "setter must be a function") 138 } 139 ret.setterFunc = o 140 } 141 142 if ret.getterFunc != nil || ret.setterFunc != nil { 143 ret.accessor = true 144 } 145 146 return ret 147} 148 149func (r *Runtime) toPropertyDescriptor(v Value) (ret PropertyDescriptor) { 150 if o, ok := v.(*Object); ok { 151 descr := o.self 152 153 // Save the original descriptor for reference 154 ret.jsDescriptor = o 155 156 ret.Value = descr.getStr("value", nil) 157 158 if p := descr.getStr("writable", nil); p != nil { 159 ret.Writable = ToFlag(p.ToBoolean()) 160 } 161 if p := descr.getStr("enumerable", nil); p != nil { 162 ret.Enumerable = ToFlag(p.ToBoolean()) 163 } 164 if p := descr.getStr("configurable", nil); p != nil { 165 ret.Configurable = ToFlag(p.ToBoolean()) 166 } 167 168 ret.Getter = descr.getStr("get", nil) 169 ret.Setter = descr.getStr("set", nil) 170 171 if ret.Getter != nil && ret.Getter != _undefined { 172 if _, ok := r.toObject(ret.Getter).self.assertCallable(); !ok { 173 r.typeErrorResult(true, "getter must be a function") 174 } 175 } 176 177 if ret.Setter != nil && ret.Setter != _undefined { 178 if _, ok := r.toObject(ret.Setter).self.assertCallable(); !ok { 179 r.typeErrorResult(true, "setter must be a function") 180 } 181 } 182 183 if (ret.Getter != nil || ret.Setter != nil) && (ret.Value != nil || ret.Writable != FLAG_NOT_SET) { 184 r.typeErrorResult(true, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute") 185 } 186 } else { 187 r.typeErrorResult(true, "Property description must be an object: %s", v.String()) 188 } 189 190 return 191} 192 193func (r *Runtime) _defineProperties(o *Object, p Value) { 194 type propItem struct { 195 name Value 196 prop PropertyDescriptor 197 } 198 props := p.ToObject(r) 199 names := props.self.ownPropertyKeys(false, nil) 200 list := make([]propItem, 0, len(names)) 201 for _, itemName := range names { 202 list = append(list, propItem{ 203 name: itemName, 204 prop: r.toPropertyDescriptor(props.get(itemName, nil)), 205 }) 206 } 207 for _, prop := range list { 208 o.defineOwnProperty(prop.name, prop.prop, true) 209 } 210} 211 212func (r *Runtime) object_create(call FunctionCall) Value { 213 var proto *Object 214 if arg := call.Argument(0); arg != _null { 215 if o, ok := arg.(*Object); ok { 216 proto = o 217 } else { 218 r.typeErrorResult(true, "Object prototype may only be an Object or null: %s", arg.String()) 219 } 220 } 221 o := r.newBaseObject(proto, classObject).val 222 223 if props := call.Argument(1); props != _undefined { 224 r._defineProperties(o, props) 225 } 226 227 return o 228} 229 230func (r *Runtime) object_defineProperty(call FunctionCall) (ret Value) { 231 if obj, ok := call.Argument(0).(*Object); ok { 232 descr := r.toPropertyDescriptor(call.Argument(2)) 233 obj.defineOwnProperty(toPropertyKey(call.Argument(1)), descr, true) 234 ret = call.Argument(0) 235 } else { 236 r.typeErrorResult(true, "Object.defineProperty called on non-object") 237 } 238 return 239} 240 241func (r *Runtime) object_defineProperties(call FunctionCall) Value { 242 obj := r.toObject(call.Argument(0)) 243 r._defineProperties(obj, call.Argument(1)) 244 return obj 245} 246 247func (r *Runtime) object_seal(call FunctionCall) Value { 248 // ES6 249 arg := call.Argument(0) 250 if obj, ok := arg.(*Object); ok { 251 descr := PropertyDescriptor{ 252 Writable: FLAG_TRUE, 253 Enumerable: FLAG_TRUE, 254 Configurable: FLAG_FALSE, 255 } 256 for _, key := range obj.self.ownPropertyKeys(true, nil) { 257 v := obj.getOwnProp(key) 258 if prop, ok := v.(*valueProperty); ok { 259 if !prop.configurable { 260 continue 261 } 262 prop.configurable = false 263 } else { 264 descr.Value = v 265 obj.defineOwnProperty(key, descr, true) 266 } 267 } 268 obj.self.preventExtensions(false) 269 return obj 270 } 271 return arg 272} 273 274func (r *Runtime) object_freeze(call FunctionCall) Value { 275 arg := call.Argument(0) 276 if obj, ok := arg.(*Object); ok { 277 descr := PropertyDescriptor{ 278 Writable: FLAG_FALSE, 279 Enumerable: FLAG_TRUE, 280 Configurable: FLAG_FALSE, 281 } 282 for _, key := range obj.self.ownPropertyKeys(true, nil) { 283 v := obj.getOwnProp(key) 284 if prop, ok := v.(*valueProperty); ok { 285 prop.configurable = false 286 if prop.value != nil { 287 prop.writable = false 288 } 289 } else { 290 descr.Value = v 291 obj.defineOwnProperty(key, descr, true) 292 } 293 } 294 obj.self.preventExtensions(false) 295 return obj 296 } else { 297 // ES6 behavior 298 return arg 299 } 300} 301 302func (r *Runtime) object_preventExtensions(call FunctionCall) (ret Value) { 303 arg := call.Argument(0) 304 if obj, ok := arg.(*Object); ok { 305 obj.self.preventExtensions(false) 306 return obj 307 } 308 // ES6 309 //r.typeErrorResult(true, "Object.preventExtensions called on non-object") 310 //panic("Unreachable") 311 return arg 312} 313 314func (r *Runtime) object_isSealed(call FunctionCall) Value { 315 if obj, ok := call.Argument(0).(*Object); ok { 316 if obj.self.isExtensible() { 317 return valueFalse 318 } 319 for _, key := range obj.self.ownPropertyKeys(true, nil) { 320 prop := obj.getOwnProp(key) 321 if prop, ok := prop.(*valueProperty); ok { 322 if prop.configurable { 323 return valueFalse 324 } 325 } else { 326 return valueFalse 327 } 328 } 329 } 330 return valueTrue 331} 332 333func (r *Runtime) object_isFrozen(call FunctionCall) Value { 334 if obj, ok := call.Argument(0).(*Object); ok { 335 if obj.self.isExtensible() { 336 return valueFalse 337 } 338 for _, key := range obj.self.ownPropertyKeys(true, nil) { 339 prop := obj.getOwnProp(key) 340 if prop, ok := prop.(*valueProperty); ok { 341 if prop.configurable || prop.value != nil && prop.writable { 342 return valueFalse 343 } 344 } else { 345 return valueFalse 346 } 347 } 348 } 349 return valueTrue 350} 351 352func (r *Runtime) object_isExtensible(call FunctionCall) Value { 353 if obj, ok := call.Argument(0).(*Object); ok { 354 if obj.self.isExtensible() { 355 return valueTrue 356 } 357 return valueFalse 358 } else { 359 // ES6 360 //r.typeErrorResult(true, "Object.isExtensible called on non-object") 361 return valueFalse 362 } 363} 364 365func (r *Runtime) object_keys(call FunctionCall) Value { 366 obj := call.Argument(0).ToObject(r) 367 368 return r.newArrayValues(obj.self.ownKeys(false, nil)) 369} 370 371func (r *Runtime) object_entries(call FunctionCall) Value { 372 obj := call.Argument(0).ToObject(r) 373 374 var values []Value 375 iter := &enumerableIter{ 376 wrapped: obj.self.enumerateOwnKeys(), 377 } 378 379 for item, next := iter.next(); next != nil; item, next = next() { 380 v := nilSafe(obj.self.getStr(item.name, nil)) 381 values = append(values, r.newArrayValues([]Value{stringValueFromRaw(item.name), v})) 382 } 383 384 return r.newArrayValues(values) 385} 386 387func (r *Runtime) object_values(call FunctionCall) Value { 388 obj := call.Argument(0).ToObject(r) 389 390 var values []Value 391 iter := &enumerableIter{ 392 wrapped: obj.self.enumerateOwnKeys(), 393 } 394 395 for item, next := iter.next(); next != nil; item, next = next() { 396 values = append(values, nilSafe(obj.self.getStr(item.name, nil))) 397 } 398 399 return r.newArrayValues(values) 400} 401 402func (r *Runtime) objectproto_hasOwnProperty(call FunctionCall) Value { 403 p := toPropertyKey(call.Argument(0)) 404 o := call.This.ToObject(r) 405 if o.hasOwnProperty(p) { 406 return valueTrue 407 } else { 408 return valueFalse 409 } 410} 411 412func (r *Runtime) objectproto_isPrototypeOf(call FunctionCall) Value { 413 if v, ok := call.Argument(0).(*Object); ok { 414 o := call.This.ToObject(r) 415 for { 416 v = v.self.proto() 417 if v == nil { 418 break 419 } 420 if v == o { 421 return valueTrue 422 } 423 } 424 } 425 return valueFalse 426} 427 428func (r *Runtime) objectproto_propertyIsEnumerable(call FunctionCall) Value { 429 p := toPropertyKey(call.Argument(0)) 430 o := call.This.ToObject(r) 431 pv := o.getOwnProp(p) 432 if pv == nil { 433 return valueFalse 434 } 435 if prop, ok := pv.(*valueProperty); ok { 436 if !prop.enumerable { 437 return valueFalse 438 } 439 } 440 return valueTrue 441} 442 443func (r *Runtime) objectproto_toString(call FunctionCall) Value { 444 switch o := call.This.(type) { 445 case valueNull: 446 return stringObjectNull 447 case valueUndefined: 448 return stringObjectUndefined 449 default: 450 obj := o.ToObject(r) 451 var clsName string 452 if isArray(obj) { 453 clsName = classArray 454 } else { 455 clsName = obj.self.className() 456 } 457 if tag := obj.self.getSym(SymToStringTag, nil); tag != nil { 458 if str, ok := tag.(valueString); ok { 459 clsName = str.String() 460 } 461 } 462 return newStringValue(fmt.Sprintf("[object %s]", clsName)) 463 } 464} 465 466func (r *Runtime) objectproto_toLocaleString(call FunctionCall) Value { 467 toString := toMethod(r.getVStr(call.This, "toString")) 468 return toString(FunctionCall{This: call.This}) 469} 470 471func (r *Runtime) objectproto_getProto(call FunctionCall) Value { 472 proto := call.This.ToObject(r).self.proto() 473 if proto != nil { 474 return proto 475 } 476 return _null 477} 478 479func (r *Runtime) objectproto_setProto(call FunctionCall) Value { 480 o := call.This 481 r.checkObjectCoercible(o) 482 proto := r.toProto(call.Argument(0)) 483 if o, ok := o.(*Object); ok { 484 o.self.setProto(proto, true) 485 } 486 487 return _undefined 488} 489 490func (r *Runtime) objectproto_valueOf(call FunctionCall) Value { 491 return call.This.ToObject(r) 492} 493 494func (r *Runtime) object_assign(call FunctionCall) Value { 495 to := call.Argument(0).ToObject(r) 496 if len(call.Arguments) > 1 { 497 for _, arg := range call.Arguments[1:] { 498 if arg != _undefined && arg != _null { 499 source := arg.ToObject(r) 500 for _, key := range source.self.ownPropertyKeys(true, nil) { 501 p := source.getOwnProp(key) 502 if p == nil { 503 continue 504 } 505 if v, ok := p.(*valueProperty); ok { 506 if !v.enumerable { 507 continue 508 } 509 p = v.get(source) 510 } 511 to.setOwn(key, p, true) 512 } 513 } 514 } 515 } 516 517 return to 518} 519 520func (r *Runtime) object_is(call FunctionCall) Value { 521 return r.toBoolean(call.Argument(0).SameAs(call.Argument(1))) 522} 523 524func (r *Runtime) toProto(proto Value) *Object { 525 if proto != _null { 526 if obj, ok := proto.(*Object); ok { 527 return obj 528 } else { 529 panic(r.NewTypeError("Object prototype may only be an Object or null: %s", proto)) 530 } 531 } 532 return nil 533} 534 535func (r *Runtime) object_setPrototypeOf(call FunctionCall) Value { 536 o := call.Argument(0) 537 r.checkObjectCoercible(o) 538 proto := r.toProto(call.Argument(1)) 539 if o, ok := o.(*Object); ok { 540 o.self.setProto(proto, true) 541 } 542 543 return o 544} 545 546func (r *Runtime) initObject() { 547 o := r.global.ObjectPrototype.self 548 o._putProp("toString", r.newNativeFunc(r.objectproto_toString, nil, "toString", nil, 0), true, false, true) 549 o._putProp("toLocaleString", r.newNativeFunc(r.objectproto_toLocaleString, nil, "toLocaleString", nil, 0), true, false, true) 550 o._putProp("valueOf", r.newNativeFunc(r.objectproto_valueOf, nil, "valueOf", nil, 0), true, false, true) 551 o._putProp("hasOwnProperty", r.newNativeFunc(r.objectproto_hasOwnProperty, nil, "hasOwnProperty", nil, 1), true, false, true) 552 o._putProp("isPrototypeOf", r.newNativeFunc(r.objectproto_isPrototypeOf, nil, "isPrototypeOf", nil, 1), true, false, true) 553 o._putProp("propertyIsEnumerable", r.newNativeFunc(r.objectproto_propertyIsEnumerable, nil, "propertyIsEnumerable", nil, 1), true, false, true) 554 o.defineOwnPropertyStr(__proto__, PropertyDescriptor{ 555 Getter: r.newNativeFunc(r.objectproto_getProto, nil, "get __proto__", nil, 0), 556 Setter: r.newNativeFunc(r.objectproto_setProto, nil, "set __proto__", nil, 1), 557 Configurable: FLAG_TRUE, 558 }, true) 559 560 r.global.Object = r.newNativeFuncConstruct(r.builtin_Object, classObject, r.global.ObjectPrototype, 1) 561 o = r.global.Object.self 562 o._putProp("assign", r.newNativeFunc(r.object_assign, nil, "assign", nil, 2), true, false, true) 563 o._putProp("defineProperty", r.newNativeFunc(r.object_defineProperty, nil, "defineProperty", nil, 3), true, false, true) 564 o._putProp("defineProperties", r.newNativeFunc(r.object_defineProperties, nil, "defineProperties", nil, 2), true, false, true) 565 o._putProp("entries", r.newNativeFunc(r.object_entries, nil, "entries", nil, 1), true, false, true) 566 o._putProp("getOwnPropertyDescriptor", r.newNativeFunc(r.object_getOwnPropertyDescriptor, nil, "getOwnPropertyDescriptor", nil, 2), true, false, true) 567 o._putProp("getOwnPropertyDescriptors", r.newNativeFunc(r.object_getOwnPropertyDescriptors, nil, "getOwnPropertyDescriptors", nil, 1), true, false, true) 568 o._putProp("getPrototypeOf", r.newNativeFunc(r.object_getPrototypeOf, nil, "getPrototypeOf", nil, 1), true, false, true) 569 o._putProp("is", r.newNativeFunc(r.object_is, nil, "is", nil, 2), true, false, true) 570 o._putProp("getOwnPropertyNames", r.newNativeFunc(r.object_getOwnPropertyNames, nil, "getOwnPropertyNames", nil, 1), true, false, true) 571 o._putProp("getOwnPropertySymbols", r.newNativeFunc(r.object_getOwnPropertySymbols, nil, "getOwnPropertySymbols", nil, 1), true, false, true) 572 o._putProp("create", r.newNativeFunc(r.object_create, nil, "create", nil, 2), true, false, true) 573 o._putProp("seal", r.newNativeFunc(r.object_seal, nil, "seal", nil, 1), true, false, true) 574 o._putProp("freeze", r.newNativeFunc(r.object_freeze, nil, "freeze", nil, 1), true, false, true) 575 o._putProp("preventExtensions", r.newNativeFunc(r.object_preventExtensions, nil, "preventExtensions", nil, 1), true, false, true) 576 o._putProp("isSealed", r.newNativeFunc(r.object_isSealed, nil, "isSealed", nil, 1), true, false, true) 577 o._putProp("isFrozen", r.newNativeFunc(r.object_isFrozen, nil, "isFrozen", nil, 1), true, false, true) 578 o._putProp("isExtensible", r.newNativeFunc(r.object_isExtensible, nil, "isExtensible", nil, 1), true, false, true) 579 o._putProp("keys", r.newNativeFunc(r.object_keys, nil, "keys", nil, 1), true, false, true) 580 o._putProp("setPrototypeOf", r.newNativeFunc(r.object_setPrototypeOf, nil, "setPrototypeOf", nil, 2), true, false, true) 581 o._putProp("values", r.newNativeFunc(r.object_values, nil, "values", nil, 1), true, false, true) 582 583 r.addToGlobal("Object", r.global.Object) 584} 585