builtin_array.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. package goja
  2. import (
  3. "bytes"
  4. "sort"
  5. "strings"
  6. )
  7. func (r *Runtime) builtin_newArray(args []Value, proto *Object) *Object {
  8. l := len(args)
  9. if l == 1 {
  10. if al, ok := args[0].assertInt(); ok {
  11. return r.newArrayLength(al)
  12. } else if f, ok := args[0].assertFloat(); ok {
  13. al := int64(f)
  14. if float64(al) == f {
  15. return r.newArrayLength(al)
  16. } else {
  17. panic(r.newError(r.global.RangeError, "Invalid array length"))
  18. }
  19. }
  20. return r.newArrayValues([]Value{args[0]})
  21. } else {
  22. argsCopy := make([]Value, l)
  23. copy(argsCopy, args)
  24. return r.newArrayValues(argsCopy)
  25. }
  26. }
  27. func (r *Runtime) generic_push(obj *Object, call FunctionCall) Value {
  28. l := toLength(obj.self.getStr("length"))
  29. nl := l + int64(len(call.Arguments))
  30. if nl >= maxInt {
  31. r.typeErrorResult(true, "Invalid array length")
  32. panic("unreachable")
  33. }
  34. for i, arg := range call.Arguments {
  35. obj.self.put(intToValue(l+int64(i)), arg, true)
  36. }
  37. n := intToValue(nl)
  38. obj.self.putStr("length", n, true)
  39. return n
  40. }
  41. func (r *Runtime) arrayproto_push(call FunctionCall) Value {
  42. obj := call.This.ToObject(r)
  43. return r.generic_push(obj, call)
  44. }
  45. func (r *Runtime) arrayproto_pop_generic(obj *Object, call FunctionCall) Value {
  46. l := int(toLength(obj.self.getStr("length")))
  47. if l == 0 {
  48. obj.self.putStr("length", intToValue(0), true)
  49. return _undefined
  50. }
  51. idx := intToValue(int64(l - 1))
  52. val := obj.self.get(idx)
  53. obj.self.delete(idx, true)
  54. obj.self.putStr("length", idx, true)
  55. return val
  56. }
  57. func (r *Runtime) arrayproto_pop(call FunctionCall) Value {
  58. obj := call.This.ToObject(r)
  59. if a, ok := obj.self.(*arrayObject); ok {
  60. l := a.length
  61. if l > 0 {
  62. var val Value
  63. l--
  64. if l < int64(len(a.values)) {
  65. val = a.values[l]
  66. }
  67. if val == nil {
  68. // optimisation bail-out
  69. return r.arrayproto_pop_generic(obj, call)
  70. }
  71. if _, ok := val.(*valueProperty); ok {
  72. // optimisation bail-out
  73. return r.arrayproto_pop_generic(obj, call)
  74. }
  75. //a._setLengthInt(l, false)
  76. a.values[l] = nil
  77. a.values = a.values[:l]
  78. a.length = l
  79. return val
  80. }
  81. return _undefined
  82. } else {
  83. return r.arrayproto_pop_generic(obj, call)
  84. }
  85. }
  86. func (r *Runtime) arrayproto_join(call FunctionCall) Value {
  87. o := call.This.ToObject(r)
  88. l := int(toLength(o.self.getStr("length")))
  89. sep := ""
  90. if s := call.Argument(0); s != _undefined {
  91. sep = s.String()
  92. } else {
  93. sep = ","
  94. }
  95. if l == 0 {
  96. return stringEmpty
  97. }
  98. var buf bytes.Buffer
  99. element0 := o.self.get(intToValue(0))
  100. if element0 != nil && element0 != _undefined && element0 != _null {
  101. buf.WriteString(element0.String())
  102. }
  103. for i := 1; i < l; i++ {
  104. buf.WriteString(sep)
  105. element := o.self.get(intToValue(int64(i)))
  106. if element != nil && element != _undefined && element != _null {
  107. buf.WriteString(element.String())
  108. }
  109. }
  110. return newStringValue(buf.String())
  111. }
  112. func (r *Runtime) arrayproto_toString(call FunctionCall) Value {
  113. array := call.This.ToObject(r)
  114. f := array.self.getStr("join")
  115. if fObj, ok := f.(*Object); ok {
  116. if fcall, ok := fObj.self.assertCallable(); ok {
  117. return fcall(FunctionCall{
  118. This: array,
  119. })
  120. }
  121. }
  122. return r.objectproto_toString(FunctionCall{
  123. This: array,
  124. })
  125. }
  126. func (r *Runtime) writeItemLocaleString(item Value, buf *bytes.Buffer) {
  127. if item != nil && item != _undefined && item != _null {
  128. itemObj := item.ToObject(r)
  129. if f, ok := itemObj.self.getStr("toLocaleString").(*Object); ok {
  130. if c, ok := f.self.assertCallable(); ok {
  131. strVal := c(FunctionCall{
  132. This: itemObj,
  133. })
  134. buf.WriteString(strVal.String())
  135. return
  136. }
  137. }
  138. r.typeErrorResult(true, "Property 'toLocaleString' of object %s is not a function", itemObj)
  139. }
  140. }
  141. func (r *Runtime) arrayproto_toLocaleString_generic(obj *Object, start int64, buf *bytes.Buffer) Value {
  142. length := toLength(obj.self.getStr("length"))
  143. for i := int64(start); i < length; i++ {
  144. if i > 0 {
  145. buf.WriteByte(',')
  146. }
  147. item := obj.self.get(intToValue(i))
  148. r.writeItemLocaleString(item, buf)
  149. }
  150. return newStringValue(buf.String())
  151. }
  152. func (r *Runtime) arrayproto_toLocaleString(call FunctionCall) Value {
  153. array := call.This.ToObject(r)
  154. if a, ok := array.self.(*arrayObject); ok {
  155. var buf bytes.Buffer
  156. for i := int64(0); i < a.length; i++ {
  157. var item Value
  158. if i < int64(len(a.values)) {
  159. item = a.values[i]
  160. }
  161. if item == nil {
  162. return r.arrayproto_toLocaleString_generic(array, i, &buf)
  163. }
  164. if prop, ok := item.(*valueProperty); ok {
  165. item = prop.get(array)
  166. }
  167. if i > 0 {
  168. buf.WriteByte(',')
  169. }
  170. r.writeItemLocaleString(item, &buf)
  171. }
  172. return newStringValue(buf.String())
  173. } else {
  174. return r.arrayproto_toLocaleString_generic(array, 0, bytes.NewBuffer(nil))
  175. }
  176. }
  177. func (r *Runtime) arrayproto_concat_append(a *Object, item Value) {
  178. descr := r.NewObject().self
  179. descr.putStr("writable", valueTrue, false)
  180. descr.putStr("enumerable", valueTrue, false)
  181. descr.putStr("configurable", valueTrue, false)
  182. aLength := toLength(a.self.getStr("length"))
  183. if obj, ok := item.(*Object); ok {
  184. if isArray(obj) {
  185. length := toLength(obj.self.getStr("length"))
  186. for i := int64(0); i < length; i++ {
  187. v := obj.self.get(intToValue(i))
  188. if v != nil {
  189. descr.putStr("value", v, false)
  190. a.self.defineOwnProperty(intToValue(aLength), descr, false)
  191. aLength++
  192. } else {
  193. aLength++
  194. a.self.putStr("length", intToValue(aLength), false)
  195. }
  196. }
  197. return
  198. }
  199. }
  200. descr.putStr("value", item, false)
  201. a.self.defineOwnProperty(intToValue(aLength), descr, false)
  202. }
  203. func (r *Runtime) arrayproto_concat(call FunctionCall) Value {
  204. a := r.newArrayValues(nil)
  205. r.arrayproto_concat_append(a, call.This.ToObject(r))
  206. for _, item := range call.Arguments {
  207. r.arrayproto_concat_append(a, item)
  208. }
  209. return a
  210. }
  211. func max(a, b int64) int64 {
  212. if a > b {
  213. return a
  214. }
  215. return b
  216. }
  217. func min(a, b int64) int64 {
  218. if a < b {
  219. return a
  220. }
  221. return b
  222. }
  223. func (r *Runtime) arrayproto_slice(call FunctionCall) Value {
  224. o := call.This.ToObject(r)
  225. length := toLength(o.self.getStr("length"))
  226. start := call.Argument(0).ToInteger()
  227. if start < 0 {
  228. start = max(length+start, 0)
  229. } else {
  230. start = min(start, length)
  231. }
  232. var end int64
  233. if endArg := call.Argument(1); endArg != _undefined {
  234. end = endArg.ToInteger()
  235. } else {
  236. end = length
  237. }
  238. if end < 0 {
  239. end = max(length+end, 0)
  240. } else {
  241. end = min(end, length)
  242. }
  243. count := end - start
  244. if count < 0 {
  245. count = 0
  246. }
  247. a := r.newArrayLength(count)
  248. n := int64(0)
  249. descr := r.NewObject().self
  250. descr.putStr("writable", valueTrue, false)
  251. descr.putStr("enumerable", valueTrue, false)
  252. descr.putStr("configurable", valueTrue, false)
  253. for start < end {
  254. p := o.self.get(intToValue(start))
  255. if p != nil && p != _undefined {
  256. descr.putStr("value", p, false)
  257. a.self.defineOwnProperty(intToValue(n), descr, false)
  258. }
  259. start++
  260. n++
  261. }
  262. return a
  263. }
  264. func (r *Runtime) arrayproto_sort(call FunctionCall) Value {
  265. o := call.This.ToObject(r)
  266. var compareFn func(FunctionCall) Value
  267. if arg, ok := call.Argument(0).(*Object); ok {
  268. compareFn, _ = arg.self.assertCallable()
  269. }
  270. ctx := arraySortCtx{
  271. obj: o.self,
  272. compare: compareFn,
  273. }
  274. sort.Sort(&ctx)
  275. return o
  276. }
  277. func (r *Runtime) arrayproto_splice(call FunctionCall) Value {
  278. o := call.This.ToObject(r)
  279. a := r.newArrayValues(nil)
  280. length := toLength(o.self.getStr("length"))
  281. relativeStart := call.Argument(0).ToInteger()
  282. var actualStart int64
  283. if relativeStart < 0 {
  284. actualStart = max(length+relativeStart, 0)
  285. } else {
  286. actualStart = min(relativeStart, length)
  287. }
  288. actualDeleteCount := min(max(call.Argument(1).ToInteger(), 0), length-actualStart)
  289. for k := int64(0); k < actualDeleteCount; k++ {
  290. from := intToValue(k + actualStart)
  291. if o.self.hasProperty(from) {
  292. a.self.put(intToValue(k), o.self.get(from), false)
  293. }
  294. }
  295. itemCount := max(int64(len(call.Arguments)-2), 0)
  296. if itemCount < actualDeleteCount {
  297. for k := actualStart; k < length-actualDeleteCount; k++ {
  298. from := intToValue(k + actualDeleteCount)
  299. to := intToValue(k + itemCount)
  300. if o.self.hasProperty(from) {
  301. o.self.put(to, o.self.get(from), true)
  302. } else {
  303. o.self.delete(to, true)
  304. }
  305. }
  306. for k := length; k > length-actualDeleteCount+itemCount; k-- {
  307. o.self.delete(intToValue(k-1), true)
  308. }
  309. } else if itemCount > actualDeleteCount {
  310. for k := length - actualDeleteCount; k > actualStart; k-- {
  311. from := intToValue(k + actualDeleteCount - 1)
  312. to := intToValue(k + itemCount - 1)
  313. if o.self.hasProperty(from) {
  314. o.self.put(to, o.self.get(from), true)
  315. } else {
  316. o.self.delete(to, true)
  317. }
  318. }
  319. }
  320. if itemCount > 0 {
  321. for i, item := range call.Arguments[2:] {
  322. o.self.put(intToValue(actualStart+int64(i)), item, true)
  323. }
  324. }
  325. o.self.putStr("length", intToValue(length-actualDeleteCount+itemCount), true)
  326. return a
  327. }
  328. func (r *Runtime) arrayproto_unshift(call FunctionCall) Value {
  329. o := call.This.ToObject(r)
  330. length := toLength(o.self.getStr("length"))
  331. argCount := int64(len(call.Arguments))
  332. for k := length - 1; k >= 0; k-- {
  333. from := intToValue(k)
  334. to := intToValue(k + argCount)
  335. if o.self.hasProperty(from) {
  336. o.self.put(to, o.self.get(from), true)
  337. } else {
  338. o.self.delete(to, true)
  339. }
  340. }
  341. for k, arg := range call.Arguments {
  342. o.self.put(intToValue(int64(k)), arg, true)
  343. }
  344. newLen := intToValue(length + argCount)
  345. o.self.putStr("length", newLen, true)
  346. return newLen
  347. }
  348. func (r *Runtime) arrayproto_indexOf(call FunctionCall) Value {
  349. o := call.This.ToObject(r)
  350. length := toLength(o.self.getStr("length"))
  351. if length == 0 {
  352. return intToValue(-1)
  353. }
  354. n := call.Argument(1).ToInteger()
  355. if n >= length {
  356. return intToValue(-1)
  357. }
  358. if n < 0 {
  359. n = max(length+n, 0)
  360. }
  361. searchElement := call.Argument(0)
  362. for ; n < length; n++ {
  363. idx := intToValue(n)
  364. if val := o.self.get(idx); val != nil {
  365. if searchElement.StrictEquals(val) {
  366. return idx
  367. }
  368. }
  369. }
  370. return intToValue(-1)
  371. }
  372. func (r *Runtime) arrayproto_lastIndexOf(call FunctionCall) Value {
  373. o := call.This.ToObject(r)
  374. length := toLength(o.self.getStr("length"))
  375. if length == 0 {
  376. return intToValue(-1)
  377. }
  378. var fromIndex int64
  379. if len(call.Arguments) < 2 {
  380. fromIndex = length - 1
  381. } else {
  382. fromIndex = call.Argument(1).ToInteger()
  383. if fromIndex >= 0 {
  384. fromIndex = min(fromIndex, length-1)
  385. } else {
  386. fromIndex += length
  387. }
  388. }
  389. searchElement := call.Argument(0)
  390. for k := fromIndex; k >= 0; k-- {
  391. idx := intToValue(k)
  392. if val := o.self.get(idx); val != nil {
  393. if searchElement.StrictEquals(val) {
  394. return idx
  395. }
  396. }
  397. }
  398. return intToValue(-1)
  399. }
  400. func (r *Runtime) arrayproto_every(call FunctionCall) Value {
  401. o := call.This.ToObject(r)
  402. length := toLength(o.self.getStr("length"))
  403. callbackFn := call.Argument(0).ToObject(r)
  404. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  405. fc := FunctionCall{
  406. This: call.Argument(1),
  407. Arguments: []Value{nil, nil, o},
  408. }
  409. for k := int64(0); k < length; k++ {
  410. idx := intToValue(k)
  411. if val := o.self.get(idx); val != nil {
  412. fc.Arguments[0] = val
  413. fc.Arguments[1] = idx
  414. if !callbackFn(fc).ToBoolean() {
  415. return valueFalse
  416. }
  417. }
  418. }
  419. } else {
  420. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  421. }
  422. return valueTrue
  423. }
  424. func (r *Runtime) arrayproto_some(call FunctionCall) Value {
  425. o := call.This.ToObject(r)
  426. length := toLength(o.self.getStr("length"))
  427. callbackFn := call.Argument(0).ToObject(r)
  428. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  429. fc := FunctionCall{
  430. This: call.Argument(1),
  431. Arguments: []Value{nil, nil, o},
  432. }
  433. for k := int64(0); k < length; k++ {
  434. idx := intToValue(k)
  435. if val := o.self.get(idx); val != nil {
  436. fc.Arguments[0] = val
  437. fc.Arguments[1] = idx
  438. if callbackFn(fc).ToBoolean() {
  439. return valueTrue
  440. }
  441. }
  442. }
  443. } else {
  444. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  445. }
  446. return valueFalse
  447. }
  448. func (r *Runtime) arrayproto_forEach(call FunctionCall) Value {
  449. o := call.This.ToObject(r)
  450. length := toLength(o.self.getStr("length"))
  451. callbackFn := call.Argument(0).ToObject(r)
  452. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  453. fc := FunctionCall{
  454. This: call.Argument(1),
  455. Arguments: []Value{nil, nil, o},
  456. }
  457. for k := int64(0); k < length; k++ {
  458. idx := intToValue(k)
  459. if val := o.self.get(idx); val != nil {
  460. fc.Arguments[0] = val
  461. fc.Arguments[1] = idx
  462. callbackFn(fc)
  463. }
  464. }
  465. } else {
  466. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  467. }
  468. return _undefined
  469. }
  470. func (r *Runtime) arrayproto_map(call FunctionCall) Value {
  471. o := call.This.ToObject(r)
  472. length := toLength(o.self.getStr("length"))
  473. callbackFn := call.Argument(0).ToObject(r)
  474. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  475. fc := FunctionCall{
  476. This: call.Argument(1),
  477. Arguments: []Value{nil, nil, o},
  478. }
  479. a := r.newArrayObject()
  480. a._setLengthInt(length, true)
  481. a.values = make([]Value, length)
  482. for k := int64(0); k < length; k++ {
  483. idx := intToValue(k)
  484. if val := o.self.get(idx); val != nil {
  485. fc.Arguments[0] = val
  486. fc.Arguments[1] = idx
  487. a.values[k] = callbackFn(fc)
  488. a.objCount++
  489. }
  490. }
  491. return a.val
  492. } else {
  493. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  494. }
  495. panic("unreachable")
  496. }
  497. func (r *Runtime) arrayproto_filter(call FunctionCall) Value {
  498. o := call.This.ToObject(r)
  499. length := toLength(o.self.getStr("length"))
  500. callbackFn := call.Argument(0).ToObject(r)
  501. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  502. a := r.newArrayObject()
  503. fc := FunctionCall{
  504. This: call.Argument(1),
  505. Arguments: []Value{nil, nil, o},
  506. }
  507. for k := int64(0); k < length; k++ {
  508. idx := intToValue(k)
  509. if val := o.self.get(idx); val != nil {
  510. fc.Arguments[0] = val
  511. fc.Arguments[1] = idx
  512. if callbackFn(fc).ToBoolean() {
  513. a.values = append(a.values, val)
  514. }
  515. }
  516. }
  517. a.length = int64(len(a.values))
  518. a.objCount = a.length
  519. return a.val
  520. } else {
  521. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  522. }
  523. panic("unreachable")
  524. }
  525. func (r *Runtime) arrayproto_reduce(call FunctionCall) Value {
  526. o := call.This.ToObject(r)
  527. length := toLength(o.self.getStr("length"))
  528. callbackFn := call.Argument(0).ToObject(r)
  529. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  530. fc := FunctionCall{
  531. This: _undefined,
  532. Arguments: []Value{nil, nil, nil, o},
  533. }
  534. var k int64
  535. if len(call.Arguments) >= 2 {
  536. fc.Arguments[0] = call.Argument(1)
  537. } else {
  538. for ; k < length; k++ {
  539. idx := intToValue(k)
  540. if val := o.self.get(idx); val != nil {
  541. fc.Arguments[0] = val
  542. break
  543. }
  544. }
  545. if fc.Arguments[0] == nil {
  546. r.typeErrorResult(true, "No initial value")
  547. panic("unreachable")
  548. }
  549. k++
  550. }
  551. for ; k < length; k++ {
  552. idx := intToValue(k)
  553. if val := o.self.get(idx); val != nil {
  554. fc.Arguments[1] = val
  555. fc.Arguments[2] = idx
  556. fc.Arguments[0] = callbackFn(fc)
  557. }
  558. }
  559. return fc.Arguments[0]
  560. } else {
  561. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  562. }
  563. panic("unreachable")
  564. }
  565. func (r *Runtime) arrayproto_reduceRight(call FunctionCall) Value {
  566. o := call.This.ToObject(r)
  567. length := toLength(o.self.getStr("length"))
  568. callbackFn := call.Argument(0).ToObject(r)
  569. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  570. fc := FunctionCall{
  571. This: _undefined,
  572. Arguments: []Value{nil, nil, nil, o},
  573. }
  574. k := length - 1
  575. if len(call.Arguments) >= 2 {
  576. fc.Arguments[0] = call.Argument(1)
  577. } else {
  578. for ; k >= 0; k-- {
  579. idx := intToValue(k)
  580. if val := o.self.get(idx); val != nil {
  581. fc.Arguments[0] = val
  582. break
  583. }
  584. }
  585. if fc.Arguments[0] == nil {
  586. r.typeErrorResult(true, "No initial value")
  587. panic("unreachable")
  588. }
  589. k--
  590. }
  591. for ; k >= 0; k-- {
  592. idx := intToValue(k)
  593. if val := o.self.get(idx); val != nil {
  594. fc.Arguments[1] = val
  595. fc.Arguments[2] = idx
  596. fc.Arguments[0] = callbackFn(fc)
  597. }
  598. }
  599. return fc.Arguments[0]
  600. } else {
  601. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  602. }
  603. panic("unreachable")
  604. }
  605. func arrayproto_reverse_generic_step(o *Object, lower, upper int64) {
  606. lowerP := intToValue(lower)
  607. upperP := intToValue(upper)
  608. lowerValue := o.self.get(lowerP)
  609. upperValue := o.self.get(upperP)
  610. if lowerValue != nil && upperValue != nil {
  611. o.self.put(lowerP, upperValue, true)
  612. o.self.put(upperP, lowerValue, true)
  613. } else if lowerValue == nil && upperValue != nil {
  614. o.self.put(lowerP, upperValue, true)
  615. o.self.delete(upperP, true)
  616. } else if lowerValue != nil && upperValue == nil {
  617. o.self.delete(lowerP, true)
  618. o.self.put(upperP, lowerValue, true)
  619. }
  620. }
  621. func (r *Runtime) arrayproto_reverse_generic(o *Object, start int64) {
  622. l := toLength(o.self.getStr("length"))
  623. middle := l / 2
  624. for lower := start; lower != middle; lower++ {
  625. arrayproto_reverse_generic_step(o, lower, l-lower-1)
  626. }
  627. }
  628. func (r *Runtime) arrayproto_reverse(call FunctionCall) Value {
  629. o := call.This.ToObject(r)
  630. if a, ok := o.self.(*arrayObject); ok {
  631. l := a.length
  632. middle := l / 2
  633. al := int64(len(a.values))
  634. for lower := int64(0); lower != middle; lower++ {
  635. upper := l - lower - 1
  636. var lowerValue, upperValue Value
  637. if upper >= al || lower >= al {
  638. goto bailout
  639. }
  640. lowerValue = a.values[lower]
  641. if lowerValue == nil {
  642. goto bailout
  643. }
  644. if _, ok := lowerValue.(*valueProperty); ok {
  645. goto bailout
  646. }
  647. upperValue = a.values[upper]
  648. if upperValue == nil {
  649. goto bailout
  650. }
  651. if _, ok := upperValue.(*valueProperty); ok {
  652. goto bailout
  653. }
  654. a.values[lower], a.values[upper] = upperValue, lowerValue
  655. continue
  656. bailout:
  657. arrayproto_reverse_generic_step(o, lower, upper)
  658. }
  659. //TODO: go arrays
  660. } else {
  661. r.arrayproto_reverse_generic(o, 0)
  662. }
  663. return o
  664. }
  665. func (r *Runtime) arrayproto_shift(call FunctionCall) Value {
  666. o := call.This.ToObject(r)
  667. length := toLength(o.self.getStr("length"))
  668. if length == 0 {
  669. o.self.putStr("length", intToValue(0), true)
  670. return _undefined
  671. }
  672. first := o.self.get(intToValue(0))
  673. for i := int64(1); i < length; i++ {
  674. v := o.self.get(intToValue(i))
  675. if v != nil && v != _undefined {
  676. o.self.put(intToValue(i-1), v, true)
  677. } else {
  678. o.self.delete(intToValue(i-1), true)
  679. }
  680. }
  681. lv := intToValue(length - 1)
  682. o.self.delete(lv, true)
  683. o.self.putStr("length", lv, true)
  684. return first
  685. }
  686. func (r *Runtime) array_isArray(call FunctionCall) Value {
  687. if o, ok := call.Argument(0).(*Object); ok {
  688. if isArray(o) {
  689. return valueTrue
  690. }
  691. }
  692. return valueFalse
  693. }
  694. func (r *Runtime) createArrayProto(val *Object) objectImpl {
  695. o := &arrayObject{
  696. baseObject: baseObject{
  697. class: classArray,
  698. val: val,
  699. extensible: true,
  700. prototype: r.global.ObjectPrototype,
  701. },
  702. }
  703. o.init()
  704. o._putProp("constructor", r.global.Array, true, false, true)
  705. o._putProp("pop", r.newNativeFunc(r.arrayproto_pop, nil, "pop", nil, 0), true, false, true)
  706. o._putProp("push", r.newNativeFunc(r.arrayproto_push, nil, "push", nil, 1), true, false, true)
  707. o._putProp("join", r.newNativeFunc(r.arrayproto_join, nil, "join", nil, 1), true, false, true)
  708. o._putProp("toString", r.newNativeFunc(r.arrayproto_toString, nil, "toString", nil, 0), true, false, true)
  709. o._putProp("toLocaleString", r.newNativeFunc(r.arrayproto_toLocaleString, nil, "toLocaleString", nil, 0), true, false, true)
  710. o._putProp("concat", r.newNativeFunc(r.arrayproto_concat, nil, "concat", nil, 1), true, false, true)
  711. o._putProp("reverse", r.newNativeFunc(r.arrayproto_reverse, nil, "reverse", nil, 0), true, false, true)
  712. o._putProp("shift", r.newNativeFunc(r.arrayproto_shift, nil, "shift", nil, 0), true, false, true)
  713. o._putProp("slice", r.newNativeFunc(r.arrayproto_slice, nil, "slice", nil, 2), true, false, true)
  714. o._putProp("sort", r.newNativeFunc(r.arrayproto_sort, nil, "sort", nil, 1), true, false, true)
  715. o._putProp("splice", r.newNativeFunc(r.arrayproto_splice, nil, "splice", nil, 2), true, false, true)
  716. o._putProp("unshift", r.newNativeFunc(r.arrayproto_unshift, nil, "unshift", nil, 1), true, false, true)
  717. o._putProp("indexOf", r.newNativeFunc(r.arrayproto_indexOf, nil, "indexOf", nil, 1), true, false, true)
  718. o._putProp("lastIndexOf", r.newNativeFunc(r.arrayproto_lastIndexOf, nil, "lastIndexOf", nil, 1), true, false, true)
  719. o._putProp("every", r.newNativeFunc(r.arrayproto_every, nil, "every", nil, 1), true, false, true)
  720. o._putProp("some", r.newNativeFunc(r.arrayproto_some, nil, "some", nil, 1), true, false, true)
  721. o._putProp("forEach", r.newNativeFunc(r.arrayproto_forEach, nil, "forEach", nil, 1), true, false, true)
  722. o._putProp("map", r.newNativeFunc(r.arrayproto_map, nil, "map", nil, 1), true, false, true)
  723. o._putProp("filter", r.newNativeFunc(r.arrayproto_filter, nil, "filter", nil, 1), true, false, true)
  724. o._putProp("reduce", r.newNativeFunc(r.arrayproto_reduce, nil, "reduce", nil, 1), true, false, true)
  725. o._putProp("reduceRight", r.newNativeFunc(r.arrayproto_reduceRight, nil, "reduceRight", nil, 1), true, false, true)
  726. return o
  727. }
  728. func (r *Runtime) createArray(val *Object) objectImpl {
  729. o := r.newNativeFuncConstructObj(val, r.builtin_newArray, "Array", r.global.ArrayPrototype, 1)
  730. o._putProp("isArray", r.newNativeFunc(r.array_isArray, nil, "isArray", nil, 1), true, false, true)
  731. return o
  732. }
  733. func (r *Runtime) initArray() {
  734. //r.global.ArrayPrototype = r.newArray(r.global.ObjectPrototype).val
  735. //o := r.global.ArrayPrototype.self
  736. r.global.ArrayPrototype = r.newLazyObject(r.createArrayProto)
  737. //r.global.Array = r.newNativeFuncConstruct(r.builtin_newArray, "Array", r.global.ArrayPrototype, 1)
  738. //o = r.global.Array.self
  739. //o._putProp("isArray", r.newNativeFunc(r.array_isArray, nil, "isArray", nil, 1), true, false, true)
  740. r.global.Array = r.newLazyObject(r.createArray)
  741. r.addToGlobal("Array", r.global.Array)
  742. }
  743. type sortable interface {
  744. sortLen() int64
  745. sortGet(int64) Value
  746. swap(int64, int64)
  747. }
  748. type arraySortCtx struct {
  749. obj sortable
  750. compare func(FunctionCall) Value
  751. }
  752. func (ctx *arraySortCtx) sortCompare(x, y Value) int {
  753. if x == nil && y == nil {
  754. return 0
  755. }
  756. if x == nil {
  757. return 1
  758. }
  759. if y == nil {
  760. return -1
  761. }
  762. if x == _undefined && y == _undefined {
  763. return 0
  764. }
  765. if x == _undefined {
  766. return 1
  767. }
  768. if y == _undefined {
  769. return -1
  770. }
  771. if ctx.compare != nil {
  772. return int(ctx.compare(FunctionCall{
  773. This: _undefined,
  774. Arguments: []Value{x, y},
  775. }).ToInteger())
  776. }
  777. return strings.Compare(x.String(), y.String())
  778. }
  779. // sort.Interface
  780. func (a *arraySortCtx) Len() int {
  781. return int(a.obj.sortLen())
  782. }
  783. func (a *arraySortCtx) Less(j, k int) bool {
  784. return a.sortCompare(a.obj.sortGet(int64(j)), a.obj.sortGet(int64(k))) == -1
  785. }
  786. func (a *arraySortCtx) Swap(j, k int) {
  787. a.obj.swap(int64(j), int64(k))
  788. }