github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/object_dynamic.go (about)

     1  package goja
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strconv"
     7  
     8  	"github.com/nuvolaris/goja/unistring"
     9  )
    10  
    11  /*
    12  DynamicObject is an interface representing a handler for a dynamic Object. Such an object can be created
    13  using the Runtime.NewDynamicObject() method.
    14  
    15  Note that Runtime.ToValue() does not have any special treatment for DynamicObject. The only way to create
    16  a dynamic object is by using the Runtime.NewDynamicObject() method. This is done deliberately to avoid
    17  silent code breaks when this interface changes.
    18  */
    19  type DynamicObject interface {
    20  	// Get a property value for the key. May return nil if the property does not exist.
    21  	Get(key string) Value
    22  	// Set a property value for the key. Return true if success, false otherwise.
    23  	Set(key string, val Value) bool
    24  	// Has should return true if and only if the property exists.
    25  	Has(key string) bool
    26  	// Delete the property for the key. Returns true on success (note, that includes missing property).
    27  	Delete(key string) bool
    28  	// Keys returns a list of all existing property keys. There are no checks for duplicates or to make sure
    29  	// that the order conforms to https://262.ecma-international.org/#sec-ordinaryownpropertykeys
    30  	Keys() []string
    31  }
    32  
    33  /*
    34  DynamicArray is an interface representing a handler for a dynamic array Object. Such an object can be created
    35  using the Runtime.NewDynamicArray() method.
    36  
    37  Any integer property key or a string property key that can be parsed into an int value (including negative
    38  ones) is treated as an index and passed to the trap methods of the DynamicArray. Note this is different from
    39  the regular ECMAScript arrays which only support positive indexes up to 2^32-1.
    40  
    41  DynamicArray cannot be sparse, i.e. hasOwnProperty(num) will return true for num >= 0 && num < Len(). Deleting
    42  such a property is equivalent to setting it to undefined. Note that this creates a slight peculiarity because
    43  hasOwnProperty() will still return true, even after deletion.
    44  
    45  Note that Runtime.ToValue() does not have any special treatment for DynamicArray. The only way to create
    46  a dynamic array is by using the Runtime.NewDynamicArray() method. This is done deliberately to avoid
    47  silent code breaks when this interface changes.
    48  */
    49  type DynamicArray interface {
    50  	// Len returns the current array length.
    51  	Len() int
    52  	// Get an item at index idx. Note that idx may be any integer, negative or beyond the current length.
    53  	Get(idx int) Value
    54  	// Set an item at index idx. Note that idx may be any integer, negative or beyond the current length.
    55  	// The expected behaviour when it's beyond length is that the array's length is increased to accommodate
    56  	// the item. All elements in the 'new' section of the array should be zeroed.
    57  	Set(idx int, val Value) bool
    58  	// SetLen is called when the array's 'length' property is changed. If the length is increased all elements in the
    59  	// 'new' section of the array should be zeroed.
    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  /*
    79  NewDynamicObject creates an Object backed by the provided DynamicObject handler.
    80  
    81  All properties of this Object are Writable, Enumerable and Configurable data properties. Any attempt to define
    82  a property that does not conform to this will fail.
    83  
    84  The Object is always extensible and cannot be made non-extensible. Object.preventExtensions() will fail.
    85  
    86  The Object's prototype is initially set to Object.prototype, but can be changed using regular mechanisms
    87  (Object.SetPrototype() in Go or Object.setPrototypeOf() in JS).
    88  
    89  The Object cannot have own Symbol properties, however its prototype can. If you need an iterator support for
    90  example, you could create a regular object, set Symbol.iterator on that object and then use it as a
    91  prototype. See TestDynamicObjectCustomProto for more details.
    92  
    93  Export() returns the original DynamicObject.
    94  
    95  This mechanism is similar to ECMAScript Proxy, however because all properties are enumerable and the object
    96  is always extensible there is no need for invariant checks which removes the need to have a target object and
    97  makes it a lot more efficient.
    98  */
    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  /*
   113  NewSharedDynamicObject is similar to Runtime.NewDynamicObject but the resulting Object can be shared across multiple
   114  Runtimes. The Object's prototype will be null. The provided DynamicObject must be goroutine-safe.
   115  */
   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  /*
   129  NewDynamicArray creates an array Object backed by the provided DynamicArray handler.
   130  It is similar to NewDynamicObject, the differences are:
   131  
   132  - the Object is an array (i.e. Array.isArray() will return true and it will have the length property).
   133  
   134  - the prototype will be initially set to Array.prototype.
   135  
   136  - the Object cannot have any own string properties except for the 'length'.
   137  */
   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.global.ArrayPrototype,
   145  		},
   146  	}
   147  	v.self = o
   148  	return v
   149  }
   150  
   151  /*
   152  NewSharedDynamicArray is similar to Runtime.NewDynamicArray but the resulting Object can be shared across multiple
   153  Runtimes. The Object's prototype will be null. If you need to run Array's methods on it, use Array.prototype.[...].call(a, ...).
   154  The provided DynamicArray must be goroutine-safe.
   155  */
   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  			// we know it's foreign because prototype loops are not allowed
   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  			// we know it's foreign because prototype loops are not allowed
   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  		// we know it's foreign because prototype loops are not allowed
   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  }