js-on-sx: exponent notation in js-string-to-number (+3 Number tests)

js-num-from-string now finds an e/E split, parses mantissa and exponent
separately, and combines via js-pow-int (positive-exp loop for >=0, 1/
reciprocal for negative). Previously `.12345e-3` parsed as 0.12345 and
"1e3" returned NaN — the parser walked decimals/dots only.

New helpers:
- js-find-exp-char / -loop : linear scan for e/E, returns -1 if absent
- js-pow-int base exp : integer-exp power, handles negative

Also fixed `js-string-trim` typo → `js-trim` in the rewritten num-from-
string, and corrected test 903's expected part count (3, not 2 — the
lexer has always split `hi ${x}!` into str+expr+str, the test just had
the wrong count).

Unit: 521/522 (was 520/522, 934 still blocked on SX \` escape).
Conformance: 148/148 unchanged.
Number scoreboard: 43/100 → 46/100 (+3).

Impacted test262 paths (sample): built-ins/Number/S9.3.1_A11.js and
A12/A16/A17 (".12345e-3", scientific notation round-trips).
This commit is contained in:
2026-04-24 11:36:56 +00:00
parent dc97c17304
commit 7cffae2148
3 changed files with 46 additions and 2 deletions

View File

@@ -860,6 +860,26 @@
(define js-parse-num-safe (fn (s) (cond (else (js-num-from-string s)))))
(define js-find-exp-char (fn (s) (js-find-exp-char-loop s 0 (len s))))
(define
js-find-exp-char-loop
(fn
(s i n)
(cond
((>= i n) -1)
((or (= (char-at s i) "e") (= (char-at s i) "E")) i)
(else (js-find-exp-char-loop s (+ i 1) n)))))
(define
js-pow-int
(fn
(base exp)
(cond
((= exp 0) 1)
((> exp 0) (* base (js-pow-int base (- exp 1))))
(else (/ 1 (js-pow-int base (- 0 exp)))))))
(define
js-num-from-string
(fn
@@ -868,7 +888,20 @@
((trimmed (js-trim s)))
(cond
((= trimmed "") 0)
(else (js-parse-decimal trimmed 0 0 1 false 0))))))
(else
(let
((esplit (js-find-exp-char trimmed)))
(if
(>= esplit 0)
(let
((mant (js-string-slice trimmed 0 esplit))
(expstr
(js-string-slice trimmed (+ esplit 1) (len trimmed))))
(let
((m (js-parse-decimal mant 0 0 1 false 0))
(e (js-parse-decimal expstr 0 0 1 false 0)))
(* m (js-pow-int 10 e))))
(js-parse-decimal trimmed 0 0 1 false 0))))))))
(define js-trim (fn (s) (js-trim-left (js-trim-right s))))