builtin_array.go 22 KB

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