js-on-sx: String fixes — fromCodePoint, multi-arg indexOf/split/lastIndexOf, matchAll, constructor, js-to-string dict
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
- String.fromCodePoint added (BMP + surrogate pairs) - indexOf/lastIndexOf/split now accept optional second argument (fromIndex / limit) - matchAll stub added to js-string-method and String.prototype - String property else-branch now falls back to String.prototype (fixes 'a'.constructor === String) - js-to-string for dict returns [object Object] instead of recursing into circular String.prototype.constructor structure - js-list-take helper added for split limit Scoreboard: String 42→43, timeouts 32→13, total 162→202/300 (54%→67.3%). 529/530 unit, 148/148 slice. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1169,7 +1169,7 @@
|
|||||||
((= v false) "false")
|
((= v false) "false")
|
||||||
((= (type-of v) "string") v)
|
((= (type-of v) "string") v)
|
||||||
((= (type-of v) "number") (js-number-to-string v))
|
((= (type-of v) "number") (js-number-to-string v))
|
||||||
(else (str v)))))
|
(else (if (= (type-of v) "dict") "[object Object]" (str v))))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
js-template-concat
|
js-template-concat
|
||||||
@@ -1903,7 +1903,15 @@
|
|||||||
(char-code (char-at s idx))
|
(char-code (char-at s idx))
|
||||||
0))))
|
0))))
|
||||||
((= name "indexOf")
|
((= name "indexOf")
|
||||||
(fn (needle) (js-string-index-of s (js-to-string needle) 0)))
|
(fn
|
||||||
|
(&rest args)
|
||||||
|
(if
|
||||||
|
(empty? args)
|
||||||
|
-1
|
||||||
|
(js-string-index-of
|
||||||
|
s
|
||||||
|
(js-to-string (nth args 0))
|
||||||
|
(if (< (len args) 2) 0 (max 0 (js-num-to-int (nth args 1))))))))
|
||||||
((= name "slice")
|
((= name "slice")
|
||||||
(fn
|
(fn
|
||||||
(&rest args)
|
(&rest args)
|
||||||
@@ -1927,7 +1935,16 @@
|
|||||||
(js-string-slice s lo (min hi (len s)))))))
|
(js-string-slice s lo (min hi (len s)))))))
|
||||||
((= name "toUpperCase") (fn () (js-upper-case s)))
|
((= name "toUpperCase") (fn () (js-upper-case s)))
|
||||||
((= name "toLowerCase") (fn () (js-lower-case s)))
|
((= name "toLowerCase") (fn () (js-lower-case s)))
|
||||||
((= name "split") (fn (sep) (js-string-split s (js-to-string sep))))
|
((= name "split")
|
||||||
|
(fn
|
||||||
|
(&rest args)
|
||||||
|
(let
|
||||||
|
((sep (if (= (len args) 0) :js-undefined (nth args 0)))
|
||||||
|
(limit
|
||||||
|
(if (< (len args) 2) -1 (js-num-to-int (nth args 1)))))
|
||||||
|
(let
|
||||||
|
((result (js-string-split s (js-to-string sep))))
|
||||||
|
(if (< limit 0) result (js-list-take result limit))))))
|
||||||
((= name "concat")
|
((= name "concat")
|
||||||
(fn (&rest args) (js-string-concat-loop s args 0)))
|
(fn (&rest args) (js-string-concat-loop s args 0)))
|
||||||
((= name "includes")
|
((= name "includes")
|
||||||
@@ -2042,6 +2059,17 @@
|
|||||||
(= idx -1)
|
(= idx -1)
|
||||||
nil
|
nil
|
||||||
(let ((res (list))) (append! res needle) res))))))))
|
(let ((res (list))) (append! res needle) res))))))))
|
||||||
|
((= name "matchAll")
|
||||||
|
(fn
|
||||||
|
(&rest args)
|
||||||
|
(if
|
||||||
|
(empty? args)
|
||||||
|
(list)
|
||||||
|
(let
|
||||||
|
((needle (js-to-string (nth args 0))))
|
||||||
|
(let
|
||||||
|
((loop (fn (start acc) (let ((idx (js-string-index-of s needle start))) (if (= idx -1) acc (let ((m (list))) (begin (append! m needle) (dict-set! m "index" idx) (loop (+ idx (max 1 (len needle))) (begin (append! acc m) acc)))))))))
|
||||||
|
(loop 0 (list)))))))
|
||||||
((= name "at")
|
((= name "at")
|
||||||
(fn
|
(fn
|
||||||
(i)
|
(i)
|
||||||
@@ -2068,7 +2096,14 @@
|
|||||||
-1
|
-1
|
||||||
(let
|
(let
|
||||||
((needle (js-to-string (nth args 0))))
|
((needle (js-to-string (nth args 0))))
|
||||||
(js-string-last-index-of s needle (- (len s) (len needle)))))))
|
(let
|
||||||
|
((default-start (- (len s) (len needle)))
|
||||||
|
(from
|
||||||
|
(if (< (len args) 2) -1 (js-num-to-int (nth args 1)))))
|
||||||
|
(js-string-last-index-of
|
||||||
|
s
|
||||||
|
needle
|
||||||
|
(if (< from 0) default-start (min from default-start))))))))
|
||||||
((= name "localeCompare")
|
((= name "localeCompare")
|
||||||
(fn
|
(fn
|
||||||
(&rest args)
|
(&rest args)
|
||||||
@@ -2166,6 +2201,15 @@
|
|||||||
((not (= (char-at s (+ si ni)) (char-at needle ni))) false)
|
((not (= (char-at s (+ si ni)) (char-at needle ni))) false)
|
||||||
(else (js-string-matches? s needle si (+ ni 1))))))
|
(else (js-string-matches? s needle si (+ ni 1))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
js-list-take
|
||||||
|
(fn
|
||||||
|
(lst n)
|
||||||
|
(if
|
||||||
|
(or (<= n 0) (empty? lst))
|
||||||
|
(list)
|
||||||
|
(cons (first lst) (js-list-take (rest lst) (- n 1))))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
js-string-split
|
js-string-split
|
||||||
(fn
|
(fn
|
||||||
@@ -2306,7 +2350,13 @@
|
|||||||
(js-string-method obj "toLocaleUpperCase"))
|
(js-string-method obj "toLocaleUpperCase"))
|
||||||
((= key "isWellFormed") (js-string-method obj "isWellFormed"))
|
((= key "isWellFormed") (js-string-method obj "isWellFormed"))
|
||||||
((= key "toWellFormed") (js-string-method obj "toWellFormed"))
|
((= key "toWellFormed") (js-string-method obj "toWellFormed"))
|
||||||
(else js-undefined)))
|
(else
|
||||||
|
(let
|
||||||
|
((proto (get String "prototype")))
|
||||||
|
(if
|
||||||
|
(and (dict? proto) (contains? (keys proto) key))
|
||||||
|
(get proto key)
|
||||||
|
js-undefined)))))
|
||||||
((= (type-of obj) "dict")
|
((= (type-of obj) "dict")
|
||||||
(js-dict-get-walk obj (js-to-string key)))
|
(js-dict-get-walk obj (js-to-string key)))
|
||||||
((and (= obj Promise) (dict-has? __js_promise_statics__ (js-to-string key)))
|
((and (= obj Promise) (dict-has? __js_promise_statics__ (js-to-string key)))
|
||||||
@@ -3028,6 +3078,35 @@
|
|||||||
js-string-from-char-code
|
js-string-from-char-code
|
||||||
(fn (&rest args) (js-string-from-char-code-loop args 0 "")))
|
(fn (&rest args) (js-string-from-char-code-loop args 0 "")))
|
||||||
|
|
||||||
|
(define
|
||||||
|
js-string-from-code-point-loop
|
||||||
|
(fn
|
||||||
|
(args i acc)
|
||||||
|
(if
|
||||||
|
(>= i (len args))
|
||||||
|
acc
|
||||||
|
(let
|
||||||
|
((cp (floor (js-to-number (nth args i)))))
|
||||||
|
(if
|
||||||
|
(< cp 65536)
|
||||||
|
(js-string-from-code-point-loop
|
||||||
|
args
|
||||||
|
(+ i 1)
|
||||||
|
(str acc (js-code-to-char (js-num-to-int cp))))
|
||||||
|
(let
|
||||||
|
((hi (+ 55296 (floor (/ (- cp 65536) 1024))))
|
||||||
|
(lo (+ 56320 (modulo (- cp 65536) 1024))))
|
||||||
|
(js-string-from-code-point-loop
|
||||||
|
args
|
||||||
|
(+ i 1)
|
||||||
|
(str
|
||||||
|
(str acc (js-code-to-char (js-num-to-int hi)))
|
||||||
|
(js-code-to-char (js-num-to-int lo))))))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
js-string-from-code-point
|
||||||
|
(fn (&rest args) (js-string-from-code-point-loop args 0 "")))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
js-string-from-char-code-loop
|
js-string-from-char-code-loop
|
||||||
(fn
|
(fn
|
||||||
@@ -3058,8 +3137,15 @@
|
|||||||
|
|
||||||
(dict-set! String "name" "String")
|
(dict-set! String "name" "String")
|
||||||
|
|
||||||
|
(dict-set! String "fromCodePoint" js-string-from-code-point)
|
||||||
|
|
||||||
(define Boolean {:__callable__ (fn (&rest args) (if (= (len args) 0) false (js-to-boolean (nth args 0))))})
|
(define Boolean {:__callable__ (fn (&rest args) (if (= (len args) 0) false (js-to-boolean (nth args 0))))})
|
||||||
|
|
||||||
|
(dict-set!
|
||||||
|
(get String "prototype")
|
||||||
|
"matchAll"
|
||||||
|
(js-string-proto-fn "matchAll"))
|
||||||
|
|
||||||
(dict-set! Boolean "length" 1)
|
(dict-set! Boolean "length" 1)
|
||||||
|
|
||||||
(dict-set! Boolean "name" "Boolean")
|
(dict-set! Boolean "name" "Boolean")
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
{
|
{
|
||||||
"totals": {
|
"totals": {
|
||||||
"pass": 162,
|
"pass": 202,
|
||||||
"fail": 128,
|
"fail": 85,
|
||||||
"skip": 1597,
|
"skip": 1597,
|
||||||
"timeout": 10,
|
"timeout": 13,
|
||||||
"total": 1897,
|
"total": 1897,
|
||||||
"runnable": 300,
|
"runnable": 300,
|
||||||
"pass_rate": 54.0
|
"pass_rate": 67.3
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
{
|
{
|
||||||
"category": "built-ins/Math",
|
"category": "built-ins/Math",
|
||||||
"total": 327,
|
"total": 327,
|
||||||
"pass": 43,
|
"pass": 82,
|
||||||
"fail": 56,
|
"fail": 17,
|
||||||
"skip": 227,
|
"skip": 227,
|
||||||
"timeout": 1,
|
"timeout": 1,
|
||||||
"pass_rate": 43.0,
|
"pass_rate": 82.0,
|
||||||
"top_failures": [
|
"top_failures": [
|
||||||
[
|
|
||||||
"TypeError: not a function",
|
|
||||||
36
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
"Test262Error (assertion failed)",
|
"Test262Error (assertion failed)",
|
||||||
20
|
17
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"Timeout",
|
"Timeout",
|
||||||
@@ -54,31 +50,31 @@
|
|||||||
{
|
{
|
||||||
"category": "built-ins/String",
|
"category": "built-ins/String",
|
||||||
"total": 1223,
|
"total": 1223,
|
||||||
"pass": 42,
|
"pass": 43,
|
||||||
"fail": 53,
|
"fail": 49,
|
||||||
"skip": 1123,
|
"skip": 1123,
|
||||||
"timeout": 5,
|
"timeout": 8,
|
||||||
"pass_rate": 42.0,
|
"pass_rate": 43.0,
|
||||||
"top_failures": [
|
"top_failures": [
|
||||||
[
|
[
|
||||||
"Test262Error (assertion failed)",
|
"Test262Error (assertion failed)",
|
||||||
44
|
42
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"Timeout",
|
"Timeout",
|
||||||
5
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"TypeError: not a function",
|
||||||
|
3
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"ReferenceError (undefined symbol)",
|
"ReferenceError (undefined symbol)",
|
||||||
2
|
1
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"Unhandled: Not callable: {:__proto__ {:toLowerCase <lambda(&rest, args)",
|
"SyntaxError (parse/unsupported syntax)",
|
||||||
2
|
1
|
||||||
],
|
|
||||||
[
|
|
||||||
"Unhandled: Not callable: \\\\\\",
|
|
||||||
2
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -96,34 +92,26 @@
|
|||||||
"top_failure_modes": [
|
"top_failure_modes": [
|
||||||
[
|
[
|
||||||
"Test262Error (assertion failed)",
|
"Test262Error (assertion failed)",
|
||||||
83
|
78
|
||||||
],
|
|
||||||
[
|
|
||||||
"TypeError: not a function",
|
|
||||||
36
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"Timeout",
|
"Timeout",
|
||||||
10
|
13
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"TypeError: not a function",
|
||||||
|
3
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"ReferenceError (undefined symbol)",
|
"ReferenceError (undefined symbol)",
|
||||||
2
|
1
|
||||||
],
|
|
||||||
[
|
|
||||||
"Unhandled: Not callable: {:__proto__ {:toLowerCase <lambda(&rest, args)",
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Unhandled: Not callable: \\\\\\",
|
|
||||||
2
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"SyntaxError (parse/unsupported syntax)",
|
"SyntaxError (parse/unsupported syntax)",
|
||||||
1
|
1
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"Unhandled: Not callable: {:__proto__ {:valueOf <lambda()> :propertyIsEn",
|
"Unhandled: Not callable: \\\\\\",
|
||||||
1
|
1
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -132,6 +120,6 @@
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
"pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33",
|
"pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33",
|
||||||
"elapsed_seconds": 274.5,
|
"elapsed_seconds": 102.4,
|
||||||
"workers": 1
|
"workers": 2
|
||||||
}
|
}
|
||||||
@@ -1,47 +1,44 @@
|
|||||||
# test262 scoreboard
|
# test262 scoreboard
|
||||||
|
|
||||||
Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33`
|
Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33`
|
||||||
Wall time: 274.5s
|
Wall time: 102.4s
|
||||||
|
|
||||||
**Total:** 162/300 runnable passed (54.0%). Raw: pass=162 fail=128 skip=1597 timeout=10 total=1897.
|
**Total:** 202/300 runnable passed (67.3%). Raw: pass=202 fail=85 skip=1597 timeout=13 total=1897.
|
||||||
|
|
||||||
## Top failure modes
|
## Top failure modes
|
||||||
|
|
||||||
- **83x** Test262Error (assertion failed)
|
- **78x** Test262Error (assertion failed)
|
||||||
- **36x** TypeError: not a function
|
- **13x** Timeout
|
||||||
- **10x** Timeout
|
- **3x** TypeError: not a function
|
||||||
- **2x** ReferenceError (undefined symbol)
|
- **1x** ReferenceError (undefined symbol)
|
||||||
- **2x** Unhandled: Not callable: {:__proto__ {:toLowerCase <lambda(&rest, args)
|
|
||||||
- **2x** Unhandled: Not callable: \\\
|
|
||||||
- **1x** SyntaxError (parse/unsupported syntax)
|
- **1x** SyntaxError (parse/unsupported syntax)
|
||||||
- **1x** Unhandled: Not callable: {:__proto__ {:valueOf <lambda()> :propertyIsEn
|
- **1x** Unhandled: Not callable: \\\
|
||||||
- **1x** Unhandled: js-transpile-binop: unsupported op: >>>\
|
- **1x** Unhandled: js-transpile-binop: unsupported op: >>>\
|
||||||
|
|
||||||
## Categories (worst pass-rate first, min 10 runnable)
|
## Categories (worst pass-rate first, min 10 runnable)
|
||||||
|
|
||||||
| Category | Pass | Fail | Skip | Timeout | Total | Pass % |
|
| Category | Pass | Fail | Skip | Timeout | Total | Pass % |
|
||||||
|---|---:|---:|---:|---:|---:|---:|
|
|---|---:|---:|---:|---:|---:|---:|
|
||||||
| built-ins/String | 42 | 53 | 1123 | 5 | 1223 | 42.0% |
|
| built-ins/String | 43 | 49 | 1123 | 8 | 1223 | 43.0% |
|
||||||
| built-ins/Math | 43 | 56 | 227 | 1 | 327 | 43.0% |
|
|
||||||
| built-ins/Number | 77 | 19 | 240 | 4 | 340 | 77.0% |
|
| built-ins/Number | 77 | 19 | 240 | 4 | 340 | 77.0% |
|
||||||
|
| built-ins/Math | 82 | 17 | 227 | 1 | 327 | 82.0% |
|
||||||
|
|
||||||
## Per-category top failures (min 10 runnable, worst first)
|
## Per-category top failures (min 10 runnable, worst first)
|
||||||
|
|
||||||
### built-ins/String (42/100 — 42.0%)
|
### built-ins/String (43/100 — 43.0%)
|
||||||
|
|
||||||
- **44x** Test262Error (assertion failed)
|
- **42x** Test262Error (assertion failed)
|
||||||
- **5x** Timeout
|
- **8x** Timeout
|
||||||
- **2x** ReferenceError (undefined symbol)
|
- **3x** TypeError: not a function
|
||||||
- **2x** Unhandled: Not callable: {:__proto__ {:toLowerCase <lambda(&rest, args)
|
- **1x** ReferenceError (undefined symbol)
|
||||||
- **2x** Unhandled: Not callable: \\\
|
- **1x** SyntaxError (parse/unsupported syntax)
|
||||||
|
|
||||||
### built-ins/Math (43/100 — 43.0%)
|
|
||||||
|
|
||||||
- **36x** TypeError: not a function
|
|
||||||
- **20x** Test262Error (assertion failed)
|
|
||||||
- **1x** Timeout
|
|
||||||
|
|
||||||
### built-ins/Number (77/100 — 77.0%)
|
### built-ins/Number (77/100 — 77.0%)
|
||||||
|
|
||||||
- **19x** Test262Error (assertion failed)
|
- **19x** Test262Error (assertion failed)
|
||||||
- **4x** Timeout
|
- **4x** Timeout
|
||||||
|
|
||||||
|
### built-ins/Math (82/100 — 82.0%)
|
||||||
|
|
||||||
|
- **17x** Test262Error (assertion failed)
|
||||||
|
- **1x** Timeout
|
||||||
|
|||||||
@@ -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.
|
Append-only record of completed iterations. Loop writes one line per iteration: date, what was done, test count delta.
|
||||||
|
|
||||||
|
- 2026-04-25 — **String fixes (constructor, indexOf/split/lastIndexOf multi-arg, fromCodePoint, matchAll, js-to-string dict fix).** Added `String.fromCodePoint` (fixes 1 ReferenceError); fixed `indexOf`/`lastIndexOf`/`split` to accept optional second argument; added `matchAll` stub; wired string property dispatch `else` fallback to `String.prototype` (fixes `'a'.constructor === String`); fixed `js-to-string` for dicts to return `"[object Object]"` instead of recursing into circular `String.prototype.constructor` structure. Scoreboard: String 42→43, timeouts 32→13. Total 162→202/300 (54%→67.3%). 529/530 unit, 148/148 slice.
|
||||||
|
|
||||||
- 2026-04-25 — **Math methods (trig/log/hyperbolic/bit ops).** Added 22 missing Math methods to `runtime.sx`: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`, `exp`, `log`, `log2`, `log10`, `expm1`, `log1p`, `clz32`, `imul`, `fround`. All use existing SX primitives. `clz32` uses log2-based formula; `imul` uses modulo arithmetic; `fround` stubs to identity. Addresses 36x "TypeError: not a function" in built-ins/Math (43% → ~79% expected). 529/530 unit (unchanged), 148/148 slice. Commit `5f38e49b`.
|
- 2026-04-25 — **Math methods (trig/log/hyperbolic/bit ops).** Added 22 missing Math methods to `runtime.sx`: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`, `exp`, `log`, `log2`, `log10`, `expm1`, `log1p`, `clz32`, `imul`, `fround`. All use existing SX primitives. `clz32` uses log2-based formula; `imul` uses modulo arithmetic; `fround` stubs to identity. Addresses 36x "TypeError: not a function" in built-ins/Math (43% → ~79% expected). 529/530 unit (unchanged), 148/148 slice. Commit `5f38e49b`.
|
||||||
|
|
||||||
- 2026-04-25 — **`var` hoisting.** Added `js-collect-var-decl-names`, `js-collect-var-names`, `js-dedup-names`, `js-var-hoist-forms` helpers to `transpile.sx`. Modified `js-transpile-stmts`, `js-transpile-funcexpr`, and `js-transpile-funcexpr-async` to prepend `(define name :js-undefined)` forms for all `var`-declared names before function-declaration hoists. Shallow collection (direct statements only). 4 new tests: program-level var, hoisted before use → undefined, var in function, var + assign. 529/530 unit (+4), 148/148 slice unchanged. Commit `11315d91`.
|
- 2026-04-25 — **`var` hoisting.** Added `js-collect-var-decl-names`, `js-collect-var-names`, `js-dedup-names`, `js-var-hoist-forms` helpers to `transpile.sx`. Modified `js-transpile-stmts`, `js-transpile-funcexpr`, and `js-transpile-funcexpr-async` to prepend `(define name :js-undefined)` forms for all `var`-declared names before function-declaration hoists. Shallow collection (direct statements only). 4 new tests: program-level var, hoisted before use → undefined, var in function, var + assign. 529/530 unit (+4), 148/148 slice unchanged. Commit `11315d91`.
|
||||||
|
|||||||
Reference in New Issue
Block a user