diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 42175917..df5757ca 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -1608,6 +1608,34 @@ (define Array {:isArray js-array-is-array :of js-array-of}) +(define + js-string-from-char-code + (fn (&rest args) (js-string-from-char-code-loop args 0 ""))) + +(define + js-string-from-char-code-loop + (fn + (args i acc) + (if + (>= i (len args)) + acc + (js-string-from-char-code-loop + args + (+ i 1) + (str acc (js-code-to-char (js-num-to-int (nth args i)))))))) + +(define String {:fromCharCode js-string-from-char-code}) + +(define + parseInt + (fn + (&rest args) + (if (= (len args) 0) 0 (js-math-trunc (js-to-number (nth args 0)))))) + +(define + parseFloat + (fn (&rest args) (if (= (len args) 0) 0 (js-to-number (nth args 0))))) + (define js-promise-flush-callbacks! (fn @@ -2022,4 +2050,4 @@ (str "/" (get rx "source") "/" (get rx "flags"))) (else js-undefined)))) -(define js-global {:isFinite js-global-is-finite :console console :Number Number :Math Math :Array Array :NaN 0 :Infinity inf :isNaN js-global-is-nan :Object Object :undefined js-undefined}) +(define js-global {:isFinite js-global-is-finite :console console :Number Number :Math Math :Array Array :String String :NaN 0 :Infinity inf :isNaN js-global-is-nan :Object Object :undefined js-undefined}) diff --git a/lib/js/test.sh b/lib/js/test.sh index a7bce38e..ad5a835d 100755 --- a/lib/js/test.sh +++ b/lib/js/test.sh @@ -981,8 +981,21 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 1803) (eval "(js-eval \"({x:1}).valueOf().x\")") +;; ── Phase 11.fromCharCode: String/parseInt/parseFloat ────────── +(epoch 1900) +(eval "(js-eval \"String.fromCharCode(65)\")") +(epoch 1901) +(eval "(js-eval \"String.fromCharCode(72, 105)\")") +(epoch 1902) +(eval "(js-eval \"parseInt('42')\")") +(epoch 1903) +(eval "(js-eval \"parseInt(3.7)\")") +(epoch 1904) +(eval "(js-eval \"parseFloat('3.14')\")") + EPOCHS + OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) check() { @@ -1505,6 +1518,13 @@ check 1801 "hasOwnProperty no" 'false' check 1802 "({}).toString()" '"[object Object]"' check 1803 "obj.valueOf().x" '1' +# ── Phase 11.fromCharCode / parseInt / parseFloat ────────────── +check 1900 "String.fromCharCode(65)" '"A"' +check 1901 "String.fromCharCode(72,105)" '"Hi"' +check 1902 "parseInt('42')" '42' +check 1903 "parseInt(3.7)" '3' +check 1904 "parseFloat('3.14')" '3.14' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "✓ $PASS/$TOTAL JS-on-SX tests passed" diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 8e19880c..123909c3 100644 --- a/plans/js-on-sx.md +++ b/plans/js-on-sx.md @@ -185,6 +185,8 @@ Append-only record of completed iterations. Loop writes one line per iteration: - 2026-04-23 — **More Array.prototype + Object fallbacks (`hasOwnProperty` etc).** Array: `includes`, `find`, `findIndex`, `some`, `every`, `reverse` (in `js-array-method` dispatch + `js-get-prop` list-branch keys). Helpers: `js-list-find-loop / -find-index-loop / -some-loop / -every-loop / -reverse-loop` all tail-recursive, no `while` because SX doesn't have one. Object fallbacks: `js-invoke-method` now falls back to `js-invoke-object-method` for dicts when js-get-prop returns undefined AND the method name is in the builtin set (`hasOwnProperty`, `isPrototypeOf`, `propertyIsEnumerable`, `toString`, `valueOf`, `toLocaleString`). `hasOwnProperty` checks `(contains? (keys recv) (js-to-string k))`. This lets `o.hasOwnProperty('x')` work on plain dicts without having to install an Object.prototype. 13 new tests, **376/378** (363→+13). Conformance unchanged. +- 2026-04-23 — **`String.fromCharCode`, `parseInt`, `parseFloat`.** `String` global with `fromCharCode` (variadic, loops through args and concatenates via `js-code-to-char`). `parseInt` truncates toward zero via `js-math-trunc`; `parseFloat` delegates to `js-to-number`. Wired into `js-global`. 5 new tests, **381/383** (376→+5). Conformance unchanged. + ## Phase 3-5 gotchas Worth remembering for later phases: