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 }