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