go.ketch.com/lib/goja@v0.0.1/object_dynamic.go (about) 1 package goja 2 3 import ( 4 "fmt" 5 "reflect" 6 "strconv" 7 8 "go.ketch.com/lib/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) toPrimitiveNumber() Value { 435 return o.val.genericToPrimitiveNumber() 436 } 437 438 func (o *baseDynamicObject) toPrimitiveString() Value { 439 return o.val.genericToPrimitiveString() 440 } 441 442 func (o *baseDynamicObject) toPrimitive() Value { 443 return o.val.genericToPrimitive() 444 } 445 446 func (o *baseDynamicObject) assertCallable() (call func(FunctionCall) Value, ok bool) { 447 return nil, false 448 } 449 450 func (*baseDynamicObject) assertConstructor() func(args []Value, newTarget *Object) *Object { 451 return nil 452 } 453 454 func (o *baseDynamicObject) proto() *Object { 455 return o.prototype 456 } 457 458 func (o *baseDynamicObject) setProto(proto *Object, throw bool) bool { 459 o.prototype = proto 460 return true 461 } 462 463 func (o *baseDynamicObject) hasInstance(v Value) bool { 464 panic(newTypeError("Expecting a function in instanceof check, but got a dynamic object")) 465 } 466 467 func (*baseDynamicObject) isExtensible() bool { 468 return true 469 } 470 471 func (o *baseDynamicObject) preventExtensions(throw bool) bool { 472 typeErrorResult(throw, "Cannot make a dynamic object non-extensible") 473 return false 474 } 475 476 type dynamicObjectPropIter struct { 477 o *dynamicObject 478 propNames []string 479 idx int 480 } 481 482 func (i *dynamicObjectPropIter) next() (propIterItem, iterNextFunc) { 483 for i.idx < len(i.propNames) { 484 name := i.propNames[i.idx] 485 i.idx++ 486 if i.o.d.Has(name) { 487 return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next 488 } 489 } 490 return propIterItem{}, nil 491 } 492 493 func (o *dynamicObject) iterateStringKeys() iterNextFunc { 494 keys := o.d.Keys() 495 return (&dynamicObjectPropIter{ 496 o: o, 497 propNames: keys, 498 }).next 499 } 500 501 func (o *baseDynamicObject) iterateSymbols() iterNextFunc { 502 return func() (propIterItem, iterNextFunc) { 503 return propIterItem{}, nil 504 } 505 } 506 507 func (o *dynamicObject) iterateKeys() iterNextFunc { 508 return o.iterateStringKeys() 509 } 510 511 func (o *dynamicObject) export(ctx *objectExportCtx) interface{} { 512 return o.d 513 } 514 515 func (o *dynamicObject) exportType() reflect.Type { 516 return reflect.TypeOf(o.d) 517 } 518 519 func (o *baseDynamicObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error { 520 return genericExportToMap(o.val, dst, typ, ctx) 521 } 522 523 func (o *baseDynamicObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error { 524 return genericExportToArrayOrSlice(o.val, dst, typ, ctx) 525 } 526 527 func (o *dynamicObject) equal(impl objectImpl) bool { 528 if other, ok := impl.(*dynamicObject); ok { 529 return o.d == other.d 530 } 531 return false 532 } 533 534 func (o *dynamicObject) stringKeys(all bool, accum []Value) []Value { 535 keys := o.d.Keys() 536 if l := len(accum) + len(keys); l > cap(accum) { 537 oldAccum := accum 538 accum = make([]Value, len(accum), l) 539 copy(accum, oldAccum) 540 } 541 for _, key := range keys { 542 accum = append(accum, newStringValue(key)) 543 } 544 return accum 545 } 546 547 func (*baseDynamicObject) symbols(all bool, accum []Value) []Value { 548 return accum 549 } 550 551 func (o *dynamicObject) keys(all bool, accum []Value) []Value { 552 return o.stringKeys(all, accum) 553 } 554 555 func (*baseDynamicObject) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value { 556 return nil 557 } 558 559 func (*baseDynamicObject) _putSym(s *Symbol, prop Value) { 560 } 561 562 func (o *baseDynamicObject) getPrivateEnv(*privateEnvType, bool) *privateElements { 563 panic(newTypeError("Dynamic objects cannot have private elements")) 564 } 565 566 func (a *dynamicArray) sortLen() int { 567 return a.a.Len() 568 } 569 570 func (a *dynamicArray) sortGet(i int) Value { 571 return a.a.Get(i) 572 } 573 574 func (a *dynamicArray) swap(i int, j int) { 575 x := a.sortGet(i) 576 y := a.sortGet(j) 577 a.a.Set(int(i), y) 578 a.a.Set(int(j), x) 579 } 580 581 func (a *dynamicArray) className() string { 582 return classArray 583 } 584 585 func (a *dynamicArray) getStr(p unistring.String, receiver Value) Value { 586 if p == "length" { 587 return intToValue(int64(a.a.Len())) 588 } 589 if idx, ok := strToInt(p); ok { 590 return a.a.Get(idx) 591 } 592 return a.getParentStr(p, receiver) 593 } 594 595 func (a *dynamicArray) getIdx(p valueInt, receiver Value) Value { 596 if val := a.getOwnPropIdx(p); val != nil { 597 return val 598 } 599 return a.getParentIdx(p, receiver) 600 } 601 602 func (a *dynamicArray) getOwnPropStr(u unistring.String) Value { 603 if u == "length" { 604 return &valueProperty{ 605 value: intToValue(int64(a.a.Len())), 606 writable: true, 607 } 608 } 609 if idx, ok := strToInt(u); ok { 610 return a.a.Get(idx) 611 } 612 return nil 613 } 614 615 func (a *dynamicArray) getOwnPropIdx(v valueInt) Value { 616 return a.a.Get(toIntStrict(int64(v))) 617 } 618 619 func (a *dynamicArray) _setLen(v Value, throw bool) bool { 620 if a.a.SetLen(toIntStrict(v.ToInteger())) { 621 return true 622 } 623 typeErrorResult(throw, "'SetLen' on a dynamic array returned false") 624 return false 625 } 626 627 func (a *dynamicArray) setOwnStr(p unistring.String, v Value, throw bool) bool { 628 if p == "length" { 629 return a._setLen(v, throw) 630 } 631 if idx, ok := strToInt(p); ok { 632 return a._setIdx(idx, v, throw) 633 } 634 typeErrorResult(throw, "Cannot set property %q on a dynamic array", p.String()) 635 return false 636 } 637 638 func (a *dynamicArray) _setIdx(idx int, v Value, throw bool) bool { 639 if a.a.Set(idx, v) { 640 return true 641 } 642 typeErrorResult(throw, "'Set' on a dynamic array returned false") 643 return false 644 } 645 646 func (a *dynamicArray) setOwnIdx(p valueInt, v Value, throw bool) bool { 647 return a._setIdx(toIntStrict(int64(p)), v, throw) 648 } 649 650 func (a *dynamicArray) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) { 651 return a.setParentForeignStr(p, v, receiver, throw) 652 } 653 654 func (a *dynamicArray) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) { 655 return a.setParentForeignIdx(p, v, receiver, throw) 656 } 657 658 func (a *dynamicArray) hasPropertyStr(u unistring.String) bool { 659 if a.hasOwnPropertyStr(u) { 660 return true 661 } 662 if proto := a.prototype; proto != nil { 663 return proto.self.hasPropertyStr(u) 664 } 665 return false 666 } 667 668 func (a *dynamicArray) hasPropertyIdx(idx valueInt) bool { 669 if a.hasOwnPropertyIdx(idx) { 670 return true 671 } 672 if proto := a.prototype; proto != nil { 673 return proto.self.hasPropertyIdx(idx) 674 } 675 return false 676 } 677 678 func (a *dynamicArray) _has(idx int) bool { 679 return idx >= 0 && idx < a.a.Len() 680 } 681 682 func (a *dynamicArray) hasOwnPropertyStr(u unistring.String) bool { 683 if u == "length" { 684 return true 685 } 686 if idx, ok := strToInt(u); ok { 687 return a._has(idx) 688 } 689 return false 690 } 691 692 func (a *dynamicArray) hasOwnPropertyIdx(v valueInt) bool { 693 return a._has(toIntStrict(int64(v))) 694 } 695 696 func (a *dynamicArray) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool { 697 if a.checkDynamicObjectPropertyDescr(name, desc, throw) { 698 if idx, ok := strToInt(name); ok { 699 return a._setIdx(idx, desc.Value, throw) 700 } 701 typeErrorResult(throw, "Cannot define property %q on a dynamic array", name.String()) 702 } 703 return false 704 } 705 706 func (a *dynamicArray) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool { 707 if a.checkDynamicObjectPropertyDescr(name, desc, throw) { 708 return a._setIdx(toIntStrict(int64(name)), desc.Value, throw) 709 } 710 return false 711 } 712 713 func (a *dynamicArray) _delete(idx int, throw bool) bool { 714 if a._has(idx) { 715 a._setIdx(idx, _undefined, throw) 716 } 717 return true 718 } 719 720 func (a *dynamicArray) deleteStr(name unistring.String, throw bool) bool { 721 if idx, ok := strToInt(name); ok { 722 return a._delete(idx, throw) 723 } 724 if a.hasOwnPropertyStr(name) { 725 typeErrorResult(throw, "Cannot delete property %q on a dynamic array", name.String()) 726 return false 727 } 728 return true 729 } 730 731 func (a *dynamicArray) deleteIdx(idx valueInt, throw bool) bool { 732 return a._delete(toIntStrict(int64(idx)), throw) 733 } 734 735 type dynArrayPropIter struct { 736 a DynamicArray 737 idx, limit int 738 } 739 740 func (i *dynArrayPropIter) next() (propIterItem, iterNextFunc) { 741 if i.idx < i.limit && i.idx < i.a.Len() { 742 name := strconv.Itoa(i.idx) 743 i.idx++ 744 return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next 745 } 746 747 return propIterItem{}, nil 748 } 749 750 func (a *dynamicArray) iterateStringKeys() iterNextFunc { 751 return (&dynArrayPropIter{ 752 a: a.a, 753 limit: a.a.Len(), 754 }).next 755 } 756 757 func (a *dynamicArray) iterateKeys() iterNextFunc { 758 return a.iterateStringKeys() 759 } 760 761 func (a *dynamicArray) export(ctx *objectExportCtx) interface{} { 762 return a.a 763 } 764 765 func (a *dynamicArray) exportType() reflect.Type { 766 return reflect.TypeOf(a.a) 767 } 768 769 func (a *dynamicArray) equal(impl objectImpl) bool { 770 if other, ok := impl.(*dynamicArray); ok { 771 return a == other 772 } 773 return false 774 } 775 776 func (a *dynamicArray) stringKeys(all bool, accum []Value) []Value { 777 al := a.a.Len() 778 l := len(accum) + al 779 if all { 780 l++ 781 } 782 if l > cap(accum) { 783 oldAccum := accum 784 accum = make([]Value, len(oldAccum), l) 785 copy(accum, oldAccum) 786 } 787 for i := 0; i < al; i++ { 788 accum = append(accum, asciiString(strconv.Itoa(i))) 789 } 790 if all { 791 accum = append(accum, asciiString("length")) 792 } 793 return accum 794 } 795 796 func (a *dynamicArray) keys(all bool, accum []Value) []Value { 797 return a.stringKeys(all, accum) 798 }