object_dynamic.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  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. NewSharedDynamicObject is similar to Runtime.NewDynamicObject but the resulting Object can be shared across multiple
  95. Runtimes. The Object's prototype will be null. The provided DynamicObject must be goroutine-safe.
  96. */
  97. func NewSharedDynamicObject(d DynamicObject) *Object {
  98. v := &Object{}
  99. o := &dynamicObject{
  100. d: d,
  101. baseDynamicObject: baseDynamicObject{
  102. val: v,
  103. },
  104. }
  105. v.self = o
  106. return v
  107. }
  108. /*
  109. NewDynamicArray creates an array Object backed by the provided DynamicArray handler.
  110. It is similar to NewDynamicObject, the differences are:
  111. - the Object is an array (i.e. Array.isArray() will return true and it will have the length property).
  112. - the prototype will be initially set to Array.prototype.
  113. - the Object cannot have any own string properties except for the 'length'.
  114. */
  115. func (r *Runtime) NewDynamicArray(a DynamicArray) *Object {
  116. v := &Object{runtime: r}
  117. o := &dynamicArray{
  118. a: a,
  119. baseDynamicObject: baseDynamicObject{
  120. val: v,
  121. prototype: r.getArrayPrototype(),
  122. },
  123. }
  124. v.self = o
  125. return v
  126. }
  127. /*
  128. NewSharedDynamicArray is similar to Runtime.NewDynamicArray but the resulting Object can be shared across multiple
  129. Runtimes. The Object's prototype will be null. If you need to run Array's methods on it, use Array.prototype.[...].call(a, ...).
  130. The provided DynamicArray must be goroutine-safe.
  131. */
  132. func NewSharedDynamicArray(a DynamicArray) *Object {
  133. v := &Object{}
  134. o := &dynamicArray{
  135. a: a,
  136. baseDynamicObject: baseDynamicObject{
  137. val: v,
  138. },
  139. }
  140. v.self = o
  141. return v
  142. }
  143. func (*dynamicObject) sortLen() int {
  144. return 0
  145. }
  146. func (*dynamicObject) sortGet(i int) Value {
  147. return nil
  148. }
  149. func (*dynamicObject) swap(i int, i2 int) {
  150. }
  151. func (*dynamicObject) className() string {
  152. return classObject
  153. }
  154. func (o *baseDynamicObject) getParentStr(p unistring.String, receiver Value) Value {
  155. if proto := o.prototype; proto != nil {
  156. if receiver == nil {
  157. return proto.self.getStr(p, o.val)
  158. }
  159. return proto.self.getStr(p, receiver)
  160. }
  161. return nil
  162. }
  163. func (o *dynamicObject) getStr(p unistring.String, receiver Value) Value {
  164. prop := o.d.Get(p.String())
  165. if prop == nil {
  166. return o.getParentStr(p, receiver)
  167. }
  168. return prop
  169. }
  170. func (o *baseDynamicObject) getParentIdx(p valueInt, receiver Value) Value {
  171. if proto := o.prototype; proto != nil {
  172. if receiver == nil {
  173. return proto.self.getIdx(p, o.val)
  174. }
  175. return proto.self.getIdx(p, receiver)
  176. }
  177. return nil
  178. }
  179. func (o *dynamicObject) getIdx(p valueInt, receiver Value) Value {
  180. prop := o.d.Get(p.String())
  181. if prop == nil {
  182. return o.getParentIdx(p, receiver)
  183. }
  184. return prop
  185. }
  186. func (o *baseDynamicObject) getSym(p *Symbol, receiver Value) Value {
  187. if proto := o.prototype; proto != nil {
  188. if receiver == nil {
  189. return proto.self.getSym(p, o.val)
  190. }
  191. return proto.self.getSym(p, receiver)
  192. }
  193. return nil
  194. }
  195. func (o *dynamicObject) getOwnPropStr(u unistring.String) Value {
  196. return o.d.Get(u.String())
  197. }
  198. func (o *dynamicObject) getOwnPropIdx(v valueInt) Value {
  199. return o.d.Get(v.String())
  200. }
  201. func (*baseDynamicObject) getOwnPropSym(*Symbol) Value {
  202. return nil
  203. }
  204. func (o *dynamicObject) _set(prop string, v Value, throw bool) bool {
  205. if o.d.Set(prop, v) {
  206. return true
  207. }
  208. typeErrorResult(throw, "'Set' on a dynamic object returned false")
  209. return false
  210. }
  211. func (o *baseDynamicObject) _setSym(throw bool) {
  212. typeErrorResult(throw, "Dynamic objects do not support Symbol properties")
  213. }
  214. func (o *dynamicObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
  215. prop := p.String()
  216. if !o.d.Has(prop) {
  217. if proto := o.prototype; proto != nil {
  218. // we know it's foreign because prototype loops are not allowed
  219. if res, handled := proto.self.setForeignStr(p, v, o.val, throw); handled {
  220. return res
  221. }
  222. }
  223. }
  224. return o._set(prop, v, throw)
  225. }
  226. func (o *dynamicObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
  227. prop := p.String()
  228. if !o.d.Has(prop) {
  229. if proto := o.prototype; proto != nil {
  230. // we know it's foreign because prototype loops are not allowed
  231. if res, handled := proto.self.setForeignIdx(p, v, o.val, throw); handled {
  232. return res
  233. }
  234. }
  235. }
  236. return o._set(prop, v, throw)
  237. }
  238. func (o *baseDynamicObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
  239. if proto := o.prototype; proto != nil {
  240. // we know it's foreign because prototype loops are not allowed
  241. if res, handled := proto.self.setForeignSym(s, v, o.val, throw); handled {
  242. return res
  243. }
  244. }
  245. o._setSym(throw)
  246. return false
  247. }
  248. func (o *baseDynamicObject) setParentForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
  249. if proto := o.prototype; proto != nil {
  250. if receiver != proto {
  251. return proto.self.setForeignStr(p, v, receiver, throw)
  252. }
  253. return proto.self.setOwnStr(p, v, throw), true
  254. }
  255. return false, false
  256. }
  257. func (o *dynamicObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
  258. prop := p.String()
  259. if !o.d.Has(prop) {
  260. return o.setParentForeignStr(p, v, receiver, throw)
  261. }
  262. return false, false
  263. }
  264. func (o *baseDynamicObject) setParentForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
  265. if proto := o.prototype; proto != nil {
  266. if receiver != proto {
  267. return proto.self.setForeignIdx(p, v, receiver, throw)
  268. }
  269. return proto.self.setOwnIdx(p, v, throw), true
  270. }
  271. return false, false
  272. }
  273. func (o *dynamicObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
  274. prop := p.String()
  275. if !o.d.Has(prop) {
  276. return o.setParentForeignIdx(p, v, receiver, throw)
  277. }
  278. return false, false
  279. }
  280. func (o *baseDynamicObject) setForeignSym(p *Symbol, v, receiver Value, throw bool) (res bool, handled bool) {
  281. if proto := o.prototype; proto != nil {
  282. if receiver != proto {
  283. return proto.self.setForeignSym(p, v, receiver, throw)
  284. }
  285. return proto.self.setOwnSym(p, v, throw), true
  286. }
  287. return false, false
  288. }
  289. func (o *dynamicObject) hasPropertyStr(u unistring.String) bool {
  290. if o.hasOwnPropertyStr(u) {
  291. return true
  292. }
  293. if proto := o.prototype; proto != nil {
  294. return proto.self.hasPropertyStr(u)
  295. }
  296. return false
  297. }
  298. func (o *dynamicObject) hasPropertyIdx(idx valueInt) bool {
  299. if o.hasOwnPropertyIdx(idx) {
  300. return true
  301. }
  302. if proto := o.prototype; proto != nil {
  303. return proto.self.hasPropertyIdx(idx)
  304. }
  305. return false
  306. }
  307. func (o *baseDynamicObject) hasPropertySym(s *Symbol) bool {
  308. if proto := o.prototype; proto != nil {
  309. return proto.self.hasPropertySym(s)
  310. }
  311. return false
  312. }
  313. func (o *dynamicObject) hasOwnPropertyStr(u unistring.String) bool {
  314. return o.d.Has(u.String())
  315. }
  316. func (o *dynamicObject) hasOwnPropertyIdx(v valueInt) bool {
  317. return o.d.Has(v.String())
  318. }
  319. func (*baseDynamicObject) hasOwnPropertySym(_ *Symbol) bool {
  320. return false
  321. }
  322. func (o *baseDynamicObject) checkDynamicObjectPropertyDescr(name fmt.Stringer, descr PropertyDescriptor, throw bool) bool {
  323. if descr.Getter != nil || descr.Setter != nil {
  324. typeErrorResult(throw, "Dynamic objects do not support accessor properties")
  325. return false
  326. }
  327. if descr.Writable == FLAG_FALSE {
  328. typeErrorResult(throw, "Dynamic object field %q cannot be made read-only", name.String())
  329. return false
  330. }
  331. if descr.Enumerable == FLAG_FALSE {
  332. typeErrorResult(throw, "Dynamic object field %q cannot be made non-enumerable", name.String())
  333. return false
  334. }
  335. if descr.Configurable == FLAG_FALSE {
  336. typeErrorResult(throw, "Dynamic object field %q cannot be made non-configurable", name.String())
  337. return false
  338. }
  339. return true
  340. }
  341. func (o *dynamicObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
  342. if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
  343. return o._set(name.String(), desc.Value, throw)
  344. }
  345. return false
  346. }
  347. func (o *dynamicObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
  348. if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
  349. return o._set(name.String(), desc.Value, throw)
  350. }
  351. return false
  352. }
  353. func (o *baseDynamicObject) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
  354. o._setSym(throw)
  355. return false
  356. }
  357. func (o *dynamicObject) _delete(prop string, throw bool) bool {
  358. if o.d.Delete(prop) {
  359. return true
  360. }
  361. typeErrorResult(throw, "Could not delete property %q of a dynamic object", prop)
  362. return false
  363. }
  364. func (o *dynamicObject) deleteStr(name unistring.String, throw bool) bool {
  365. return o._delete(name.String(), throw)
  366. }
  367. func (o *dynamicObject) deleteIdx(idx valueInt, throw bool) bool {
  368. return o._delete(idx.String(), throw)
  369. }
  370. func (*baseDynamicObject) deleteSym(_ *Symbol, _ bool) bool {
  371. return true
  372. }
  373. func (o *baseDynamicObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
  374. return nil, false
  375. }
  376. func (o *baseDynamicObject) vmCall(vm *vm, n int) {
  377. panic(vm.r.NewTypeError("Dynamic object is not callable"))
  378. }
  379. func (*baseDynamicObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
  380. return nil
  381. }
  382. func (o *baseDynamicObject) proto() *Object {
  383. return o.prototype
  384. }
  385. func (o *baseDynamicObject) setProto(proto *Object, throw bool) bool {
  386. o.prototype = proto
  387. return true
  388. }
  389. func (o *baseDynamicObject) hasInstance(v Value) bool {
  390. panic(newTypeError("Expecting a function in instanceof check, but got a dynamic object"))
  391. }
  392. func (*baseDynamicObject) isExtensible() bool {
  393. return true
  394. }
  395. func (o *baseDynamicObject) preventExtensions(throw bool) bool {
  396. typeErrorResult(throw, "Cannot make a dynamic object non-extensible")
  397. return false
  398. }
  399. type dynamicObjectPropIter struct {
  400. o *dynamicObject
  401. propNames []string
  402. idx int
  403. }
  404. func (i *dynamicObjectPropIter) next() (propIterItem, iterNextFunc) {
  405. for i.idx < len(i.propNames) {
  406. name := i.propNames[i.idx]
  407. i.idx++
  408. if i.o.d.Has(name) {
  409. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
  410. }
  411. }
  412. return propIterItem{}, nil
  413. }
  414. func (o *dynamicObject) iterateStringKeys() iterNextFunc {
  415. keys := o.d.Keys()
  416. return (&dynamicObjectPropIter{
  417. o: o,
  418. propNames: keys,
  419. }).next
  420. }
  421. func (o *baseDynamicObject) iterateSymbols() iterNextFunc {
  422. return func() (propIterItem, iterNextFunc) {
  423. return propIterItem{}, nil
  424. }
  425. }
  426. func (o *dynamicObject) iterateKeys() iterNextFunc {
  427. return o.iterateStringKeys()
  428. }
  429. func (o *dynamicObject) export(ctx *objectExportCtx) interface{} {
  430. return o.d
  431. }
  432. func (o *dynamicObject) exportType() reflect.Type {
  433. return reflect.TypeOf(o.d)
  434. }
  435. func (o *baseDynamicObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
  436. return genericExportToMap(o.val, dst, typ, ctx)
  437. }
  438. func (o *baseDynamicObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
  439. return genericExportToArrayOrSlice(o.val, dst, typ, ctx)
  440. }
  441. func (o *dynamicObject) equal(impl objectImpl) bool {
  442. if other, ok := impl.(*dynamicObject); ok {
  443. return o.d == other.d
  444. }
  445. return false
  446. }
  447. func (o *dynamicObject) stringKeys(all bool, accum []Value) []Value {
  448. keys := o.d.Keys()
  449. if l := len(accum) + len(keys); l > cap(accum) {
  450. oldAccum := accum
  451. accum = make([]Value, len(accum), l)
  452. copy(accum, oldAccum)
  453. }
  454. for _, key := range keys {
  455. accum = append(accum, newStringValue(key))
  456. }
  457. return accum
  458. }
  459. func (*baseDynamicObject) symbols(all bool, accum []Value) []Value {
  460. return accum
  461. }
  462. func (o *dynamicObject) keys(all bool, accum []Value) []Value {
  463. return o.stringKeys(all, accum)
  464. }
  465. func (*baseDynamicObject) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
  466. return nil
  467. }
  468. func (*baseDynamicObject) _putSym(s *Symbol, prop Value) {
  469. }
  470. func (o *baseDynamicObject) getPrivateEnv(*privateEnvType, bool) *privateElements {
  471. panic(newTypeError("Dynamic objects cannot have private elements"))
  472. }
  473. func (o *baseDynamicObject) typeOf() String {
  474. return stringObjectC
  475. }
  476. func (a *dynamicArray) sortLen() int {
  477. return a.a.Len()
  478. }
  479. func (a *dynamicArray) sortGet(i int) Value {
  480. return a.a.Get(i)
  481. }
  482. func (a *dynamicArray) swap(i int, j int) {
  483. x := a.sortGet(i)
  484. y := a.sortGet(j)
  485. a.a.Set(int(i), y)
  486. a.a.Set(int(j), x)
  487. }
  488. func (a *dynamicArray) className() string {
  489. return classArray
  490. }
  491. func (a *dynamicArray) getStr(p unistring.String, receiver Value) Value {
  492. if p == "length" {
  493. return intToValue(int64(a.a.Len()))
  494. }
  495. if idx, ok := strToInt(p); ok {
  496. return a.a.Get(idx)
  497. }
  498. return a.getParentStr(p, receiver)
  499. }
  500. func (a *dynamicArray) getIdx(p valueInt, receiver Value) Value {
  501. if val := a.getOwnPropIdx(p); val != nil {
  502. return val
  503. }
  504. return a.getParentIdx(p, receiver)
  505. }
  506. func (a *dynamicArray) getOwnPropStr(u unistring.String) Value {
  507. if u == "length" {
  508. return &valueProperty{
  509. value: intToValue(int64(a.a.Len())),
  510. writable: true,
  511. }
  512. }
  513. if idx, ok := strToInt(u); ok {
  514. return a.a.Get(idx)
  515. }
  516. return nil
  517. }
  518. func (a *dynamicArray) getOwnPropIdx(v valueInt) Value {
  519. return a.a.Get(toIntStrict(int64(v)))
  520. }
  521. func (a *dynamicArray) _setLen(v Value, throw bool) bool {
  522. if a.a.SetLen(toIntStrict(v.ToInteger())) {
  523. return true
  524. }
  525. typeErrorResult(throw, "'SetLen' on a dynamic array returned false")
  526. return false
  527. }
  528. func (a *dynamicArray) setOwnStr(p unistring.String, v Value, throw bool) bool {
  529. if p == "length" {
  530. return a._setLen(v, throw)
  531. }
  532. if idx, ok := strToInt(p); ok {
  533. return a._setIdx(idx, v, throw)
  534. }
  535. typeErrorResult(throw, "Cannot set property %q on a dynamic array", p.String())
  536. return false
  537. }
  538. func (a *dynamicArray) _setIdx(idx int, v Value, throw bool) bool {
  539. if a.a.Set(idx, v) {
  540. return true
  541. }
  542. typeErrorResult(throw, "'Set' on a dynamic array returned false")
  543. return false
  544. }
  545. func (a *dynamicArray) setOwnIdx(p valueInt, v Value, throw bool) bool {
  546. return a._setIdx(toIntStrict(int64(p)), v, throw)
  547. }
  548. func (a *dynamicArray) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
  549. return a.setParentForeignStr(p, v, receiver, throw)
  550. }
  551. func (a *dynamicArray) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
  552. return a.setParentForeignIdx(p, v, receiver, throw)
  553. }
  554. func (a *dynamicArray) hasPropertyStr(u unistring.String) bool {
  555. if a.hasOwnPropertyStr(u) {
  556. return true
  557. }
  558. if proto := a.prototype; proto != nil {
  559. return proto.self.hasPropertyStr(u)
  560. }
  561. return false
  562. }
  563. func (a *dynamicArray) hasPropertyIdx(idx valueInt) bool {
  564. if a.hasOwnPropertyIdx(idx) {
  565. return true
  566. }
  567. if proto := a.prototype; proto != nil {
  568. return proto.self.hasPropertyIdx(idx)
  569. }
  570. return false
  571. }
  572. func (a *dynamicArray) _has(idx int) bool {
  573. return idx >= 0 && idx < a.a.Len()
  574. }
  575. func (a *dynamicArray) hasOwnPropertyStr(u unistring.String) bool {
  576. if u == "length" {
  577. return true
  578. }
  579. if idx, ok := strToInt(u); ok {
  580. return a._has(idx)
  581. }
  582. return false
  583. }
  584. func (a *dynamicArray) hasOwnPropertyIdx(v valueInt) bool {
  585. return a._has(toIntStrict(int64(v)))
  586. }
  587. func (a *dynamicArray) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
  588. if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
  589. if idx, ok := strToInt(name); ok {
  590. return a._setIdx(idx, desc.Value, throw)
  591. }
  592. typeErrorResult(throw, "Cannot define property %q on a dynamic array", name.String())
  593. }
  594. return false
  595. }
  596. func (a *dynamicArray) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
  597. if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
  598. return a._setIdx(toIntStrict(int64(name)), desc.Value, throw)
  599. }
  600. return false
  601. }
  602. func (a *dynamicArray) _delete(idx int, throw bool) bool {
  603. if a._has(idx) {
  604. a._setIdx(idx, _undefined, throw)
  605. }
  606. return true
  607. }
  608. func (a *dynamicArray) deleteStr(name unistring.String, throw bool) bool {
  609. if idx, ok := strToInt(name); ok {
  610. return a._delete(idx, throw)
  611. }
  612. if a.hasOwnPropertyStr(name) {
  613. typeErrorResult(throw, "Cannot delete property %q on a dynamic array", name.String())
  614. return false
  615. }
  616. return true
  617. }
  618. func (a *dynamicArray) deleteIdx(idx valueInt, throw bool) bool {
  619. return a._delete(toIntStrict(int64(idx)), throw)
  620. }
  621. type dynArrayPropIter struct {
  622. a DynamicArray
  623. idx, limit int
  624. }
  625. func (i *dynArrayPropIter) next() (propIterItem, iterNextFunc) {
  626. if i.idx < i.limit && i.idx < i.a.Len() {
  627. name := strconv.Itoa(i.idx)
  628. i.idx++
  629. return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
  630. }
  631. return propIterItem{}, nil
  632. }
  633. func (a *dynamicArray) iterateStringKeys() iterNextFunc {
  634. return (&dynArrayPropIter{
  635. a: a.a,
  636. limit: a.a.Len(),
  637. }).next
  638. }
  639. func (a *dynamicArray) iterateKeys() iterNextFunc {
  640. return a.iterateStringKeys()
  641. }
  642. func (a *dynamicArray) export(ctx *objectExportCtx) interface{} {
  643. return a.a
  644. }
  645. func (a *dynamicArray) exportType() reflect.Type {
  646. return reflect.TypeOf(a.a)
  647. }
  648. func (a *dynamicArray) equal(impl objectImpl) bool {
  649. if other, ok := impl.(*dynamicArray); ok {
  650. return a == other
  651. }
  652. return false
  653. }
  654. func (a *dynamicArray) stringKeys(all bool, accum []Value) []Value {
  655. al := a.a.Len()
  656. l := len(accum) + al
  657. if all {
  658. l++
  659. }
  660. if l > cap(accum) {
  661. oldAccum := accum
  662. accum = make([]Value, len(oldAccum), l)
  663. copy(accum, oldAccum)
  664. }
  665. for i := 0; i < al; i++ {
  666. accum = append(accum, asciiString(strconv.Itoa(i)))
  667. }
  668. if all {
  669. accum = append(accum, asciiString("length"))
  670. }
  671. return accum
  672. }
  673. func (a *dynamicArray) keys(all bool, accum []Value) []Value {
  674. return a.stringKeys(all, accum)
  675. }