builtin_array.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  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 := toLength(obj.self.getStr("length"))
  47. if l == 0 {
  48. obj.self.putStr("length", intToValue(0), true)
  49. return _undefined
  50. }
  51. idx := intToValue(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 := propertyDescr{
  179. Writable: FLAG_TRUE,
  180. Enumerable: FLAG_TRUE,
  181. Configurable: FLAG_TRUE,
  182. }
  183. aLength := toLength(a.self.getStr("length"))
  184. if obj, ok := item.(*Object); ok {
  185. if isArray(obj) {
  186. length := toLength(obj.self.getStr("length"))
  187. for i := int64(0); i < length; i++ {
  188. v := obj.self.get(intToValue(i))
  189. if v != nil {
  190. descr.Value = v
  191. a.self.defineOwnProperty(intToValue(aLength), descr, false)
  192. aLength++
  193. } else {
  194. aLength++
  195. a.self.putStr("length", intToValue(aLength), false)
  196. }
  197. }
  198. return
  199. }
  200. }
  201. descr.Value = item
  202. a.self.defineOwnProperty(intToValue(aLength), descr, false)
  203. }
  204. func (r *Runtime) arrayproto_concat(call FunctionCall) Value {
  205. a := r.newArrayValues(nil)
  206. r.arrayproto_concat_append(a, call.This.ToObject(r))
  207. for _, item := range call.Arguments {
  208. r.arrayproto_concat_append(a, item)
  209. }
  210. return a
  211. }
  212. func max(a, b int64) int64 {
  213. if a > b {
  214. return a
  215. }
  216. return b
  217. }
  218. func min(a, b int64) int64 {
  219. if a < b {
  220. return a
  221. }
  222. return b
  223. }
  224. func (r *Runtime) arrayproto_slice(call FunctionCall) Value {
  225. o := call.This.ToObject(r)
  226. length := toLength(o.self.getStr("length"))
  227. start := call.Argument(0).ToInteger()
  228. if start < 0 {
  229. start = max(length+start, 0)
  230. } else {
  231. start = min(start, length)
  232. }
  233. var end int64
  234. if endArg := call.Argument(1); endArg != _undefined {
  235. end = endArg.ToInteger()
  236. } else {
  237. end = length
  238. }
  239. if end < 0 {
  240. end = max(length+end, 0)
  241. } else {
  242. end = min(end, length)
  243. }
  244. count := end - start
  245. if count < 0 {
  246. count = 0
  247. }
  248. a := r.newArrayLength(count)
  249. n := int64(0)
  250. descr := propertyDescr{
  251. Writable: FLAG_TRUE,
  252. Enumerable: FLAG_TRUE,
  253. Configurable: FLAG_TRUE,
  254. }
  255. for start < end {
  256. p := o.self.get(intToValue(start))
  257. if p != nil && p != _undefined {
  258. descr.Value = p
  259. a.self.defineOwnProperty(intToValue(n), descr, false)
  260. }
  261. start++
  262. n++
  263. }
  264. return a
  265. }
  266. func (r *Runtime) arrayproto_sort(call FunctionCall) Value {
  267. o := call.This.ToObject(r)
  268. var compareFn func(FunctionCall) Value
  269. if arg, ok := call.Argument(0).(*Object); ok {
  270. compareFn, _ = arg.self.assertCallable()
  271. }
  272. ctx := arraySortCtx{
  273. obj: o.self,
  274. compare: compareFn,
  275. }
  276. sort.Sort(&ctx)
  277. return o
  278. }
  279. func (r *Runtime) arrayproto_splice(call FunctionCall) Value {
  280. o := call.This.ToObject(r)
  281. a := r.newArrayValues(nil)
  282. length := toLength(o.self.getStr("length"))
  283. relativeStart := call.Argument(0).ToInteger()
  284. var actualStart int64
  285. if relativeStart < 0 {
  286. actualStart = max(length+relativeStart, 0)
  287. } else {
  288. actualStart = min(relativeStart, length)
  289. }
  290. actualDeleteCount := min(max(call.Argument(1).ToInteger(), 0), length-actualStart)
  291. for k := int64(0); k < actualDeleteCount; k++ {
  292. from := intToValue(k + actualStart)
  293. if o.self.hasProperty(from) {
  294. a.self.put(intToValue(k), o.self.get(from), false)
  295. }
  296. }
  297. itemCount := max(int64(len(call.Arguments)-2), 0)
  298. if itemCount < actualDeleteCount {
  299. for k := actualStart; k < length-actualDeleteCount; k++ {
  300. from := intToValue(k + actualDeleteCount)
  301. to := intToValue(k + itemCount)
  302. if o.self.hasProperty(from) {
  303. o.self.put(to, o.self.get(from), true)
  304. } else {
  305. o.self.delete(to, true)
  306. }
  307. }
  308. for k := length; k > length-actualDeleteCount+itemCount; k-- {
  309. o.self.delete(intToValue(k-1), true)
  310. }
  311. } else if itemCount > actualDeleteCount {
  312. for k := length - actualDeleteCount; k > actualStart; k-- {
  313. from := intToValue(k + actualDeleteCount - 1)
  314. to := intToValue(k + itemCount - 1)
  315. if o.self.hasProperty(from) {
  316. o.self.put(to, o.self.get(from), true)
  317. } else {
  318. o.self.delete(to, true)
  319. }
  320. }
  321. }
  322. if itemCount > 0 {
  323. for i, item := range call.Arguments[2:] {
  324. o.self.put(intToValue(actualStart+int64(i)), item, true)
  325. }
  326. }
  327. o.self.putStr("length", intToValue(length-actualDeleteCount+itemCount), true)
  328. return a
  329. }
  330. func (r *Runtime) arrayproto_unshift(call FunctionCall) Value {
  331. o := call.This.ToObject(r)
  332. length := toLength(o.self.getStr("length"))
  333. argCount := int64(len(call.Arguments))
  334. for k := length - 1; k >= 0; k-- {
  335. from := intToValue(k)
  336. to := intToValue(k + argCount)
  337. if o.self.hasProperty(from) {
  338. o.self.put(to, o.self.get(from), true)
  339. } else {
  340. o.self.delete(to, true)
  341. }
  342. }
  343. for k, arg := range call.Arguments {
  344. o.self.put(intToValue(int64(k)), arg, true)
  345. }
  346. newLen := intToValue(length + argCount)
  347. o.self.putStr("length", newLen, true)
  348. return newLen
  349. }
  350. func (r *Runtime) arrayproto_indexOf(call FunctionCall) Value {
  351. o := call.This.ToObject(r)
  352. length := toLength(o.self.getStr("length"))
  353. if length == 0 {
  354. return intToValue(-1)
  355. }
  356. n := call.Argument(1).ToInteger()
  357. if n >= length {
  358. return intToValue(-1)
  359. }
  360. if n < 0 {
  361. n = max(length+n, 0)
  362. }
  363. searchElement := call.Argument(0)
  364. for ; n < length; n++ {
  365. idx := intToValue(n)
  366. if val := o.self.get(idx); val != nil {
  367. if searchElement.StrictEquals(val) {
  368. return idx
  369. }
  370. }
  371. }
  372. return intToValue(-1)
  373. }
  374. func (r *Runtime) arrayproto_lastIndexOf(call FunctionCall) Value {
  375. o := call.This.ToObject(r)
  376. length := toLength(o.self.getStr("length"))
  377. if length == 0 {
  378. return intToValue(-1)
  379. }
  380. var fromIndex int64
  381. if len(call.Arguments) < 2 {
  382. fromIndex = length - 1
  383. } else {
  384. fromIndex = call.Argument(1).ToInteger()
  385. if fromIndex >= 0 {
  386. fromIndex = min(fromIndex, length-1)
  387. } else {
  388. fromIndex += length
  389. }
  390. }
  391. searchElement := call.Argument(0)
  392. for k := fromIndex; k >= 0; k-- {
  393. idx := intToValue(k)
  394. if val := o.self.get(idx); val != nil {
  395. if searchElement.StrictEquals(val) {
  396. return idx
  397. }
  398. }
  399. }
  400. return intToValue(-1)
  401. }
  402. func (r *Runtime) arrayproto_every(call FunctionCall) Value {
  403. o := call.This.ToObject(r)
  404. length := toLength(o.self.getStr("length"))
  405. callbackFn := call.Argument(0).ToObject(r)
  406. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  407. fc := FunctionCall{
  408. This: call.Argument(1),
  409. Arguments: []Value{nil, nil, o},
  410. }
  411. for k := int64(0); k < length; k++ {
  412. idx := intToValue(k)
  413. if val := o.self.get(idx); val != nil {
  414. fc.Arguments[0] = val
  415. fc.Arguments[1] = idx
  416. if !callbackFn(fc).ToBoolean() {
  417. return valueFalse
  418. }
  419. }
  420. }
  421. } else {
  422. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  423. }
  424. return valueTrue
  425. }
  426. func (r *Runtime) arrayproto_some(call FunctionCall) Value {
  427. o := call.This.ToObject(r)
  428. length := toLength(o.self.getStr("length"))
  429. callbackFn := call.Argument(0).ToObject(r)
  430. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  431. fc := FunctionCall{
  432. This: call.Argument(1),
  433. Arguments: []Value{nil, nil, o},
  434. }
  435. for k := int64(0); k < length; k++ {
  436. idx := intToValue(k)
  437. if val := o.self.get(idx); val != nil {
  438. fc.Arguments[0] = val
  439. fc.Arguments[1] = idx
  440. if callbackFn(fc).ToBoolean() {
  441. return valueTrue
  442. }
  443. }
  444. }
  445. } else {
  446. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  447. }
  448. return valueFalse
  449. }
  450. func (r *Runtime) arrayproto_forEach(call FunctionCall) Value {
  451. o := call.This.ToObject(r)
  452. length := toLength(o.self.getStr("length"))
  453. callbackFn := call.Argument(0).ToObject(r)
  454. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  455. fc := FunctionCall{
  456. This: call.Argument(1),
  457. Arguments: []Value{nil, nil, o},
  458. }
  459. for k := int64(0); k < length; k++ {
  460. idx := intToValue(k)
  461. if val := o.self.get(idx); val != nil {
  462. fc.Arguments[0] = val
  463. fc.Arguments[1] = idx
  464. callbackFn(fc)
  465. }
  466. }
  467. } else {
  468. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  469. }
  470. return _undefined
  471. }
  472. func (r *Runtime) arrayproto_map(call FunctionCall) Value {
  473. o := call.This.ToObject(r)
  474. length := toLength(o.self.getStr("length"))
  475. callbackFn := call.Argument(0).ToObject(r)
  476. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  477. fc := FunctionCall{
  478. This: call.Argument(1),
  479. Arguments: []Value{nil, nil, o},
  480. }
  481. a := r.newArrayObject()
  482. a._setLengthInt(length, true)
  483. a.values = make([]Value, length)
  484. for k := int64(0); k < length; k++ {
  485. idx := intToValue(k)
  486. if val := o.self.get(idx); val != nil {
  487. fc.Arguments[0] = val
  488. fc.Arguments[1] = idx
  489. a.values[k] = callbackFn(fc)
  490. a.objCount++
  491. }
  492. }
  493. return a.val
  494. } else {
  495. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  496. }
  497. panic("unreachable")
  498. }
  499. func (r *Runtime) arrayproto_filter(call FunctionCall) Value {
  500. o := call.This.ToObject(r)
  501. length := toLength(o.self.getStr("length"))
  502. callbackFn := call.Argument(0).ToObject(r)
  503. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  504. a := r.newArrayObject()
  505. fc := FunctionCall{
  506. This: call.Argument(1),
  507. Arguments: []Value{nil, nil, o},
  508. }
  509. for k := int64(0); k < length; k++ {
  510. idx := intToValue(k)
  511. if val := o.self.get(idx); val != nil {
  512. fc.Arguments[0] = val
  513. fc.Arguments[1] = idx
  514. if callbackFn(fc).ToBoolean() {
  515. a.values = append(a.values, val)
  516. }
  517. }
  518. }
  519. a.length = int64(len(a.values))
  520. a.objCount = a.length
  521. return a.val
  522. } else {
  523. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  524. }
  525. panic("unreachable")
  526. }
  527. func (r *Runtime) arrayproto_reduce(call FunctionCall) Value {
  528. o := call.This.ToObject(r)
  529. length := toLength(o.self.getStr("length"))
  530. callbackFn := call.Argument(0).ToObject(r)
  531. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  532. fc := FunctionCall{
  533. This: _undefined,
  534. Arguments: []Value{nil, nil, nil, o},
  535. }
  536. var k int64
  537. if len(call.Arguments) >= 2 {
  538. fc.Arguments[0] = call.Argument(1)
  539. } else {
  540. for ; k < length; k++ {
  541. idx := intToValue(k)
  542. if val := o.self.get(idx); val != nil {
  543. fc.Arguments[0] = val
  544. break
  545. }
  546. }
  547. if fc.Arguments[0] == nil {
  548. r.typeErrorResult(true, "No initial value")
  549. panic("unreachable")
  550. }
  551. k++
  552. }
  553. for ; k < length; k++ {
  554. idx := intToValue(k)
  555. if val := o.self.get(idx); val != nil {
  556. fc.Arguments[1] = val
  557. fc.Arguments[2] = idx
  558. fc.Arguments[0] = callbackFn(fc)
  559. }
  560. }
  561. return fc.Arguments[0]
  562. } else {
  563. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  564. }
  565. panic("unreachable")
  566. }
  567. func (r *Runtime) arrayproto_reduceRight(call FunctionCall) Value {
  568. o := call.This.ToObject(r)
  569. length := toLength(o.self.getStr("length"))
  570. callbackFn := call.Argument(0).ToObject(r)
  571. if callbackFn, ok := callbackFn.self.assertCallable(); ok {
  572. fc := FunctionCall{
  573. This: _undefined,
  574. Arguments: []Value{nil, nil, nil, o},
  575. }
  576. k := length - 1
  577. if len(call.Arguments) >= 2 {
  578. fc.Arguments[0] = call.Argument(1)
  579. } else {
  580. for ; k >= 0; k-- {
  581. idx := intToValue(k)
  582. if val := o.self.get(idx); val != nil {
  583. fc.Arguments[0] = val
  584. break
  585. }
  586. }
  587. if fc.Arguments[0] == nil {
  588. r.typeErrorResult(true, "No initial value")
  589. panic("unreachable")
  590. }
  591. k--
  592. }
  593. for ; k >= 0; k-- {
  594. idx := intToValue(k)
  595. if val := o.self.get(idx); val != nil {
  596. fc.Arguments[1] = val
  597. fc.Arguments[2] = idx
  598. fc.Arguments[0] = callbackFn(fc)
  599. }
  600. }
  601. return fc.Arguments[0]
  602. } else {
  603. r.typeErrorResult(true, "%s is not a function", call.Argument(0))
  604. }
  605. panic("unreachable")
  606. }
  607. func arrayproto_reverse_generic_step(o *Object, lower, upper int64) {
  608. lowerP := intToValue(lower)
  609. upperP := intToValue(upper)
  610. lowerValue := o.self.get(lowerP)
  611. upperValue := o.self.get(upperP)
  612. if lowerValue != nil && upperValue != nil {
  613. o.self.put(lowerP, upperValue, true)
  614. o.self.put(upperP, lowerValue, true)
  615. } else if lowerValue == nil && upperValue != nil {
  616. o.self.put(lowerP, upperValue, true)
  617. o.self.delete(upperP, true)
  618. } else if lowerValue != nil && upperValue == nil {
  619. o.self.delete(lowerP, true)
  620. o.self.put(upperP, lowerValue, true)
  621. }
  622. }
  623. func (r *Runtime) arrayproto_reverse_generic(o *Object, start int64) {
  624. l := toLength(o.self.getStr("length"))
  625. middle := l / 2
  626. for lower := start; lower != middle; lower++ {
  627. arrayproto_reverse_generic_step(o, lower, l-lower-1)
  628. }
  629. }
  630. func (r *Runtime) arrayproto_reverse(call FunctionCall) Value {
  631. o := call.This.ToObject(r)
  632. if a, ok := o.self.(*arrayObject); ok {
  633. l := a.length
  634. middle := l / 2
  635. al := int64(len(a.values))
  636. for lower := int64(0); lower != middle; lower++ {
  637. upper := l - lower - 1
  638. var lowerValue, upperValue Value
  639. if upper >= al || lower >= al {
  640. goto bailout
  641. }
  642. lowerValue = a.values[lower]
  643. if lowerValue == nil {
  644. goto bailout
  645. }
  646. if _, ok := lowerValue.(*valueProperty); ok {
  647. goto bailout
  648. }
  649. upperValue = a.values[upper]
  650. if upperValue == nil {
  651. goto bailout
  652. }
  653. if _, ok := upperValue.(*valueProperty); ok {
  654. goto bailout
  655. }
  656. a.values[lower], a.values[upper] = upperValue, lowerValue
  657. continue
  658. bailout:
  659. arrayproto_reverse_generic_step(o, lower, upper)
  660. }
  661. //TODO: go arrays
  662. } else {
  663. r.arrayproto_reverse_generic(o, 0)
  664. }
  665. return o
  666. }
  667. func (r *Runtime) arrayproto_shift(call FunctionCall) Value {
  668. o := call.This.ToObject(r)
  669. length := toLength(o.self.getStr("length"))
  670. if length == 0 {
  671. o.self.putStr("length", intToValue(0), true)
  672. return _undefined
  673. }
  674. first := o.self.get(intToValue(0))
  675. for i := int64(1); i < length; i++ {
  676. v := o.self.get(intToValue(i))
  677. if v != nil && v != _undefined {
  678. o.self.put(intToValue(i-1), v, true)
  679. } else {
  680. o.self.delete(intToValue(i-1), true)
  681. }
  682. }
  683. lv := intToValue(length - 1)
  684. o.self.delete(lv, true)
  685. o.self.putStr("length", lv, true)
  686. return first
  687. }
  688. func (r *Runtime) array_isArray(call FunctionCall) Value {
  689. if o, ok := call.Argument(0).(*Object); ok {
  690. if isArray(o) {
  691. return valueTrue
  692. }
  693. }
  694. return valueFalse
  695. }
  696. func (r *Runtime) createArrayProto(val *Object) objectImpl {
  697. o := &arrayObject{
  698. baseObject: baseObject{
  699. class: classArray,
  700. val: val,
  701. extensible: true,
  702. prototype: r.global.ObjectPrototype,
  703. },
  704. }
  705. o.init()
  706. o._putProp("constructor", r.global.Array, true, false, true)
  707. o._putProp("pop", r.newNativeFunc(r.arrayproto_pop, nil, "pop", nil, 0), true, false, true)
  708. o._putProp("push", r.newNativeFunc(r.arrayproto_push, nil, "push", nil, 1), true, false, true)
  709. o._putProp("join", r.newNativeFunc(r.arrayproto_join, nil, "join", nil, 1), true, false, true)
  710. o._putProp("toString", r.newNativeFunc(r.arrayproto_toString, nil, "toString", nil, 0), true, false, true)
  711. o._putProp("toLocaleString", r.newNativeFunc(r.arrayproto_toLocaleString, nil, "toLocaleString", nil, 0), true, false, true)
  712. o._putProp("concat", r.newNativeFunc(r.arrayproto_concat, nil, "concat", nil, 1), true, false, true)
  713. o._putProp("reverse", r.newNativeFunc(r.arrayproto_reverse, nil, "reverse", nil, 0), true, false, true)
  714. o._putProp("shift", r.newNativeFunc(r.arrayproto_shift, nil, "shift", nil, 0), true, false, true)
  715. o._putProp("slice", r.newNativeFunc(r.arrayproto_slice, nil, "slice", nil, 2), true, false, true)
  716. o._putProp("sort", r.newNativeFunc(r.arrayproto_sort, nil, "sort", nil, 1), true, false, true)
  717. o._putProp("splice", r.newNativeFunc(r.arrayproto_splice, nil, "splice", nil, 2), true, false, true)
  718. o._putProp("unshift", r.newNativeFunc(r.arrayproto_unshift, nil, "unshift", nil, 1), true, false, true)
  719. o._putProp("indexOf", r.newNativeFunc(r.arrayproto_indexOf, nil, "indexOf", nil, 1), true, false, true)
  720. o._putProp("lastIndexOf", r.newNativeFunc(r.arrayproto_lastIndexOf, nil, "lastIndexOf", nil, 1), true, false, true)
  721. o._putProp("every", r.newNativeFunc(r.arrayproto_every, nil, "every", nil, 1), true, false, true)
  722. o._putProp("some", r.newNativeFunc(r.arrayproto_some, nil, "some", nil, 1), true, false, true)
  723. o._putProp("forEach", r.newNativeFunc(r.arrayproto_forEach, nil, "forEach", nil, 1), true, false, true)
  724. o._putProp("map", r.newNativeFunc(r.arrayproto_map, nil, "map", nil, 1), true, false, true)
  725. o._putProp("filter", r.newNativeFunc(r.arrayproto_filter, nil, "filter", nil, 1), true, false, true)
  726. o._putProp("reduce", r.newNativeFunc(r.arrayproto_reduce, nil, "reduce", nil, 1), true, false, true)
  727. o._putProp("reduceRight", r.newNativeFunc(r.arrayproto_reduceRight, nil, "reduceRight", nil, 1), true, false, true)
  728. return o
  729. }
  730. func (r *Runtime) createArray(val *Object) objectImpl {
  731. o := r.newNativeFuncConstructObj(val, r.builtin_newArray, "Array", r.global.ArrayPrototype, 1)
  732. o._putProp("isArray", r.newNativeFunc(r.array_isArray, nil, "isArray", nil, 1), true, false, true)
  733. return o
  734. }
  735. func (r *Runtime) initArray() {
  736. //r.global.ArrayPrototype = r.newArray(r.global.ObjectPrototype).val
  737. //o := r.global.ArrayPrototype.self
  738. r.global.ArrayPrototype = r.newLazyObject(r.createArrayProto)
  739. //r.global.Array = r.newNativeFuncConstruct(r.builtin_newArray, "Array", r.global.ArrayPrototype, 1)
  740. //o = r.global.Array.self
  741. //o._putProp("isArray", r.newNativeFunc(r.array_isArray, nil, "isArray", nil, 1), true, false, true)
  742. r.global.Array = r.newLazyObject(r.createArray)
  743. r.addToGlobal("Array", r.global.Array)
  744. }
  745. type sortable interface {
  746. sortLen() int64
  747. sortGet(int64) Value
  748. swap(int64, int64)
  749. }
  750. type arraySortCtx struct {
  751. obj sortable
  752. compare func(FunctionCall) Value
  753. }
  754. func (ctx *arraySortCtx) sortCompare(x, y Value) int {
  755. if x == nil && y == nil {
  756. return 0
  757. }
  758. if x == nil {
  759. return 1
  760. }
  761. if y == nil {
  762. return -1
  763. }
  764. if x == _undefined && y == _undefined {
  765. return 0
  766. }
  767. if x == _undefined {
  768. return 1
  769. }
  770. if y == _undefined {
  771. return -1
  772. }
  773. if ctx.compare != nil {
  774. return int(ctx.compare(FunctionCall{
  775. This: _undefined,
  776. Arguments: []Value{x, y},
  777. }).ToInteger())
  778. }
  779. return strings.Compare(x.String(), y.String())
  780. }
  781. // sort.Interface
  782. func (a *arraySortCtx) Len() int {
  783. return int(a.obj.sortLen())
  784. }
  785. func (a *arraySortCtx) Less(j, k int) bool {
  786. return a.sortCompare(a.obj.sortGet(int64(j)), a.obj.sortGet(int64(k))) < 0
  787. }
  788. func (a *arraySortCtx) Swap(j, k int) {
  789. a.obj.swap(int64(j), int64(k))
  790. }