diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 023d4182..72bc49b3 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -1799,6 +1799,37 @@ result)) (else (list))))) +(define + js-arraylike-to-list + (fn + (v) + (cond + ((list? v) v) + ((= (type-of v) "string") (js-string-to-list v 0 (list))) + ((dict? v) + (let + ((n-val (get v "length"))) + (if + (or (= n-val nil) (js-undefined? n-val)) + (list) + (let + ((n (js-to-number n-val))) + (js-arraylike-to-list-loop v 0 n (list)))))) + (else (list))))) + +(define + js-arraylike-to-list-loop + (fn + (v i n acc) + (if + (>= i n) + acc + (let + ((val (get v (str i)))) + (do + (append! acc (if (= val nil) :js-undefined val)) + (js-arraylike-to-list-loop v (+ i 1) n acc)))))) + (define js-string-to-list (fn @@ -1933,7 +1964,11 @@ (name) (fn (&rest args) - (let ((this-val (js-this))) (js-invoke-method this-val name args))))) + (let + ((this-val (js-this))) + (let + ((recv (cond ((list? this-val) this-val) ((and (dict? this-val) (contains? (keys this-val) "length")) (js-arraylike-to-list this-val)) (else this-val)))) + (js-invoke-method recv name args)))))) (define js-array-from diff --git a/lib/js/test.sh b/lib/js/test.sh index fb266335..b6512405 100755 --- a/lib/js/test.sh +++ b/lib/js/test.sh @@ -1169,6 +1169,20 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 3405) (eval "(js-eval \"var arr2 = [1,2]; Array.prototype.push.call(arr2, 10, 20); arr2.length\")") +;; ── 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\")") +(epoch 3501) +(eval "(js-eval \"var a = {length: 3, 0: 41, 1: 42, 2: 43}; Array.prototype.slice.call(a).join(',')\")") +(epoch 3502) +(eval "(js-eval \"var a = {length: 3, 0: 1, 1: 2, 2: 3}; Array.prototype.map.call(a, function(x){return x*2;}).join(',')\")") +(epoch 3503) +(eval "(js-eval \"var a = {length: 3, 0: 1, 1: 2, 2: 3}; Array.prototype.indexOf.call(a, 2)\")") +(epoch 3504) +(eval "(js-eval \"var a = {length: 3, 0: 1, 1: 2, 2: 3}; Array.prototype.filter.call(a, function(x){return x>1;}).join(',')\")") +(epoch 3505) +(eval "(js-eval \"var a = {length: 3, 0: 10, 1: 20, 2: 30}; var sum = 0; Array.prototype.forEach.call(a, function(x){sum += x;}); sum\")") + EPOCHS @@ -1805,6 +1819,14 @@ check 3403 "fn.call this-binding" '42' check 3404 "fn.apply arg-unpack" '7' check 3405 "Array.prototype.push.call arr" '4' +# ── 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"' +check 3502 "map.call arrLike" '"2,4,6"' +check 3503 "indexOf.call arrLike" '1' +check 3504 "filter.call arrLike" '"2,3"' +check 3505 "forEach.call arrLike sum" '60' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "✓ $PASS/$TOTAL JS-on-SX tests passed"