js-on-sx: raise JS TypeError for non-callable callee, undefined()
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 59s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 59s
Calling a non-callable raised an OCaml-level Eval_error "Not callable" that JS try/catch couldn't intercept. Added a (js-function? callable) precheck in js-apply-fn that raises a TypeError instance via (js-new-call TypeError (list msg)) so e instanceof TypeError is true. Same swap for the undefined() branch in js-call-plain (was raising a bare string). built-ins/String: 71/99 → 73/99 (canonical), 74/99 → 75/99 (isolated). conformance.sh: 148/148.
This commit is contained in:
@@ -425,30 +425,44 @@
|
||||
(fn-val args)
|
||||
(let
|
||||
((callable (if (and (dict? fn-val) (contains? (keys fn-val) "__callable__")) (get fn-val "__callable__") fn-val)))
|
||||
(cond
|
||||
((= (len args) 0) (callable))
|
||||
((= (len args) 1) (callable (nth args 0)))
|
||||
((= (len args) 2) (callable (nth args 0) (nth args 1)))
|
||||
((= (len args) 3)
|
||||
(callable (nth args 0) (nth args 1) (nth args 2)))
|
||||
((= (len args) 4)
|
||||
(callable (nth args 0) (nth args 1) (nth args 2) (nth args 3)))
|
||||
((= (len args) 5)
|
||||
(callable
|
||||
(nth args 0)
|
||||
(nth args 1)
|
||||
(nth args 2)
|
||||
(nth args 3)
|
||||
(nth args 4)))
|
||||
((= (len args) 6)
|
||||
(callable
|
||||
(nth args 0)
|
||||
(nth args 1)
|
||||
(nth args 2)
|
||||
(nth args 3)
|
||||
(nth args 4)
|
||||
(nth args 5)))
|
||||
(else (apply callable args))))))
|
||||
(if
|
||||
(not (js-function? callable))
|
||||
(raise
|
||||
(js-new-call
|
||||
TypeError
|
||||
(list (str (str fn-val) " is not a function"))))
|
||||
(cond
|
||||
((= (len args) 0) (callable))
|
||||
((= (len args) 1) (callable (nth args 0)))
|
||||
((= (len args) 2)
|
||||
(callable (nth args 0) (nth args 1)))
|
||||
((= (len args) 3)
|
||||
(callable
|
||||
(nth args 0)
|
||||
(nth args 1)
|
||||
(nth args 2)))
|
||||
((= (len args) 4)
|
||||
(callable
|
||||
(nth args 0)
|
||||
(nth args 1)
|
||||
(nth args 2)
|
||||
(nth args 3)))
|
||||
((= (len args) 5)
|
||||
(callable
|
||||
(nth args 0)
|
||||
(nth args 1)
|
||||
(nth args 2)
|
||||
(nth args 3)
|
||||
(nth args 4)))
|
||||
((= (len args) 6)
|
||||
(callable
|
||||
(nth args 0)
|
||||
(nth args 1)
|
||||
(nth args 2)
|
||||
(nth args 3)
|
||||
(nth args 4)
|
||||
(nth args 5)))
|
||||
(else (apply callable args)))))))
|
||||
|
||||
;; ── Relational comparisons ────────────────────────────────────────
|
||||
|
||||
@@ -608,7 +622,7 @@
|
||||
(fn-val args)
|
||||
(cond
|
||||
((js-undefined? fn-val)
|
||||
(error "TypeError: undefined is not a function"))
|
||||
(raise (js-new-call TypeError (list "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)))))
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"totals": {
|
||||
"pass": 71,
|
||||
"fail": 22,
|
||||
"pass": 73,
|
||||
"fail": 20,
|
||||
"skip": 1,
|
||||
"timeout": 6,
|
||||
"total": 100,
|
||||
"runnable": 99,
|
||||
"pass_rate": 71.7
|
||||
"pass_rate": 73.7
|
||||
},
|
||||
"categories": [
|
||||
{
|
||||
"category": "built-ins/String",
|
||||
"total": 100,
|
||||
"pass": 71,
|
||||
"fail": 22,
|
||||
"pass": 73,
|
||||
"fail": 20,
|
||||
"skip": 1,
|
||||
"timeout": 6,
|
||||
"pass_rate": 71.7,
|
||||
"pass_rate": 73.7,
|
||||
"top_failures": [
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
@@ -31,11 +31,11 @@
|
||||
6
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: \\\\\\",
|
||||
2
|
||||
"ReferenceError (undefined symbol)",
|
||||
1
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
"SyntaxError (parse/unsupported syntax)",
|
||||
1
|
||||
]
|
||||
]
|
||||
@@ -54,10 +54,6 @@
|
||||
"Timeout",
|
||||
6
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: \\\\\\",
|
||||
2
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
1
|
||||
@@ -68,6 +64,6 @@
|
||||
]
|
||||
],
|
||||
"pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33",
|
||||
"elapsed_seconds": 375.3,
|
||||
"elapsed_seconds": 280.3,
|
||||
"workers": 1
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
# test262 scoreboard
|
||||
|
||||
Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33`
|
||||
Wall time: 375.3s
|
||||
Wall time: 280.3s
|
||||
|
||||
**Total:** 71/99 runnable passed (71.7%). Raw: pass=71 fail=22 skip=1 timeout=6 total=100.
|
||||
**Total:** 73/99 runnable passed (73.7%). Raw: pass=73 fail=20 skip=1 timeout=6 total=100.
|
||||
|
||||
## Top failure modes
|
||||
|
||||
- **10x** Test262Error (assertion failed)
|
||||
- **8x** TypeError: not a function
|
||||
- **6x** Timeout
|
||||
- **2x** Unhandled: Not callable: \\\
|
||||
- **1x** ReferenceError (undefined symbol)
|
||||
- **1x** SyntaxError (parse/unsupported syntax)
|
||||
|
||||
@@ -18,14 +17,14 @@ Wall time: 375.3s
|
||||
|
||||
| Category | Pass | Fail | Skip | Timeout | Total | Pass % |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| built-ins/String | 71 | 22 | 1 | 6 | 100 | 71.7% |
|
||||
| built-ins/String | 73 | 20 | 1 | 6 | 100 | 73.7% |
|
||||
|
||||
## Per-category top failures (min 10 runnable, worst first)
|
||||
|
||||
### built-ins/String (71/99 — 71.7%)
|
||||
### built-ins/String (73/99 — 73.7%)
|
||||
|
||||
- **10x** Test262Error (assertion failed)
|
||||
- **8x** TypeError: not a function
|
||||
- **6x** Timeout
|
||||
- **2x** Unhandled: Not callable: \\\
|
||||
- **1x** ReferenceError (undefined symbol)
|
||||
- **1x** SyntaxError (parse/unsupported syntax)
|
||||
|
||||
@@ -158,6 +158,8 @@ Each item: implement → tests → update progress. Mark `[x]` when tests green.
|
||||
|
||||
Append-only record of completed iterations. Loop writes one line per iteration: date, what was done, test count delta.
|
||||
|
||||
- 2026-05-07 — **`js-apply-fn` raises a JS-level `TypeError` instance when the callee isn't callable.** Calling a non-callable (`'a'()`, `(1+2)()`, etc.) raised an OCaml-level `Eval_error "Not callable"` from the CEK call dispatcher, which the JS `try { } catch(e)` (which transpiles to `(guard ...)`) couldn't intercept. Added a `(js-function? callable)` precheck at the top of `js-apply-fn`: when false, `(raise (js-new-call TypeError ...))` produces an instance whose proto chain makes `e instanceof TypeError === true`. Also rewrote the `undefined()` case in `js-call-plain` to use the same constructor path (was raising a bare string). built-ins/String: 71/99 → 73/99 (canonical), 74/99 → 75/99 (isolated). conformance.sh: 148/148.
|
||||
|
||||
- 2026-05-07 — **`js-dict-get-walk` falls back to `Object.prototype` when an object has no `__proto__`.** Object literals (`{}`, `{a:1}`) didn't carry a `__proto__` link, so `({}).toString()` couldn't find `Object.prototype.toString` — and overriding `Object.prototype.toString` had no effect on plain objects. Added a cond clause in `js-dict-get-walk`: if the object has no `__proto__` AND is not `Object.prototype` itself, walk into `Object.prototype`. Termination guaranteed because Object.prototype is the recursion base case. Now `({}).toString() === "[object Object]"`, override of `Object.prototype.toString` propagates to plain objects, and `({a:1}).hasOwnProperty('a') === true`. built-ins/String: 69/99 → 71/99 (canonical), 71/99 → 74/99 (isolated). conformance.sh: 148/148.
|
||||
|
||||
- 2026-05-07 — **`js-new-call` accepts list-typed constructor returns (not just dict).** `new Array(1,2,3)` was returning an empty wrapper object because `js-new-call` only honoured a non-undefined return when `(type-of ret) === "dict"`; SX lists (which represent JS arrays here) were silently discarded in favour of the empty `obj`. Widened the check to accept `"list"` returns. Fixes `new Array(1,2,3).length`, `String(new Array(1,2,3))`, and any constructor whose body returns a list. built-ins/String 67/99 → 69/99 (canonical), 70/99 → 71/99 (isolated). conformance.sh: 148/148.
|
||||
|
||||
Reference in New Issue
Block a user