1 package goja
2
3 import (
4 "fmt"
5 "reflect"
6 "strconv"
7
8 "github.com/dop251/goja/unistring"
9 )
10
11
19 type DynamicObject interface {
20
21 Get(key string) Value
22
23 Set(key string, val Value) bool
24
25 Has(key string) bool
26
27 Delete(key string) bool
28
29
30 Keys() []string
31 }
32
33
49 type DynamicArray interface {
50
51 Len() int
52
53 Get(idx int) Value
54
55
56
57 Set(idx int, val Value) bool
58
59
60 SetLen(int) bool
61 }
62
63 type baseDynamicObject struct {
64 val *Object
65 prototype *Object
66 }
67
68 type dynamicObject struct {
69 baseDynamicObject
70 d DynamicObject
71 }
72
73 type dynamicArray struct {
74 baseDynamicObject
75 a DynamicArray
76 }
77
78
99 func (r *Runtime) NewDynamicObject(d DynamicObject) *Object {
100 v := &Object{runtime: r}
101 o := &dynamicObject{
102 d: d,
103 baseDynamicObject: baseDynamicObject{
104 val: v,
105 prototype: r.global.ObjectPrototype,
106 },
107 }
108 v.self = o
109 return v
110 }
111
112
116 func NewSharedDynamicObject(d DynamicObject) *Object {
117 v := &Object{}
118 o := &dynamicObject{
119 d: d,
120 baseDynamicObject: baseDynamicObject{
121 val: v,
122 },
123 }
124 v.self = o
125 return v
126 }
127
128
138 func (r *Runtime) NewDynamicArray(a DynamicArray) *Object {
139 v := &Object{runtime: r}
140 o := &dynamicArray{
141 a: a,
142 baseDynamicObject: baseDynamicObject{
143 val: v,
144 prototype: r.getArrayPrototype(),
145 },
146 }
147 v.self = o
148 return v
149 }
150
151
156 func NewSharedDynamicArray(a DynamicArray) *Object {
157 v := &Object{}
158 o := &dynamicArray{
159 a: a,
160 baseDynamicObject: baseDynamicObject{
161 val: v,
162 },
163 }
164 v.self = o
165 return v
166 }
167
168 func (*dynamicObject) sortLen() int {
169 return 0
170 }
171
172 func (*dynamicObject) sortGet(i int) Value {
173 return nil
174 }
175
176 func (*dynamicObject) swap(i int, i2 int) {
177 }
178
179 func (*dynamicObject) className() string {
180 return classObject
181 }
182
183 func (o *baseDynamicObject) getParentStr(p unistring.String, receiver Value) Value {
184 if proto := o.prototype; proto != nil {
185 if receiver == nil {
186 return proto.self.getStr(p, o.val)
187 }
188 return proto.self.getStr(p, receiver)
189 }
190 return nil
191 }
192
193 func (o *dynamicObject) getStr(p unistring.String, receiver Value) Value {
194 prop := o.d.Get(p.String())
195 if prop == nil {
196 return o.getParentStr(p, receiver)
197 }
198 return prop
199 }
200
201 func (o *baseDynamicObject) getParentIdx(p valueInt, receiver Value) Value {
202 if proto := o.prototype; proto != nil {
203 if receiver == nil {
204 return proto.self.getIdx(p, o.val)
205 }
206 return proto.self.getIdx(p, receiver)
207 }
208 return nil
209 }
210
211 func (o *dynamicObject) getIdx(p valueInt, receiver Value) Value {
212 prop := o.d.Get(p.String())
213 if prop == nil {
214 return o.getParentIdx(p, receiver)
215 }
216 return prop
217 }
218
219 func (o *baseDynamicObject) getSym(p *Symbol, receiver Value) Value {
220 if proto := o.prototype; proto != nil {
221 if receiver == nil {
222 return proto.self.getSym(p, o.val)
223 }
224 return proto.self.getSym(p, receiver)
225 }
226 return nil
227 }
228
229 func (o *dynamicObject) getOwnPropStr(u unistring.String) Value {
230 return o.d.Get(u.String())
231 }
232
233 func (o *dynamicObject) getOwnPropIdx(v valueInt) Value {
234 return o.d.Get(v.String())
235 }
236
237 func (*baseDynamicObject) getOwnPropSym(*Symbol) Value {
238 return nil
239 }
240
241 func (o *dynamicObject) _set(prop string, v Value, throw bool) bool {
242 if o.d.Set(prop, v) {
243 return true
244 }
245 typeErrorResult(throw, "'Set' on a dynamic object returned false")
246 return false
247 }
248
249 func (o *baseDynamicObject) _setSym(throw bool) {
250 typeErrorResult(throw, "Dynamic objects do not support Symbol properties")
251 }
252
253 func (o *dynamicObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
254 prop := p.String()
255 if !o.d.Has(prop) {
256 if proto := o.prototype; proto != nil {
257
258 if res, handled := proto.self.setForeignStr(p, v, o.val, throw); handled {
259 return res
260 }
261 }
262 }
263 return o._set(prop, v, throw)
264 }
265
266 func (o *dynamicObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
267 prop := p.String()
268 if !o.d.Has(prop) {
269 if proto := o.prototype; proto != nil {
270
271 if res, handled := proto.self.setForeignIdx(p, v, o.val, throw); handled {
272 return res
273 }
274 }
275 }
276 return o._set(prop, v, throw)
277 }
278
279 func (o *baseDynamicObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
280 if proto := o.prototype; proto != nil {
281
282 if res, handled := proto.self.setForeignSym(s, v, o.val, throw); handled {
283 return res
284 }
285 }
286 o._setSym(throw)
287 return false
288 }
289
290 func (o *baseDynamicObject) setParentForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
291 if proto := o.prototype; proto != nil {
292 if receiver != proto {
293 return proto.self.setForeignStr(p, v, receiver, throw)
294 }
295 return proto.self.setOwnStr(p, v, throw), true
296 }
297 return false, false
298 }
299
300 func (o *dynamicObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
301 prop := p.String()
302 if !o.d.Has(prop) {
303 return o.setParentForeignStr(p, v, receiver, throw)
304 }
305 return false, false
306 }
307
308 func (o *baseDynamicObject) setParentForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
309 if proto := o.prototype; proto != nil {
310 if receiver != proto {
311 return proto.self.setForeignIdx(p, v, receiver, throw)
312 }
313 return proto.self.setOwnIdx(p, v, throw), true
314 }
315 return false, false
316 }
317
318 func (o *dynamicObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
319 prop := p.String()
320 if !o.d.Has(prop) {
321 return o.setParentForeignIdx(p, v, receiver, throw)
322 }
323 return false, false
324 }
325
326 func (o *baseDynamicObject) setForeignSym(p *Symbol, v, receiver Value, throw bool) (res bool, handled bool) {
327 if proto := o.prototype; proto != nil {
328 if receiver != proto {
329 return proto.self.setForeignSym(p, v, receiver, throw)
330 }
331 return proto.self.setOwnSym(p, v, throw), true
332 }
333 return false, false
334 }
335
336 func (o *dynamicObject) hasPropertyStr(u unistring.String) bool {
337 if o.hasOwnPropertyStr(u) {
338 return true
339 }
340 if proto := o.prototype; proto != nil {
341 return proto.self.hasPropertyStr(u)
342 }
343 return false
344 }
345
346 func (o *dynamicObject) hasPropertyIdx(idx valueInt) bool {
347 if o.hasOwnPropertyIdx(idx) {
348 return true
349 }
350 if proto := o.prototype; proto != nil {
351 return proto.self.hasPropertyIdx(idx)
352 }
353 return false
354 }
355
356 func (o *baseDynamicObject) hasPropertySym(s *Symbol) bool {
357 if proto := o.prototype; proto != nil {
358 return proto.self.hasPropertySym(s)
359 }
360 return false
361 }
362
363 func (o *dynamicObject) hasOwnPropertyStr(u unistring.String) bool {
364 return o.d.Has(u.String())
365 }
366
367 func (o *dynamicObject) hasOwnPropertyIdx(v valueInt) bool {
368 return o.d.Has(v.String())
369 }
370
371 func (*baseDynamicObject) hasOwnPropertySym(_ *Symbol) bool {
372 return false
373 }
374
375 func (o *baseDynamicObject) checkDynamicObjectPropertyDescr(name fmt.Stringer, descr PropertyDescriptor, throw bool) bool {
376 if descr.Getter != nil || descr.Setter != nil {
377 typeErrorResult(throw, "Dynamic objects do not support accessor properties")
378 return false
379 }
380 if descr.Writable == FLAG_FALSE {
381 typeErrorResult(throw, "Dynamic object field %q cannot be made read-only", name.String())
382 return false
383 }
384 if descr.Enumerable == FLAG_FALSE {
385 typeErrorResult(throw, "Dynamic object field %q cannot be made non-enumerable", name.String())
386 return false
387 }
388 if descr.Configurable == FLAG_FALSE {
389 typeErrorResult(throw, "Dynamic object field %q cannot be made non-configurable", name.String())
390 return false
391 }
392 return true
393 }
394
395 func (o *dynamicObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
396 if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
397 return o._set(name.String(), desc.Value, throw)
398 }
399 return false
400 }
401
402 func (o *dynamicObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
403 if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
404 return o._set(name.String(), desc.Value, throw)
405 }
406 return false
407 }
408
409 func (o *baseDynamicObject) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
410 o._setSym(throw)
411 return false
412 }
413
414 func (o *dynamicObject) _delete(prop string, throw bool) bool {
415 if o.d.Delete(prop) {
416 return true
417 }
418 typeErrorResult(throw, "Could not delete property %q of a dynamic object", prop)
419 return false
420 }
421
422 func (o *dynamicObject) deleteStr(name unistring.String, throw bool) bool {
423 return o._delete(name.String(), throw)
424 }
425
426 func (o *dynamicObject) deleteIdx(idx valueInt, throw bool) bool {
427 return o._delete(idx.String(), throw)
428 }
429
430 func (*baseDynamicObject) deleteSym(_ *Symbol, _ bool) bool {
431 return true
432 }
433
434 func (o *baseDynamicObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
435 return nil, false
436 }
437
438 func (o *baseDynamicObject) vmCall(vm *vm, n int) {
439 panic(vm.r.NewTypeError("Dynamic object is not callable"))
440 }
441
442 func (*baseDynamicObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
443 return nil
444 }
445
446 func (o *baseDynamicObject) proto() *Object {
447 return o.prototype
448 }
449
450 func (o *baseDynamicObject) setProto(proto *Object, throw bool) bool {
451 o.prototype = proto
452 return true
453 }
454
455 func (o *baseDynamicObject) hasInstance(v Value) bool {
456 panic(newTypeError("Expecting a function in instanceof check, but got a dynamic object"))
457 }
458
459 func (*baseDynamicObject) isExtensible() bool {
460 return true
461 }
462
463 func (o *baseDynamicObject) preventExtensions(throw bool) bool {
464 typeErrorResult(throw, "Cannot make a dynamic object non-extensible")
465 return false
466 }
467
468 type dynamicObjectPropIter struct {
469 o *dynamicObject
470 propNames []string
471 idx int
472 }
473
474 func (i *dynamicObjectPropIter) next() (propIterItem, iterNextFunc) {
475 for i.idx < len(i.propNames) {
476 name := i.propNames[i.idx]
477 i.idx++
478 if i.o.d.Has(name) {
479 return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
480 }
481 }
482 return propIterItem{}, nil
483 }
484
485 func (o *dynamicObject) iterateStringKeys() iterNextFunc {
486 keys := o.d.Keys()
487 return (&dynamicObjectPropIter{
488 o: o,
489 propNames: keys,
490 }).next
491 }
492
493 func (o *baseDynamicObject) iterateSymbols() iterNextFunc {
494 return func() (propIterItem, iterNextFunc) {
495 return propIterItem{}, nil
496 }
497 }
498
499 func (o *dynamicObject) iterateKeys() iterNextFunc {
500 return o.iterateStringKeys()
501 }
502
503 func (o *dynamicObject) export(ctx *objectExportCtx) interface{} {
504 return o.d
505 }
506
507 func (o *dynamicObject) exportType() reflect.Type {
508 return reflect.TypeOf(o.d)
509 }
510
511 func (o *baseDynamicObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
512 return genericExportToMap(o.val, dst, typ, ctx)
513 }
514
515 func (o *baseDynamicObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
516 return genericExportToArrayOrSlice(o.val, dst, typ, ctx)
517 }
518
519 func (o *dynamicObject) equal(impl objectImpl) bool {
520 if other, ok := impl.(*dynamicObject); ok {
521 return o.d == other.d
522 }
523 return false
524 }
525
526 func (o *dynamicObject) stringKeys(all bool, accum []Value) []Value {
527 keys := o.d.Keys()
528 if l := len(accum) + len(keys); l > cap(accum) {
529 oldAccum := accum
530 accum = make([]Value, len(accum), l)
531 copy(accum, oldAccum)
532 }
533 for _, key := range keys {
534 accum = append(accum, newStringValue(key))
535 }
536 return accum
537 }
538
539 func (*baseDynamicObject) symbols(all bool, accum []Value) []Value {
540 return accum
541 }
542
543 func (o *dynamicObject) keys(all bool, accum []Value) []Value {
544 return o.stringKeys(all, accum)
545 }
546
547 func (*baseDynamicObject) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
548 return nil
549 }
550
551 func (*baseDynamicObject) _putSym(s *Symbol, prop Value) {
552 }
553
554 func (o *baseDynamicObject) getPrivateEnv(*privateEnvType, bool) *privateElements {
555 panic(newTypeError("Dynamic objects cannot have private elements"))
556 }
557
558 func (o *baseDynamicObject) typeOf() String {
559 return stringObjectC
560 }
561
562 func (a *dynamicArray) sortLen() int {
563 return a.a.Len()
564 }
565
566 func (a *dynamicArray) sortGet(i int) Value {
567 return a.a.Get(i)
568 }
569
570 func (a *dynamicArray) swap(i int, j int) {
571 x := a.sortGet(i)
572 y := a.sortGet(j)
573 a.a.Set(int(i), y)
574 a.a.Set(int(j), x)
575 }
576
577 func (a *dynamicArray) className() string {
578 return classArray
579 }
580
581 func (a *dynamicArray) getStr(p unistring.String, receiver Value) Value {
582 if p == "length" {
583 return intToValue(int64(a.a.Len()))
584 }
585 if idx, ok := strToInt(p); ok {
586 return a.a.Get(idx)
587 }
588 return a.getParentStr(p, receiver)
589 }
590
591 func (a *dynamicArray) getIdx(p valueInt, receiver Value) Value {
592 if val := a.getOwnPropIdx(p); val != nil {
593 return val
594 }
595 return a.getParentIdx(p, receiver)
596 }
597
598 func (a *dynamicArray) getOwnPropStr(u unistring.String) Value {
599 if u == "length" {
600 return &valueProperty{
601 value: intToValue(int64(a.a.Len())),
602 writable: true,
603 }
604 }
605 if idx, ok := strToInt(u); ok {
606 return a.a.Get(idx)
607 }
608 return nil
609 }
610
611 func (a *dynamicArray) getOwnPropIdx(v valueInt) Value {
612 return a.a.Get(toIntStrict(int64(v)))
613 }
614
615 func (a *dynamicArray) _setLen(v Value, throw bool) bool {
616 if a.a.SetLen(toIntStrict(v.ToInteger())) {
617 return true
618 }
619 typeErrorResult(throw, "'SetLen' on a dynamic array returned false")
620 return false
621 }
622
623 func (a *dynamicArray) setOwnStr(p unistring.String, v Value, throw bool) bool {
624 if p == "length" {
625 return a._setLen(v, throw)
626 }
627 if idx, ok := strToInt(p); ok {
628 return a._setIdx(idx, v, throw)
629 }
630 typeErrorResult(throw, "Cannot set property %q on a dynamic array", p.String())
631 return false
632 }
633
634 func (a *dynamicArray) _setIdx(idx int, v Value, throw bool) bool {
635 if a.a.Set(idx, v) {
636 return true
637 }
638 typeErrorResult(throw, "'Set' on a dynamic array returned false")
639 return false
640 }
641
642 func (a *dynamicArray) setOwnIdx(p valueInt, v Value, throw bool) bool {
643 return a._setIdx(toIntStrict(int64(p)), v, throw)
644 }
645
646 func (a *dynamicArray) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
647 return a.setParentForeignStr(p, v, receiver, throw)
648 }
649
650 func (a *dynamicArray) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
651 return a.setParentForeignIdx(p, v, receiver, throw)
652 }
653
654 func (a *dynamicArray) hasPropertyStr(u unistring.String) bool {
655 if a.hasOwnPropertyStr(u) {
656 return true
657 }
658 if proto := a.prototype; proto != nil {
659 return proto.self.hasPropertyStr(u)
660 }
661 return false
662 }
663
664 func (a *dynamicArray) hasPropertyIdx(idx valueInt) bool {
665 if a.hasOwnPropertyIdx(idx) {
666 return true
667 }
668 if proto := a.prototype; proto != nil {
669 return proto.self.hasPropertyIdx(idx)
670 }
671 return false
672 }
673
674 func (a *dynamicArray) _has(idx int) bool {
675 return idx >= 0 && idx < a.a.Len()
676 }
677
678 func (a *dynamicArray) hasOwnPropertyStr(u unistring.String) bool {
679 if u == "length" {
680 return true
681 }
682 if idx, ok := strToInt(u); ok {
683 return a._has(idx)
684 }
685 return false
686 }
687
688 func (a *dynamicArray) hasOwnPropertyIdx(v valueInt) bool {
689 return a._has(toIntStrict(int64(v)))
690 }
691
692 func (a *dynamicArray) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
693 if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
694 if idx, ok := strToInt(name); ok {
695 return a._setIdx(idx, desc.Value, throw)
696 }
697 typeErrorResult(throw, "Cannot define property %q on a dynamic array", name.String())
698 }
699 return false
700 }
701
702 func (a *dynamicArray) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
703 if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
704 return a._setIdx(toIntStrict(int64(name)), desc.Value, throw)
705 }
706 return false
707 }
708
709 func (a *dynamicArray) _delete(idx int, throw bool) bool {
710 if a._has(idx) {
711 a._setIdx(idx, _undefined, throw)
712 }
713 return true
714 }
715
716 func (a *dynamicArray) deleteStr(name unistring.String, throw bool) bool {
717 if idx, ok := strToInt(name); ok {
718 return a._delete(idx, throw)
719 }
720 if a.hasOwnPropertyStr(name) {
721 typeErrorResult(throw, "Cannot delete property %q on a dynamic array", name.String())
722 return false
723 }
724 return true
725 }
726
727 func (a *dynamicArray) deleteIdx(idx valueInt, throw bool) bool {
728 return a._delete(toIntStrict(int64(idx)), throw)
729 }
730
731 type dynArrayPropIter struct {
732 a DynamicArray
733 idx, limit int
734 }
735
736 func (i *dynArrayPropIter) next() (propIterItem, iterNextFunc) {
737 if i.idx < i.limit && i.idx < i.a.Len() {
738 name := strconv.Itoa(i.idx)
739 i.idx++
740 return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
741 }
742
743 return propIterItem{}, nil
744 }
745
746 func (a *dynamicArray) iterateStringKeys() iterNextFunc {
747 return (&dynArrayPropIter{
748 a: a.a,
749 limit: a.a.Len(),
750 }).next
751 }
752
753 func (a *dynamicArray) iterateKeys() iterNextFunc {
754 return a.iterateStringKeys()
755 }
756
757 func (a *dynamicArray) export(ctx *objectExportCtx) interface{} {
758 return a.a
759 }
760
761 func (a *dynamicArray) exportType() reflect.Type {
762 return reflect.TypeOf(a.a)
763 }
764
765 func (a *dynamicArray) equal(impl objectImpl) bool {
766 if other, ok := impl.(*dynamicArray); ok {
767 return a == other
768 }
769 return false
770 }
771
772 func (a *dynamicArray) stringKeys(all bool, accum []Value) []Value {
773 al := a.a.Len()
774 l := len(accum) + al
775 if all {
776 l++
777 }
778 if l > cap(accum) {
779 oldAccum := accum
780 accum = make([]Value, len(oldAccum), l)
781 copy(accum, oldAccum)
782 }
783 for i := 0; i < al; i++ {
784 accum = append(accum, asciiString(strconv.Itoa(i)))
785 }
786 if all {
787 accum = append(accum, asciiString("length"))
788 }
789 return accum
790 }
791
792 func (a *dynamicArray) keys(all bool, accum []Value) []Value {
793 return a.stringKeys(all, accum)
794 }
795
View as plain text