object_dynamic.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. package goja
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strconv"
  6. "github.com/dop251/goja/unistring"
  7. )
  8. /*
  9. DynamicObject is an interface representing a handler for a dynamic Object. Such an object can be created
  10. using the Runtime.NewDynamicObject() method.
  11. Note that Runtime.ToValue() does not have any special treatment for DynamicObject. The only way to create
  12. a dynamic object is by using the Runtime.NewDynamicObject() method. This is done deliberately to avoid
  13. silent code breaks when this interface changes.
  14. */
  15. type DynamicObject interface {
  16. // Get a property value for the key. May return nil if the property does not exist.
  17. Get(key string) Value
  18. // Set a property value for the key. Return true if success, false otherwise.
  19. Set(key string, val Value) bool
  20. // Has should return true if and only if the property exists.
  21. Has(key string) bool
  22. // Delete the property for the key. Returns true on success (note, that includes missing property).
  23. Delete(key string) bool
  24. // Keys returns a list of all existing property keys. There are no checks for duplicates or to make sure
  25. // that the order conforms to https://262.ecma-international.org/#sec-ordinaryownpropertykeys
  26. Keys() []string
  27. }
  28. /*
  29. DynamicArray is an interface representing a handler for a dynamic array Object. Such an object can be created
  30. using the Runtime.NewDynamicArray() method.
  31. Any integer property key or a string property key that can be parsed into an int value (including negative
  32. ones) is treated as an index and passed to the trap methods of the DynamicArray. Note this is different from
  33. the regular ECMAScript arrays which only support positive indexes up to 2^32-1.
  34. DynamicArray cannot be sparse, i.e. hasOwnProperty(num) will return true for num >= 0 && num < Len(). Deleting
  35. such a property is equivalent to setting it to undefined. Note that this creates a slight peculiarity because
  36. hasOwnProperty() will still return true, even after deletion.
  37. Note that Runtime.ToValue() does not have any special treatment for DynamicArray. The only way to create
  38. a dynamic array is by using the Runtime.NewDynamicArray() method. This is done deliberately to avoid
  39. silent code breaks when this interface changes.
  40. */
  41. type DynamicArray interface {
  42. // Len returns the current array length.
  43. Len() int
  44. // Get an item at index idx. Note that idx may be any integer, negative or beyond the current length.
  45. Get(idx int) Value
  46. // Set an item at index idx. Note that idx may be any integer, negative or beyond the current length.
  47. // The expected behaviour when it's beyond length is that the array's length is increased to accommodate
  48. // the item. All elements in the 'new' section of the array should be zeroed.
  49. Set(idx int, val Value) bool
  50. // SetLen is called when the array's 'length' property is changed. If the length is increased all elements in the
  51. // 'new' section of the array should be zeroed.
  52. SetLen(int) bool
  53. }
  54. type baseDynamicObject struct {
  55. val *Object
  56. prototype *Object
  57. }
  58. type dynamicObject struct {
  59. baseDynamicObject
  60. d DynamicObject
  61. }
  62. type dynamicArray struct {
  63. baseDynamicObject
  64. a DynamicArray
  65. }
  66. /*
  67. NewDynamicObject creates an Object backed by the provided DynamicObject handler.
  68. All properties of this Object are Writable, Enumerable and Configurable data properties. Any attempt to define
  69. a property that does not conform to this will fail.
  70. The Object is always extensible and cannot be made non-extensible. Object.preventExtensions() will fail.
  71. The Object's prototype is initially set to Object.prototype, but can be changed using regular mechanisms
  72. (Object.SetPrototype() in Go or Object.setPrototypeOf() in JS).
  73. The Object cannot have own Symbol properties, however its prototype can. If you need an iterator support for
  74. example, you could create a regular object, set Symbol.iterator on that object and then use it as a
  75. prototype. See TestDynamicObjectCustomProto for more details.
  76. Export() returns the original DynamicObject.
  77. This mechanism is similar to ECMAScript Proxy, however because all properties are enumerable and the object
  78. is always extensible there is no need for invariant checks which removes the need to have a target object and
  79. makes it a lot more efficient.
  80. */
  81. func (r *Runtime) NewDynamicObject(d DynamicObject) *Object {
  82. v := &Object{runtime: r}
  83. o := &dynamicObject{
  84. d: d,
  85. baseDynamicObject: baseDynamicObject{
  86. val: v,
  87. prototype: r.global.ObjectPrototype,
  88. },
  89. }
  90. v.self = o
  91. return v
  92. }
  93. /*
  94. NewDynamicArray creates an array Object backed by the provided DynamicArray handler.
  95. It is similar to NewDynamicObject, the differences are:
  96. - the Object is an array (i.e. Array.isArray() will return true and it will have the length property).
  97. - the prototype will be initially set to Array.prototype.
  98. - the Object cannot have any own string properties except for the 'length'.
  99. */
  100. func (r *Runtime) NewDynamicArray(a DynamicArray) *Object {
  101. v := &Object{runtime: r}
  102. o := &dynamicArray{
  103. a: a,
  104. baseDynamicObject: baseDynamicObject{
  105. val: v,
  106. prototype: r.global.ArrayPrototype,
  107. },
  108. }
  109. v.self = o
  110. return v
  111. }
  112. func (*dynamicObject) sortLen() int64 {
  113. return 0
  114. }
  115. func (*dynamicObject) sortGet(i int64) Value {
  116. return nil
  117. }
  118. func (*dynamicObject) swap(i int64, i2 int64) {
  119. }
  120. func (*dynamicObject) className() string {
  121. return classObject
  122. }
  123. func (o *baseDynamicObject) getParentStr(p unistring.String, receiver Value) Value {
  124. if proto := o.prototype; proto != nil {
  125. if receiver == nil {
  126. return proto.self.getStr(p, o.val)
  127. }
  128. return proto.self.getStr(p, receiver)
  129. }
  130. return nil
  131. }
  132. func (o *dynamicObject) getStr(p unistring.String, receiver Value) Value {
  133. prop := o.d.Get(p.String())
  134. if prop == nil {
  135. return o.getParentStr(p, receiver)
  136. }
  137. return prop
  138. }
  139. func (o *baseDynamicObject) getParentIdx(p valueInt, receiver Value) Value {
  140. if proto := o.prototype; proto != nil {
  141. if receiver == nil {
  142. return proto.self.getIdx(p, o.val)
  143. }
  144. return proto.self.getIdx(p, receiver)
  145. }
  146. return nil
  147. }
  148. func (o *dynamicObject) getIdx(p valueInt, receiver Value) Value {
  149. prop := o.d.Get(p.String())
  150. if prop == nil {
  151. return o.getParentIdx(p, receiver)
  152. }
  153. return prop
  154. }
  155. func (o *baseDynamicObject) getSym(p *Symbol, receiver Value) Value {
  156. if proto := o.prototype; proto != nil {
  157. if receiver == nil {
  158. return proto.self.getSym(p, o.val)
  159. }
  160. return proto.self.getSym(p, receiver)
  161. }
  162. return nil
  163. }
  164. func (o *dynamicObject) getOwnPropStr(u unistring.String) Value {
  165. return o.d.Get(u.String())
  166. }
  167. func (o *dynamicObject) getOwnPropIdx(v valueInt) Value {
  168. return o.d.Get(v.String())
  169. }
  170. func (*baseDynamicObject) getOwnPropSym(*Symbol) Value {
  171. return nil
  172. }
  173. func (o *dynamicObject) _set(prop string, v Value, throw bool) bool {
  174. if o.d.Set(prop, v) {
  175. return true
  176. }
  177. o.val.runtime.typeErrorResult(throw, "'Set' on a dynamic object returned false")
  178. return false
  179. }
  180. func (o *baseDynamicObject) _setSym(throw bool) {
  181. o.val.runtime.typeErrorResult(throw, "Dynamic objects do not support Symbol properties")
  182. }
  183. func (o *dynamicObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
  184. prop := p.String()
  185. if !o.d.Has(prop) {
  186. if proto := o.prototype; proto != nil {
  187. // we know it's foreign because prototype loops are not allowed
  188. if res, handled := proto.self.setForeignStr(p, v, o.val, throw); handled {
  189. return res
  190. }
  191. }
  192. }
  193. return o._set(prop, v, throw)
  194. }
  195. func (o *dynamicObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
  196. prop := p.String()
  197. if !o.d.Has(prop) {
  198. if proto := o.prototype; proto != nil {
  199. // we know it's foreign because prototype loops are not allowed
  200. if res, handled := proto.self.setForeignIdx(p, v, o.val, throw); handled {
  201. return res
  202. }
  203. }
  204. }
  205. return o._set(prop, v, throw)
  206. }
  207. func (o *baseDynamicObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
  208. if proto := o.prototype; proto != nil {
  209. // we know it's foreign because prototype loops are not allowed
  210. if res, handled := proto.self.setForeignSym(s, v, o.val, throw); handled {
  211. return res
  212. }
  213. }
  214. o._setSym(throw)
  215. return false
  216. }
  217. func (o *baseDynamicObject) setParentForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
  218. if proto := o.prototype; proto != nil {
  219. if receiver != proto {
  220. return proto.self.setForeignStr(p, v, receiver, throw)
  221. }
  222. return proto.self.setOwnStr(p, v, throw), true
  223. }
  224. return false, false
  225. }
  226. func (o *dynamicObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
  227. prop := p.String()
  228. if !o.d.Has(prop) {
  229. return o.setParentForeignStr(p, v, receiver, throw)
  230. }
  231. return false, false
  232. }
  233. func (o *baseDynamicObject) setParentForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
  234. if proto := o.prototype; proto != nil {
  235. if receiver != proto {
  236. return proto.self.setForeignIdx(p, v, receiver, throw)
  237. }
  238. return proto.self.setOwnIdx(p, v, throw), true
  239. }
  240. return false, false
  241. }
  242. func (o *dynamicObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
  243. prop := p.String()
  244. if !o.d.Has(prop) {
  245. return o.setParentForeignIdx(p, v, receiver, throw)
  246. }
  247. return false, false
  248. }
  249. func (o *baseDynamicObject) setForeignSym(p *Symbol, v, receiver Value, throw bool) (res bool, handled bool) {
  250. if proto := o.prototype; proto != nil {
  251. if receiver != proto {
  252. return proto.self.setForeignSym(p, v, receiver, throw)
  253. }
  254. return proto.self.setOwnSym(p, v, throw), true
  255. }
  256. return false, false
  257. }
  258. func (o *dynamicObject) hasPropertyStr(u unistring.String) bool {
  259. if o.hasOwnPropertyStr(u) {
  260. return true
  261. }
  262. if proto := o.prototype; proto != nil {
  263. return proto.self.hasPropertyStr(u)
  264. }
  265. return false
  266. }
  267. func (o *dynamicObject) hasPropertyIdx(idx valueInt) bool {
  268. if o.hasOwnPropertyIdx(idx) {
  269. return true
  270. }
  271. if proto := o.prototype; proto != nil {
  272. return proto.self.hasPropertyIdx(idx)
  273. }
  274. return false
  275. }
  276. func (o *baseDynamicObject) hasPropertySym(s *Symbol) bool {
  277. if proto := o.prototype; proto != nil {
  278. return proto.self.hasPropertySym(s)
  279. }
  280. return false
  281. }
  282. func (o *dynamicObject) hasOwnPropertyStr(u unistring.String) bool {
  283. return o.d.Has(u.String())
  284. }
  285. func (o *dynamicObject) hasOwnPropertyIdx(v valueInt) bool {
  286. return o.d.Has(v.String())
  287. }
  288. func (*baseDynamicObject) hasOwnPropertySym(_ *Symbol) bool {
  289. return false
  290. }
  291. func (o *baseDynamicObject) checkDynamicObjectPropertyDescr(name fmt.Stringer, descr PropertyDescriptor, throw bool) bool {
  292. if descr.Getter != nil || descr.Setter != nil {
  293. o.val.runtime.typeErrorResult(throw, "Dynamic objects do not support accessor properties")
  294. return false
  295. }
  296. if descr.Writable == FLAG_FALSE {
  297. o.val.runtime.typeErrorResult(throw, "Dynamic object field %q cannot be made read-only", name.String())
  298. return false
  299. }
  300. if descr.Enumerable == FLAG_FALSE {
  301. o.val.runtime.typeErrorResult(throw, "Dynamic object field %q cannot be made non-enumerable", name.String())
  302. return false
  303. }
  304. if descr.Configurable == FLAG_FALSE {
  305. o.val.runtime.typeErrorResult(throw, "Dynamic object field %q cannot be made non-configurable", name.String())
  306. return false
  307. }
  308. return true
  309. }
  310. func (o *dynamicObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
  311. if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
  312. return o._set(name.String(), desc.Value, throw)
  313. }
  314. return false
  315. }
  316. func (o *dynamicObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
  317. if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
  318. return o._set(name.String(), desc.Value, throw)
  319. }
  320. return false
  321. }
  322. func (o *baseDynamicObject) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
  323. o._setSym(throw)
  324. return false
  325. }
  326. func (o *dynamicObject) _delete(prop string, throw bool) bool {
  327. if o.d.Delete(prop) {
  328. return true
  329. }
  330. o.val.runtime.typeErrorResult(throw, "Could not delete property %q of a dynamic object", prop)
  331. return false
  332. }
  333. func (o *dynamicObject) deleteStr(name unistring.String, throw bool) bool {
  334. return o._delete(name.String(), throw)
  335. }
  336. func (o *dynamicObject) deleteIdx(idx valueInt, throw bool) bool {
  337. return o._delete(idx.String(), throw)
  338. }
  339. func (*baseDynamicObject) deleteSym(_ *Symbol, _ bool) bool {
  340. return true
  341. }
  342. func (o *baseDynamicObject) toPrimitiveNumber() Value {
  343. return o.val.genericToPrimitiveNumber()
  344. }
  345. func (o *baseDynamicObject) toPrimitiveBigInt() Value {
  346. return o.val.genericToPrimitiveBigInt()
  347. }
  348. func (o *baseDynamicObject) toPrimitiveString() Value {
  349. return o.val.genericToPrimitiveString()
  350. }
  351. func (o *baseDynamicObject) toPrimitive() Value {
  352. return o.val.genericToPrimitive()
  353. }
  354. func (o *baseDynamicObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
  355. return nil, false
  356. }
  357. func (*baseDynamicObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
  358. return nil
  359. }
  360. func (o *baseDynamicObject) proto() *Object {
  361. return o.prototype
  362. }
  363. func (o *baseDynamicObject) setProto(proto *Object, throw bool) bool {
  364. o.prototype = proto
  365. return true
  366. }
  367. func (o *baseDynamicObject) hasInstance(v Value) bool {
  368. panic(o.val.runtime.NewTypeError("Expecting a function in instanceof check, but got a dynamic object"))
  369. }
  370. func (*baseDynamicObject) isExtensible() bool {
  371. return true
  372. }
  373. func (o *baseDynamicObject) preventExtensions(throw bool) bool {
  374. o.val.runtime.typeErrorResult(throw, "Cannot make a dynamic object non-extensible")
  375. return false
  376. }
  377. type dynamicObjectPropIter struct {
  378. o *dynamicObject
  379. propNames []string
  380. idx int
  381. }
  382. func (i *dynamicObjectPropIter) next() (propIterItem, iterNextFunc) {
  383. for i.idx < len(i.propNames) {
  384. name := i.propNames[i.idx]
  385. i.idx++
  386. if i.o.d.Has(name) {
  387. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
  388. }
  389. }
  390. return propIterItem{}, nil
  391. }
  392. func (o *dynamicObject) iterateStringKeys() iterNextFunc {
  393. keys := o.d.Keys()
  394. return (&dynamicObjectPropIter{
  395. o: o,
  396. propNames: keys,
  397. }).next
  398. }
  399. func (o *baseDynamicObject) iterateSymbols() iterNextFunc {
  400. return func() (propIterItem, iterNextFunc) {
  401. return propIterItem{}, nil
  402. }
  403. }
  404. func (o *dynamicObject) iterateKeys() iterNextFunc {
  405. return o.iterateStringKeys()
  406. }
  407. func (o *dynamicObject) export(ctx *objectExportCtx) interface{} {
  408. return o.d
  409. }
  410. func (o *dynamicObject) exportType() reflect.Type {
  411. return reflect.TypeOf(o.d)
  412. }
  413. func (o *dynamicObject) equal(impl objectImpl) bool {
  414. if other, ok := impl.(*dynamicObject); ok {
  415. return o.d == other.d
  416. }
  417. return false
  418. }
  419. func (o *dynamicObject) stringKeys(all bool, accum []Value) []Value {
  420. keys := o.d.Keys()
  421. if l := len(accum) + len(keys); l > cap(accum) {
  422. oldAccum := accum
  423. accum = make([]Value, len(accum), l)
  424. copy(accum, oldAccum)
  425. }
  426. for _, key := range keys {
  427. accum = append(accum, newStringValue(key))
  428. }
  429. return accum
  430. }
  431. func (*baseDynamicObject) symbols(all bool, accum []Value) []Value {
  432. return accum
  433. }
  434. func (o *dynamicObject) keys(all bool, accum []Value) []Value {
  435. return o.stringKeys(all, accum)
  436. }
  437. func (*baseDynamicObject) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
  438. return nil
  439. }
  440. func (*baseDynamicObject) _putSym(s *Symbol, prop Value) {
  441. }
  442. func (a *dynamicArray) sortLen() int64 {
  443. return int64(a.a.Len())
  444. }
  445. func (a *dynamicArray) sortGet(i int64) Value {
  446. return a.a.Get(int(i))
  447. }
  448. func (a *dynamicArray) swap(i int64, j int64) {
  449. x := a.sortGet(i)
  450. y := a.sortGet(j)
  451. a.a.Set(int(i), y)
  452. a.a.Set(int(j), x)
  453. }
  454. func (a *dynamicArray) className() string {
  455. return classArray
  456. }
  457. func (a *dynamicArray) getStr(p unistring.String, receiver Value) Value {
  458. if p == "length" {
  459. return intToValue(int64(a.a.Len()))
  460. }
  461. if idx, ok := strToInt(p); ok {
  462. return a.a.Get(idx)
  463. }
  464. return a.getParentStr(p, receiver)
  465. }
  466. func (a *dynamicArray) getIdx(p valueInt, receiver Value) Value {
  467. if val := a.getOwnPropIdx(p); val != nil {
  468. return val
  469. }
  470. return a.getParentIdx(p, receiver)
  471. }
  472. func (a *dynamicArray) getOwnPropStr(u unistring.String) Value {
  473. if u == "length" {
  474. return &valueProperty{
  475. value: intToValue(int64(a.a.Len())),
  476. writable: true,
  477. }
  478. }
  479. if idx, ok := strToInt(u); ok {
  480. return a.a.Get(idx)
  481. }
  482. return nil
  483. }
  484. func (a *dynamicArray) getOwnPropIdx(v valueInt) Value {
  485. return a.a.Get(toIntStrict(int64(v)))
  486. }
  487. func (a *dynamicArray) _setLen(v Value, throw bool) bool {
  488. if a.a.SetLen(toIntStrict(v.ToInteger())) {
  489. return true
  490. }
  491. a.val.runtime.typeErrorResult(throw, "'SetLen' on a dynamic array returned false")
  492. return false
  493. }
  494. func (a *dynamicArray) setOwnStr(p unistring.String, v Value, throw bool) bool {
  495. if p == "length" {
  496. return a._setLen(v, throw)
  497. }
  498. if idx, ok := strToInt(p); ok {
  499. return a._setIdx(idx, v, throw)
  500. }
  501. a.val.runtime.typeErrorResult(throw, "Cannot set property %q on a dynamic array", p.String())
  502. return false
  503. }
  504. func (a *dynamicArray) _setIdx(idx int, v Value, throw bool) bool {
  505. if a.a.Set(idx, v) {
  506. return true
  507. }
  508. a.val.runtime.typeErrorResult(throw, "'Set' on a dynamic array returned false")
  509. return false
  510. }
  511. func (a *dynamicArray) setOwnIdx(p valueInt, v Value, throw bool) bool {
  512. return a._setIdx(toIntStrict(int64(p)), v, throw)
  513. }
  514. func (a *dynamicArray) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
  515. return a.setParentForeignStr(p, v, receiver, throw)
  516. }
  517. func (a *dynamicArray) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
  518. return a.setParentForeignIdx(p, v, receiver, throw)
  519. }
  520. func (a *dynamicArray) hasPropertyStr(u unistring.String) bool {
  521. if a.hasOwnPropertyStr(u) {
  522. return true
  523. }
  524. if proto := a.prototype; proto != nil {
  525. return proto.self.hasPropertyStr(u)
  526. }
  527. return false
  528. }
  529. func (a *dynamicArray) hasPropertyIdx(idx valueInt) bool {
  530. if a.hasOwnPropertyIdx(idx) {
  531. return true
  532. }
  533. if proto := a.prototype; proto != nil {
  534. return proto.self.hasPropertyIdx(idx)
  535. }
  536. return false
  537. }
  538. func (a *dynamicArray) _has(idx int) bool {
  539. return idx >= 0 && idx < a.a.Len()
  540. }
  541. func (a *dynamicArray) hasOwnPropertyStr(u unistring.String) bool {
  542. if u == "length" {
  543. return true
  544. }
  545. if idx, ok := strToInt(u); ok {
  546. return a._has(idx)
  547. }
  548. return false
  549. }
  550. func (a *dynamicArray) hasOwnPropertyIdx(v valueInt) bool {
  551. return a._has(toIntStrict(int64(v)))
  552. }
  553. func (a *dynamicArray) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
  554. if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
  555. if idx, ok := strToInt(name); ok {
  556. return a._setIdx(idx, desc.Value, throw)
  557. }
  558. a.val.runtime.typeErrorResult(throw, "Cannot define property %q on a dynamic array", name.String())
  559. }
  560. return false
  561. }
  562. func (a *dynamicArray) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
  563. if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
  564. return a._setIdx(toIntStrict(int64(name)), desc.Value, throw)
  565. }
  566. return false
  567. }
  568. func (a *dynamicArray) _delete(idx int, throw bool) bool {
  569. if a._has(idx) {
  570. a._setIdx(idx, _undefined, throw)
  571. }
  572. return true
  573. }
  574. func (a *dynamicArray) deleteStr(name unistring.String, throw bool) bool {
  575. if idx, ok := strToInt(name); ok {
  576. return a._delete(idx, throw)
  577. }
  578. if a.hasOwnPropertyStr(name) {
  579. a.val.runtime.typeErrorResult(throw, "Cannot delete property %q on a dynamic array", name.String())
  580. return false
  581. }
  582. return true
  583. }
  584. func (a *dynamicArray) deleteIdx(idx valueInt, throw bool) bool {
  585. return a._delete(toIntStrict(int64(idx)), throw)
  586. }
  587. type dynArrayPropIter struct {
  588. a DynamicArray
  589. idx, limit int
  590. }
  591. func (i *dynArrayPropIter) next() (propIterItem, iterNextFunc) {
  592. if i.idx < i.limit && i.idx < i.a.Len() {
  593. name := strconv.Itoa(i.idx)
  594. i.idx++
  595. return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
  596. }
  597. return propIterItem{}, nil
  598. }
  599. func (a *dynamicArray) iterateStringKeys() iterNextFunc {
  600. return (&dynArrayPropIter{
  601. a: a.a,
  602. limit: a.a.Len(),
  603. }).next
  604. }
  605. func (a *dynamicArray) iterateKeys() iterNextFunc {
  606. return a.iterateStringKeys()
  607. }
  608. func (a *dynamicArray) export(ctx *objectExportCtx) interface{} {
  609. return a.a
  610. }
  611. func (a *dynamicArray) exportType() reflect.Type {
  612. return reflect.TypeOf(a.a)
  613. }
  614. func (a *dynamicArray) equal(impl objectImpl) bool {
  615. if other, ok := impl.(*dynamicArray); ok {
  616. return a == other
  617. }
  618. return false
  619. }
  620. func (a *dynamicArray) stringKeys(all bool, accum []Value) []Value {
  621. al := a.a.Len()
  622. l := len(accum) + al
  623. if all {
  624. l++
  625. }
  626. if l > cap(accum) {
  627. oldAccum := accum
  628. accum = make([]Value, len(oldAccum), l)
  629. copy(accum, oldAccum)
  630. }
  631. for i := 0; i < al; i++ {
  632. accum = append(accum, asciiString(strconv.Itoa(i)))
  633. }
  634. if all {
  635. accum = append(accum, asciiString("length"))
  636. }
  637. return accum
  638. }
  639. func (a *dynamicArray) keys(all bool, accum []Value) []Value {
  640. return a.stringKeys(all, accum)
  641. }