js-on-sx: 15 new Array.prototype methods (at, flatMap, findLast, reduceRight, toString, toReversed, toSorted, ...)
New read-only methods added: - at(i) — negative-index aware - flatMap(f) — map then flatten one level - findLast(f) / findLastIndex(f) - reduceRight(f, init?) - toString / toLocaleString — join with ',' - keys() / values() / entries() — index/value/pair lists - copyWithin(target, start, end) — in-place via set-nth! - toReversed() / toSorted() — non-mutating variants Mutating methods (unshift, splice) are stubs that return correct lengths but don't mutate — we don't have a pop-first!/clear! primitive to rebuild the list in place. Tracked as a runtime limitation. 10 new unit tests, 479/481 total. Directly targets the 785x ReferenceError in built-ins/Array and the many .toString() crashes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"'
|
||||
|
||||
Reference in New Issue
Block a user