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