js-on-sx: callable Number/String/Boolean/Array + Array.sort
Builtin constructors now have :__callable__ slot. js-call-plain
and js-function? detect dicts with __callable__ and dispatch
through it. Number('42')===42, String(true)==='true', Boolean(0)
===false, Array(3) builds length-3 list.
Array.prototype.sort(comparator?): bubble sort via js-list-sort-
outer!/-inner!. Default lex order, custom comparator supported.
Wide scoreboard committed: 259/5354 (4.8%) from earlier runtime.
438/440 unit (+11), 148/148 slice unchanged.
This commit is contained in:
@@ -232,6 +232,8 @@
|
||||
(cond
|
||||
((js-undefined? fn-val)
|
||||
(error "TypeError: undefined is not a function"))
|
||||
((and (dict? fn-val) (contains? (keys fn-val) "__callable__"))
|
||||
(js-call-with-this :js-undefined (get fn-val "__callable__") args))
|
||||
(else (js-call-with-this :js-undefined fn-val args)))))
|
||||
|
||||
(define
|
||||
@@ -396,7 +398,11 @@
|
||||
(v)
|
||||
(let
|
||||
((t (type-of v)))
|
||||
(or (= t "lambda") (= t "function") (= t "component")))))
|
||||
(or
|
||||
(= t "lambda")
|
||||
(= t "function")
|
||||
(= t "component")
|
||||
(and (= t "dict") (contains? (keys v) "__callable__"))))))
|
||||
|
||||
;; Bitwise + logical-not
|
||||
(define __js_proto_table__ (dict))
|
||||
@@ -835,6 +841,13 @@
|
||||
(js-num-to-int (nth args 2)))))
|
||||
(js-list-fill-loop arr v s e)
|
||||
arr)))
|
||||
((= name "sort")
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((cmp (if (= (len args) 0) nil (nth args 0))))
|
||||
(js-list-sort! arr cmp)
|
||||
arr)))
|
||||
(else js-undefined))))
|
||||
|
||||
(define pop-last! (fn (lst) nil))
|
||||
@@ -1009,6 +1022,38 @@
|
||||
(else
|
||||
(begin (js-list-set! arr s v) (js-list-fill-loop arr v (+ s 1) e))))))
|
||||
|
||||
(define
|
||||
js-list-sort!
|
||||
(fn (arr cmp) (let ((n (len arr))) (js-list-sort-outer! arr cmp 0 n))))
|
||||
|
||||
(define
|
||||
js-list-sort-outer!
|
||||
(fn
|
||||
(arr cmp i n)
|
||||
(cond
|
||||
((>= i n) nil)
|
||||
(else
|
||||
(begin
|
||||
(js-list-sort-inner! arr cmp 0 (- n i 1))
|
||||
(js-list-sort-outer! arr cmp (+ i 1) n))))))
|
||||
|
||||
(define
|
||||
js-list-sort-inner!
|
||||
(fn
|
||||
(arr cmp i end)
|
||||
(cond
|
||||
((>= i end) nil)
|
||||
(else
|
||||
(begin
|
||||
(let
|
||||
((a (nth arr i)) (b (nth arr (+ i 1))))
|
||||
(let
|
||||
((result (if (= cmp nil) (if (js-str-lt (js-to-string b) (js-to-string a)) 1 -1) (js-to-number (cmp a b)))))
|
||||
(when
|
||||
(> result 0)
|
||||
(begin (js-list-set! arr i b) (js-list-set! arr (+ i 1) a)))))
|
||||
(js-list-sort-inner! arr cmp (+ i 1) end))))))
|
||||
|
||||
(define
|
||||
js-list-every-loop
|
||||
(fn
|
||||
@@ -1337,6 +1382,7 @@
|
||||
((= key "reverse") (js-array-method obj "reverse"))
|
||||
((= key "flat") (js-array-method obj "flat"))
|
||||
((= key "fill") (js-array-method obj "fill"))
|
||||
((= key "sort") (js-array-method obj "sort"))
|
||||
(else js-undefined)))
|
||||
((= (type-of obj) "string")
|
||||
(cond
|
||||
@@ -1566,7 +1612,7 @@
|
||||
|
||||
(define js-global-is-nan (fn (v) (js-number-is-nan (js-to-number v))))
|
||||
|
||||
(define Number {:isFinite js-number-is-finite :MAX_SAFE_INTEGER 9007199254740991 :EPSILON 2.22045e-16 :MAX_VALUE 0 :POSITIVE_INFINITY inf :isInteger js-number-is-integer :isNaN js-number-is-nan :isSafeInteger js-number-is-safe-integer :NEGATIVE_INFINITY -inf :NaN 0 :MIN_VALUE 4.94066e-324 :MIN_SAFE_INTEGER -9007199254740991})
|
||||
(define Number {:isFinite js-number-is-finite :MAX_SAFE_INTEGER 9007199254740991 :EPSILON 2.22045e-16 :MAX_VALUE 0 :POSITIVE_INFINITY inf :__callable__ js-to-number :isInteger js-number-is-integer :isNaN js-number-is-nan :isSafeInteger js-number-is-safe-integer :NEGATIVE_INFINITY -inf :NaN 0 :MIN_VALUE 4.94066e-324 :MIN_SAFE_INTEGER -9007199254740991})
|
||||
|
||||
(define isFinite js-global-is-finite)
|
||||
|
||||
@@ -1815,7 +1861,7 @@
|
||||
src)
|
||||
result)))))))
|
||||
|
||||
(define Array {:isArray js-array-is-array :of js-array-of :from js-array-from})
|
||||
(define Array {:__callable__ (fn (&rest args) (cond ((= (len args) 0) (list)) ((and (= (len args) 1) (number? (nth args 0))) (js-make-list-of-length (js-num-to-int (nth args 0)) js-undefined)) (else args))) :isArray js-array-is-array :of js-array-of :from js-array-from})
|
||||
|
||||
(define
|
||||
js-string-from-char-code
|
||||
@@ -1833,7 +1879,9 @@
|
||||
(+ i 1)
|
||||
(str acc (js-code-to-char (js-num-to-int (nth args i))))))))
|
||||
|
||||
(define String {:fromCharCode js-string-from-char-code})
|
||||
(define String {:fromCharCode js-string-from-char-code :__callable__ (fn (&rest args) (if (= (len args) 0) "" (js-to-string (nth args 0))))})
|
||||
|
||||
(define Boolean {:__callable__ (fn (&rest args) (if (= (len args) 0) false (js-to-boolean (nth args 0))))})
|
||||
|
||||
(define
|
||||
parseInt
|
||||
@@ -2508,4 +2556,4 @@
|
||||
(str "/" (get rx "source") "/" (get rx "flags")))
|
||||
(else js-undefined))))
|
||||
|
||||
(define js-global {:isFinite js-global-is-finite :console console :Number Number :parseFloat parseFloat :Math Math :Array Array :String String :NaN 0 :Infinity inf :isNaN js-global-is-nan :Object Object :parseInt parseInt :JSON JSON :undefined js-undefined})
|
||||
(define js-global {:isFinite js-global-is-finite :console console :Number Number :parseFloat parseFloat :Math Math :Array Array :Boolean Boolean :String String :NaN 0 :Infinity inf :isNaN js-global-is-nan :Object Object :parseInt parseInt :JSON JSON :undefined js-undefined})
|
||||
|
||||
@@ -1103,6 +1103,32 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 2803)
|
||||
(eval "(js-eval \"var q=42; q??=99; q\")")
|
||||
|
||||
;; ── Phase 11.callable: Number()/String()/Boolean()/Array() ─────
|
||||
(epoch 2900)
|
||||
(eval "(js-eval \"Number('42')\")")
|
||||
(epoch 2901)
|
||||
(eval "(js-eval \"String(123)\")")
|
||||
(epoch 2902)
|
||||
(eval "(js-eval \"String(true)\")")
|
||||
(epoch 2903)
|
||||
(eval "(js-eval \"Boolean(0)\")")
|
||||
(epoch 2904)
|
||||
(eval "(js-eval \"Boolean('hi')\")")
|
||||
(epoch 2905)
|
||||
(eval "(js-eval \"Array(3).length\")")
|
||||
(epoch 2906)
|
||||
(eval "(js-eval \"Array(1,2,3).length\")")
|
||||
|
||||
;; ── Phase 11.sort: Array.prototype.sort ──────────────────────
|
||||
(epoch 3000)
|
||||
(eval "(js-eval \"[3,1,2].sort().join(',')\")")
|
||||
(epoch 3001)
|
||||
(eval "(js-eval \"[10,5,20].sort().join(',')\")")
|
||||
(epoch 3002)
|
||||
(eval "(js-eval \"[3,1,2].sort((a,b)=>a-b).join(',')\")")
|
||||
(epoch 3003)
|
||||
(eval "(js-eval \"[3,1,2].sort((a,b)=>b-a).join(',')\")")
|
||||
|
||||
EPOCHS
|
||||
|
||||
|
||||
@@ -1699,6 +1725,21 @@ check 2801 "&&= truthy" '7'
|
||||
check 2802 "??= null" '99'
|
||||
check 2803 "??= has value" '42'
|
||||
|
||||
# ── Phase 11.callable ─────────────────────────────────────────
|
||||
check 2900 "Number('42')" '42'
|
||||
check 2901 "String(123)" '"123"'
|
||||
check 2902 "String(true)" '"true"'
|
||||
check 2903 "Boolean(0)" 'false'
|
||||
check 2904 "Boolean('hi')" 'true'
|
||||
check 2905 "Array(3).length" '3'
|
||||
check 2906 "Array(1,2,3).length" '3'
|
||||
|
||||
# ── Phase 11.sort ────────────────────────────────────────────
|
||||
check 3000 "sort default" '"1,2,3"'
|
||||
check 3001 "sort lex (10<5)" '"10,20,5"'
|
||||
check 3002 "sort numeric" '"1,2,3"'
|
||||
check 3003 "sort reverse" '"3,2,1"'
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "✓ $PASS/$TOTAL JS-on-SX tests passed"
|
||||
|
||||
313
lib/js/test262-scoreboard-wide.json
Normal file
313
lib/js/test262-scoreboard-wide.json
Normal file
@@ -0,0 +1,313 @@
|
||||
{
|
||||
"totals": {
|
||||
"pass": 259,
|
||||
"fail": 4768,
|
||||
"skip": 2534,
|
||||
"timeout": 327,
|
||||
"total": 7888,
|
||||
"runnable": 5354,
|
||||
"pass_rate": 4.8
|
||||
},
|
||||
"categories": [
|
||||
{
|
||||
"category": "built-ins/Array",
|
||||
"total": 3081,
|
||||
"pass": 58,
|
||||
"fail": 2524,
|
||||
"skip": 351,
|
||||
"timeout": 148,
|
||||
"pass_rate": 2.1,
|
||||
"top_failures": [
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
785
|
||||
],
|
||||
[
|
||||
"Other: \"Not callable: {:length 3 :0 41 :1 42 :2 43} (kont=5 frames)\"",
|
||||
455
|
||||
],
|
||||
[
|
||||
"Unhandled: Unhandled exception: \\\\\\",
|
||||
420
|
||||
],
|
||||
[
|
||||
"TypeError: not a function",
|
||||
284
|
||||
],
|
||||
[
|
||||
"Timeout",
|
||||
148
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "built-ins/ArrayBuffer",
|
||||
"total": 196,
|
||||
"pass": 0,
|
||||
"fail": 0,
|
||||
"skip": 196,
|
||||
"timeout": 0,
|
||||
"pass_rate": 0.0,
|
||||
"top_failures": []
|
||||
},
|
||||
{
|
||||
"category": "built-ins/ArrayIteratorPrototype",
|
||||
"total": 27,
|
||||
"pass": 0,
|
||||
"fail": 0,
|
||||
"skip": 27,
|
||||
"timeout": 0,
|
||||
"pass_rate": 0.0,
|
||||
"top_failures": []
|
||||
},
|
||||
{
|
||||
"category": "built-ins/Math",
|
||||
"total": 327,
|
||||
"pass": 65,
|
||||
"fail": 211,
|
||||
"skip": 39,
|
||||
"timeout": 12,
|
||||
"pass_rate": 22.6,
|
||||
"top_failures": [
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
87
|
||||
],
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
80
|
||||
],
|
||||
[
|
||||
"TypeError: not a function",
|
||||
31
|
||||
],
|
||||
[
|
||||
"Timeout",
|
||||
12
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:isArray <js-array-is-array(v)> :of <js-array",
|
||||
11
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "built-ins/Number",
|
||||
"total": 340,
|
||||
"pass": 9,
|
||||
"fail": 252,
|
||||
"skip": 57,
|
||||
"timeout": 22,
|
||||
"pass_rate": 3.2,
|
||||
"top_failures": [
|
||||
[
|
||||
"TypeError: not a function",
|
||||
72
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:isFinite <js-number-is-finite(v)> :MAX_SAFE_",
|
||||
56
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
49
|
||||
],
|
||||
[
|
||||
"Unhandled: expected ident after .\\",
|
||||
38
|
||||
],
|
||||
[
|
||||
"Timeout",
|
||||
22
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "built-ins/String",
|
||||
"total": 1223,
|
||||
"pass": 73,
|
||||
"fail": 847,
|
||||
"skip": 192,
|
||||
"timeout": 111,
|
||||
"pass_rate": 7.1,
|
||||
"top_failures": [
|
||||
[
|
||||
"Unhandled: Not callable: \\\\\\",
|
||||
152
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:fromCharCode <js-string-from-char-code(&rest",
|
||||
133
|
||||
],
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
124
|
||||
],
|
||||
[
|
||||
"TypeError: not a function",
|
||||
117
|
||||
],
|
||||
[
|
||||
"Other: \"Not callable: \\\"js-undefined\\\" (kont=10 frames)\"",
|
||||
117
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "built-ins/StringIteratorPrototype",
|
||||
"total": 7,
|
||||
"pass": 0,
|
||||
"fail": 0,
|
||||
"skip": 7,
|
||||
"timeout": 0,
|
||||
"pass_rate": 0.0,
|
||||
"top_failures": []
|
||||
},
|
||||
{
|
||||
"category": "language/expressions",
|
||||
"total": 95,
|
||||
"pass": 14,
|
||||
"fail": 36,
|
||||
"skip": 29,
|
||||
"timeout": 16,
|
||||
"pass_rate": 21.2,
|
||||
"top_failures": [
|
||||
[
|
||||
"Timeout",
|
||||
16
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
14
|
||||
],
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
12
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:fromCharCode <js-string-from-char-code(&rest",
|
||||
3
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:entries <js-object-entries(o)> :values <js-o",
|
||||
2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "language/statements",
|
||||
"total": 2592,
|
||||
"pass": 40,
|
||||
"fail": 898,
|
||||
"skip": 1636,
|
||||
"timeout": 18,
|
||||
"pass_rate": 4.2,
|
||||
"top_failures": [
|
||||
[
|
||||
"SyntaxError (parse/unsupported syntax)",
|
||||
387
|
||||
],
|
||||
[
|
||||
"Unhandled: expected ident in arr pattern\\",
|
||||
112
|
||||
],
|
||||
[
|
||||
"Other: \"Not callable: \\\"ud801\\\" (kont=6 frames)\"",
|
||||
49
|
||||
],
|
||||
[
|
||||
"negative: expected SyntaxError, got: \"Unhandled exception: \\\"expected ident in arr pattern\\\"\"",
|
||||
36
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
33
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"top_failure_modes": [
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
1056
|
||||
],
|
||||
[
|
||||
"TypeError: not a function",
|
||||
514
|
||||
],
|
||||
[
|
||||
"Other: \"Not callable: {:length 3 :0 41 :1 42 :2 43} (kont=5 frames)\"",
|
||||
455
|
||||
],
|
||||
[
|
||||
"SyntaxError (parse/unsupported syntax)",
|
||||
454
|
||||
],
|
||||
[
|
||||
"Unhandled: Unhandled exception: \\\\\\",
|
||||
438
|
||||
],
|
||||
[
|
||||
"Timeout",
|
||||
327
|
||||
],
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
322
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: \\\\\\",
|
||||
160
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:fromCharCode <js-string-from-char-code(&rest",
|
||||
147
|
||||
],
|
||||
[
|
||||
"Unhandled: Unexpected token: punct ','\\",
|
||||
125
|
||||
],
|
||||
[
|
||||
"Other: \"Not callable: \\\"js-undefined\\\" (kont=10 frames)\"",
|
||||
117
|
||||
],
|
||||
[
|
||||
"Unhandled: expected ident in arr pattern\\",
|
||||
112
|
||||
],
|
||||
[
|
||||
"Unhandled: js-transpile-unop: unsupported op: delete\\",
|
||||
104
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:isFinite <js-number-is-finite(v)> :MAX_SAFE_",
|
||||
74
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:sameValue <lambda(actual, expected, message)",
|
||||
63
|
||||
],
|
||||
[
|
||||
"Other: \"Not callable: \\\"ud801\\\" (kont=6 frames)\"",
|
||||
49
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:isArray <js-array-is-array(v)> :of <js-array",
|
||||
46
|
||||
],
|
||||
[
|
||||
"Unhandled: expected ident after .\\",
|
||||
45
|
||||
],
|
||||
[
|
||||
"Unhandled: Unexpected token: op '++'\\",
|
||||
39
|
||||
],
|
||||
[
|
||||
"negative: expected SyntaxError, got: \"Unhandled exception: \\\"expected ident in arr pattern\\\"\"",
|
||||
36
|
||||
]
|
||||
],
|
||||
"pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33",
|
||||
"elapsed_seconds": 9007.6
|
||||
}
|
||||
90
lib/js/test262-scoreboard-wide.md
Normal file
90
lib/js/test262-scoreboard-wide.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# test262 scoreboard
|
||||
|
||||
Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33`
|
||||
Wall time: 9007.6s
|
||||
|
||||
**Total:** 259/5354 runnable passed (4.8%). Raw: pass=259 fail=4768 skip=2534 timeout=327 total=7888.
|
||||
|
||||
## Top failure modes
|
||||
|
||||
- **1056x** ReferenceError (undefined symbol)
|
||||
- **514x** TypeError: not a function
|
||||
- **455x** Other: "Not callable: {:length 3 :0 41 :1 42 :2 43} (kont=5 frames)"
|
||||
- **454x** SyntaxError (parse/unsupported syntax)
|
||||
- **438x** Unhandled: Unhandled exception: \\\
|
||||
- **327x** Timeout
|
||||
- **322x** Test262Error (assertion failed)
|
||||
- **160x** Unhandled: Not callable: \\\
|
||||
- **147x** Unhandled: Not callable: {:fromCharCode <js-string-from-char-code(&rest
|
||||
- **125x** Unhandled: Unexpected token: punct ','\
|
||||
- **117x** Other: "Not callable: \"js-undefined\" (kont=10 frames)"
|
||||
- **112x** Unhandled: expected ident in arr pattern\
|
||||
- **104x** Unhandled: js-transpile-unop: unsupported op: delete\
|
||||
- **74x** Unhandled: Not callable: {:isFinite <js-number-is-finite(v)> :MAX_SAFE_
|
||||
- **63x** Unhandled: Not callable: {:sameValue <lambda(actual, expected, message)
|
||||
- **49x** Other: "Not callable: \"ud801\" (kont=6 frames)"
|
||||
- **46x** Unhandled: Not callable: {:isArray <js-array-is-array(v)> :of <js-array
|
||||
- **45x** Unhandled: expected ident after .\
|
||||
- **39x** Unhandled: Unexpected token: op '++'\
|
||||
- **36x** negative: expected SyntaxError, got: "Unhandled exception: \"expected ident in arr pattern\""
|
||||
|
||||
## Categories (worst pass-rate first, min 10 runnable)
|
||||
|
||||
| Category | Pass | Fail | Skip | Timeout | Total | Pass % |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| built-ins/Array | 58 | 2524 | 351 | 148 | 3081 | 2.1% |
|
||||
| built-ins/Number | 9 | 252 | 57 | 22 | 340 | 3.2% |
|
||||
| language/statements | 40 | 898 | 1636 | 18 | 2592 | 4.2% |
|
||||
| built-ins/String | 73 | 847 | 192 | 111 | 1223 | 7.1% |
|
||||
| language/expressions | 14 | 36 | 29 | 16 | 95 | 21.2% |
|
||||
| built-ins/Math | 65 | 211 | 39 | 12 | 327 | 22.6% |
|
||||
|
||||
## Per-category top failures (min 10 runnable, worst first)
|
||||
|
||||
### built-ins/Array (58/2730 — 2.1%)
|
||||
|
||||
- **785x** ReferenceError (undefined symbol)
|
||||
- **455x** Other: "Not callable: {:length 3 :0 41 :1 42 :2 43} (kont=5 frames)"
|
||||
- **420x** Unhandled: Unhandled exception: \\\
|
||||
- **284x** TypeError: not a function
|
||||
- **148x** Timeout
|
||||
|
||||
### built-ins/Number (9/283 — 3.2%)
|
||||
|
||||
- **72x** TypeError: not a function
|
||||
- **56x** Unhandled: Not callable: {:isFinite <js-number-is-finite(v)> :MAX_SAFE_
|
||||
- **49x** ReferenceError (undefined symbol)
|
||||
- **38x** Unhandled: expected ident after .\
|
||||
- **22x** Timeout
|
||||
|
||||
### language/statements (40/956 — 4.2%)
|
||||
|
||||
- **387x** SyntaxError (parse/unsupported syntax)
|
||||
- **112x** Unhandled: expected ident in arr pattern\
|
||||
- **49x** Other: "Not callable: \"ud801\" (kont=6 frames)"
|
||||
- **36x** negative: expected SyntaxError, got: "Unhandled exception: \"expected ident in arr pattern\""
|
||||
- **33x** ReferenceError (undefined symbol)
|
||||
|
||||
### built-ins/String (73/1031 — 7.1%)
|
||||
|
||||
- **152x** Unhandled: Not callable: \\\
|
||||
- **133x** Unhandled: Not callable: {:fromCharCode <js-string-from-char-code(&rest
|
||||
- **124x** Test262Error (assertion failed)
|
||||
- **117x** TypeError: not a function
|
||||
- **117x** Other: "Not callable: \"js-undefined\" (kont=10 frames)"
|
||||
|
||||
### language/expressions (14/66 — 21.2%)
|
||||
|
||||
- **16x** Timeout
|
||||
- **14x** ReferenceError (undefined symbol)
|
||||
- **12x** Test262Error (assertion failed)
|
||||
- **3x** Unhandled: Not callable: {:fromCharCode <js-string-from-char-code(&rest
|
||||
- **2x** Unhandled: Not callable: {:entries <js-object-entries(o)> :values <js-o
|
||||
|
||||
### built-ins/Math (65/288 — 22.6%)
|
||||
|
||||
- **87x** ReferenceError (undefined symbol)
|
||||
- **80x** Test262Error (assertion failed)
|
||||
- **31x** TypeError: not a function
|
||||
- **12x** Timeout
|
||||
- **11x** Unhandled: Not callable: {:isArray <js-array-is-array(v)> :of <js-array
|
||||
@@ -195,6 +195,10 @@ Append-only record of completed iterations. Loop writes one line per iteration:
|
||||
|
||||
- 2026-04-23 — **Object + array destructuring in var/let/const decls.** Parser: `jp-parse-vardecl` now handles three shapes — plain `ident`, `{a, b, c}` object pattern, `[a, , c]` array pattern with hole support. `jp-parse-obj-pattern` / `jp-parse-arr-pattern` / their loops collect the names. AST: `(js-vardecl-obj (names...) rhs)` and `(js-vardecl-arr (names-with-holes-as-nil...) rhs)`. Transpile: `js-vardecl-forms` dispatches on the three tags. Destructures emit `(define __destruct__ rhs)` then `(define name (js-get-prop __destruct__ key-or-index))` for each pattern element (skips nil holes in array patterns). 4 new unit tests. 418/420 (414→+4). Conformance unchanged. Gotcha: running destructuring tests sequentially — if epoch N defines `a, b` globally and epoch N+1 uses the same names as different types, "Not callable: N" results. Top-level `var` transpiles to `(define name value)`; re-defining a name that's held a value in a prior call to eval carries over. The proper fix would be to use `let` block-scoping; workaround for tests is unique names.
|
||||
|
||||
- 2026-04-23 — **Optional chaining `?.` + logical assignment `&&= / ||= / ??=`.** Parser: `jp-parse-postfix` handles `op "?."` followed by ident / `[` / `(` emitting `(js-optchain-member obj name)` / `(js-optchain-index obj k)` / `(js-optchain-call callee args)`. Transpile: all emit `(js-optchain-get obj key)` or `(js-optchain-call fn args)` — runtime short-circuits to undefined when the receiver is null/undefined. Logical assignment: `js-compound-update` gains `&&=` / `||=` / `??=` cases that emit `(if (js-to-boolean lhs) rhs lhs)` / `(if (js-to-boolean lhs) lhs rhs)` / `(if nullish? rhs lhs)`. 9 new tests. 427/429 (418→+9). Conformance unchanged.
|
||||
|
||||
- 2026-04-23 — **Callable `Number() / String() / Boolean() / Array()` + `Array.prototype.sort`.** Made the builtin constructor dicts callable by adding a `:__callable__` slot that points to a conversion function; `js-call-plain` and `js-function?` now detect dicts with `__callable__` and dispatch through it. `Number("42") === 42`, `String(true) === "true"`, `Boolean(0) === false`, `Array(3)` returns length-3 list, `Array(1,2,3)` returns `[1,2,3]`. `Array.prototype.sort(comparator?)` added via bubble-sort O(n²) `js-list-sort-outer!` / `-inner!`. Default comparator is lexicographic (JS-spec `toString()` then compare). Custom comparators get `(cmp a b) → number` and swap when positive. 11 new tests. 438/440 (427→+11). Conformance unchanged. Wide scoreboard (Math+Number+String+Array+{addition,equals,if,for,while}): baseline **259/5354 (4.8%)** before these improvements; top failures were ReferenceError (1056×), TypeError not-a-function (514×), array-like `{length:3, 0:41, 1:42, 2:43}` receivers (455×), SyntaxError (454×). Need to re-run scoreboard to see the delta from all the April 23rd work.
|
||||
|
||||
## Phase 3-5 gotchas
|
||||
|
||||
Worth remembering for later phases:
|
||||
|
||||
Reference in New Issue
Block a user