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:
@@ -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))))
|
||||
|
||||
|
||||
@@ -1697,7 +1697,7 @@ check 870 "typeof Promise" '"object"'
|
||||
check 900 "tpl plain: type" '"template"'
|
||||
check 901 "tpl plain: value" '"hello"'
|
||||
check 902 "tpl interp: value is list" 'true'
|
||||
check 903 "tpl interp: 2 parts" '2'
|
||||
check 903 "tpl interp: 3 parts" '3'
|
||||
|
||||
check 910 "parse plain" '(js-str "hi")'
|
||||
check 911 'parse interp a${1}b' '(js-tpl ((js-str "a") (js-num 1) (js-str "b")))'
|
||||
|
||||
@@ -1120,6 +1120,8 @@ def main(argv):
|
||||
ap.add_argument("--output-md", type=str,
|
||||
default=str(REPO / "lib" / "js" / "test262-scoreboard.md"))
|
||||
ap.add_argument("--progress-every", type=int, default=100)
|
||||
ap.add_argument("--dump-failures", type=str, default=None,
|
||||
help="if set, write every failed test's rel path + reason to this file")
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
if not SX_SERVER.exists():
|
||||
@@ -1242,6 +1244,15 @@ def main(argv):
|
||||
out_md = Path(args.output_md)
|
||||
write_markdown(scoreboard, out_md, pinned_commit, t_run_elapsed)
|
||||
|
||||
if args.dump_failures:
|
||||
out_fail = Path(args.dump_failures)
|
||||
out_fail.parent.mkdir(parents=True, exist_ok=True)
|
||||
with out_fail.open("w", encoding="utf-8") as f:
|
||||
for r in results:
|
||||
if r.status in ("fail", "timeout"):
|
||||
f.write(f"{r.status}\t{r.rel}\t{r.reason}\n")
|
||||
print(f"failures dumped to {out_fail}", file=sys.stderr)
|
||||
|
||||
t = scoreboard["totals"]
|
||||
print(
|
||||
f"\nScoreboard: {t['pass']}/{t['runnable']} runnable passed ({t['pass_rate']}%) "
|
||||
|
||||
Reference in New Issue
Block a user