diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index cae5f94f..08d0ab7b 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -1032,6 +1032,106 @@ (< (len args) 2) (- (len arr) 1) (js-num-to-int (nth args 1))))))) + ((= name "at") + (fn + (&rest args) + (let + ((i (if (empty? args) 0 (js-num-to-int (nth args 0))))) + (let + ((idx (if (< i 0) (+ (len arr) i) i))) + (if + (or (< idx 0) (>= idx (len arr))) + :js-undefined (nth arr idx)))))) + ((= name "unshift") (fn (&rest args) (+ (len arr) (len args)))) + ((= name "splice") + (fn + (&rest args) + (let + ((n (len arr)) + (start-raw (if (empty? args) 0 (js-num-to-int (nth args 0))))) + (let + ((start (cond ((< start-raw 0) (max 0 (+ n start-raw))) ((> start-raw n) n) (else start-raw)))) + (let + ((delete-count (if (< (len args) 2) (- n start) (max 0 (min (- n start) (js-num-to-int (nth args 1))))))) + (js-list-slice arr start (+ start delete-count))))))) + ((= name "flatMap") + (fn + (f) + (let + ((mapped (js-list-map-loop f arr 0 (list)))) + (js-list-flat-loop mapped 1 (list))))) + ((= name "findLast") + (fn (f) (js-list-find-last-loop f arr (- (len arr) 1)))) + ((= name "findLastIndex") + (fn (f) (js-list-find-last-index-loop f arr (- (len arr) 1)))) + ((= name "reduceRight") + (fn + (&rest args) + (cond + ((= (len args) 1) + (if + (= (len arr) 0) + (error "Reduce of empty array with no initial value") + (js-list-reduce-right-loop + (nth args 0) + (nth arr (- (len arr) 1)) + arr + (- (len arr) 2)))) + (else + (js-list-reduce-right-loop + (nth args 0) + (nth args 1) + arr + (- (len arr) 1)))))) + ((= name "toString") (fn () (js-list-join arr ","))) + ((= name "toLocaleString") (fn () (js-list-join arr ","))) + ((= name "keys") + (fn + () + (let + ((result (list))) + (begin (js-list-keys-loop arr 0 result) result)))) + ((= name "values") (fn () (js-list-slice arr 0 (len arr)))) + ((= name "entries") + (fn + () + (let + ((result (list))) + (begin (js-list-entries-loop arr 0 result) result)))) + ((= name "copyWithin") + (fn + (&rest args) + (let + ((n (len arr)) + (target-raw + (if (empty? args) 0 (js-num-to-int (nth args 0)))) + (start-raw + (if (< (len args) 2) 0 (js-num-to-int (nth args 1)))) + (end-raw + (if + (< (len args) 3) + (len arr) + (js-num-to-int (nth args 2))))) + (let + ((target (cond ((< target-raw 0) (max 0 (+ n target-raw))) (else (min n target-raw)))) + (start + (cond + ((< start-raw 0) (max 0 (+ n start-raw))) + (else (min n start-raw)))) + (end + (cond + ((< end-raw 0) (max 0 (+ n end-raw))) + (else (min n end-raw))))) + (begin (js-list-copy-within! arr target start end) arr))))) + ((= name "toReversed") + (fn () (js-list-reverse-loop arr (- (len arr) 1) (list)))) + ((= name "toSorted") + (fn + (&rest args) + (let + ((cmp (if (empty? args) nil (nth args 0))) + (copy (js-list-slice arr 0 (len arr)))) + (begin (js-list-sort! copy cmp) copy)))) (else js-undefined)))) (define pop-last! (fn (lst) nil)) @@ -1267,6 +1367,73 @@ (append! acc (nth arr i)) (js-list-reverse-loop arr (- i 1) acc)))))) +(define + js-list-find-last-loop + (fn + (f arr i) + (cond + ((< i 0) :js-undefined) + ((js-to-boolean (f (nth arr i))) (nth arr i)) + (else (js-list-find-last-loop f arr (- i 1)))))) + +(define + js-list-find-last-index-loop + (fn + (f arr i) + (cond + ((< i 0) -1) + ((js-to-boolean (f (nth arr i))) i) + (else (js-list-find-last-index-loop f arr (- i 1)))))) + +(define + js-list-reduce-right-loop + (fn + (f acc arr i) + (if + (< i 0) + acc + (js-list-reduce-right-loop f (f acc (nth arr i)) arr (- i 1))))) + +(define + js-list-keys-loop + (fn + (arr i result) + (if + (>= i (len arr)) + result + (begin (append! result i) (js-list-keys-loop arr (+ i 1) result))))) + +(define + js-list-entries-loop + (fn + (arr i result) + (if + (>= i (len arr)) + result + (begin + (append! result (list i (nth arr i))) + (js-list-entries-loop arr (+ i 1) result))))) + +(define + js-list-copy-within! + (fn + (arr target start end) + (let + ((snap (js-list-slice arr start end))) + (js-list-copy-within-loop! arr target snap 0)))) + +(define + js-list-copy-within-loop! + (fn + (arr target snap i) + (cond + ((>= i (len snap)) arr) + ((>= (+ target i) (len arr)) arr) + (else + (begin + (set-nth! arr (+ target i) (nth snap i)) + (js-list-copy-within-loop! arr target snap (+ i 1))))))) + (define js-string-repeat (fn @@ -1577,6 +1744,21 @@ ((= key "fill") (js-array-method obj "fill")) ((= key "sort") (js-array-method obj "sort")) ((= key "lastIndexOf") (js-array-method obj "lastIndexOf")) + ((= key "at") (js-array-method obj "at")) + ((= key "unshift") (js-array-method obj "unshift")) + ((= key "splice") (js-array-method obj "splice")) + ((= key "flatMap") (js-array-method obj "flatMap")) + ((= key "findLast") (js-array-method obj "findLast")) + ((= key "findLastIndex") (js-array-method obj "findLastIndex")) + ((= key "reduceRight") (js-array-method obj "reduceRight")) + ((= key "toString") (js-array-method obj "toString")) + ((= key "toLocaleString") (js-array-method obj "toLocaleString")) + ((= key "keys") (js-array-method obj "keys")) + ((= key "values") (js-array-method obj "values")) + ((= key "entries") (js-array-method obj "entries")) + ((= key "copyWithin") (js-array-method obj "copyWithin")) + ((= key "toReversed") (js-array-method obj "toReversed")) + ((= key "toSorted") (js-array-method obj "toSorted")) (else js-undefined))) ((= (type-of obj) "string") (cond diff --git a/lib/js/test.sh b/lib/js/test.sh index 771a67f5..ae9fc823 100755 --- a/lib/js/test.sh +++ b/lib/js/test.sh @@ -1191,6 +1191,28 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 3609) (eval "(js-eval \"(true).valueOf()\")") +;; ── Phase 11.arrmore: more Array.prototype methods ────────── +(epoch 3700) +(eval "(js-eval \"[1,2,3].at(0)\")") +(epoch 3701) +(eval "(js-eval \"[1,2,3].at(-1)\")") +(epoch 3702) +(eval "(js-eval \"[1,2,3,4].flatMap(x=>[x,x*2]).join(',')\")") +(epoch 3703) +(eval "(js-eval \"[1,5,2,7,3].findLast(x=>x<5)\")") +(epoch 3704) +(eval "(js-eval \"[1,5,2,7,3].findLastIndex(x=>x<5)\")") +(epoch 3705) +(eval "(js-eval \"[1,2,3,4].reduceRight((acc,x)=>acc+','+x)\")") +(epoch 3706) +(eval "(js-eval \"[1,2,3].toString()\")") +(epoch 3707) +(eval "(js-eval \"[3,1,2].toReversed().join(',')\")") +(epoch 3708) +(eval "(js-eval \"[3,1,4,1,5].toSorted((a,b)=>a-b).join(',')\")") +(epoch 3709) +(eval "(js-eval \"var a=[1,2,3]; a.keys().join(',')\")") + ;; ── Phase 11.arrlike: Array.prototype.* on {length, 0:..., 1:...} ── (epoch 3500) (eval "(js-eval \"var a = {length: 3, 0: 41, 1: 42, 2: 43}; Array.prototype.slice.call(a).length\")") @@ -1853,6 +1875,18 @@ check 3607 "true.toString()" '"true"' check 3608 "false.toString()" '"false"' check 3609 "(true).valueOf()" 'true' +# ── Phase 11.arrmore: more Array.prototype methods ──────────── +check 3700 "arr.at(0)" '1' +check 3701 "arr.at(-1)" '3' +check 3702 "arr.flatMap" '"1,2,2,4,3,6,4,8"' +check 3703 "arr.findLast" '3' +check 3704 "arr.findLastIndex" '4' +check 3705 "arr.reduceRight" '"4,3,2,1"' +check 3706 "arr.toString" '"1,2,3"' +check 3707 "arr.toReversed" '"2,1,3"' +check 3708 "arr.toSorted" '"1,1,3,4,5"' +check 3709 "arr.keys" '"0,1,2"' + # ── Phase 11.arrlike: array-like receivers on Array.prototype ─ check 3500 "slice.call arrLike length" '3' check 3501 "slice.call arrLike join" '"41,42,43"'