From 0142d69212c0ddedbc8e2f949996c4d9a15be039 Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 10 May 2026 11:20:24 +0000 Subject: [PATCH] js-on-sx: delete returns false per non-strict spec --- lib/js/transpile.sx | 2 ++ plans/js-on-sx.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/js/transpile.sx b/lib/js/transpile.sx index 74ac10f8..17693c1a 100644 --- a/lib/js/transpile.sx +++ b/lib/js/transpile.sx @@ -225,6 +225,8 @@ (js-sym "js-delete-prop") (js-transpile (nth arg 1)) (js-transpile (nth arg 2)))) + ((js-tag? arg "js-ident") false) + ((js-tag? arg "js-paren") (js-transpile-unop op (nth arg 1))) (else true))) ((and (= op "typeof") (js-tag? arg "js-ident")) (let diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 9251766f..939d52e3 100644 --- a/plans/js-on-sx.md +++ b/plans/js-on-sx.md @@ -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-10 — **`delete ` returns `false` instead of `true` per non-strict spec.** ES non-strict semantics: `delete x` where `x` is a declared binding (variable / function / parameter) returns `false` and does not unbind. Our transpiler was emitting `true` for any `delete ` whose argument wasn't a member or index access. Now `delete ` → `false`, and `delete ` recurses on the inner expression so `delete (1+2)` still works. Result: language/expressions/delete 14/30 → 18/30 (+4). conformance.sh: 148/148. + - 2026-05-10 — **Parser rejects unary-op directly before `**` (e.g. `-1 ** 2`, `delete o.p ** 2`, `!x ** 2`, `~x ** 2`) per ES spec.** ES disallows `UnaryExpression ** ExponentiationExpression`; only `UpdateExpression ** ExponentiationExpression` and `() ** ...` are legal. Added a guard in `jp-binary-loop`: when op is `**` and the LHS is a `(js-unop ...)` node, raise SyntaxError. Parens are made transparent for everything except this check via a new `jp-paren-wrap` helper that emits `(js-paren )` only when wrapping an explicit unary op (so `(-1) ** 2` parses fine), and a new `js-paren` AST tag in `js-transpile` that just unwraps. Result: language/expressions/exponentiation 25/30 → 28/30 (+3). conformance.sh: 148/148. - 2026-05-10 — **`Math.round` / `Math.max` / `Math.min` honour spec edge cases for NaN, ±Infinity, and ±0.** `Math.round(NaN)` was returning 0 because `floor(NaN+0.5)` doesn't propagate NaN; ditto `±Infinity` paths. `Math.max({})` silently returned `-Infinity` (initial accumulator) because the first arg wasn't ToNumber'd. `Math.max(0, -0)` returned `-0` because `>` doesn't distinguish them. Rewrites: round NaN/±Infinity/±0 short-circuits; max/min ToNumber the first arg, propagate NaN immediately, and use a `js-is-positive-zero?` (rational-safe) tiebreaker so `Math.max(0, -0) === 0` per spec. Result: built-ins/Math/round 5/10 → 8/10 (+3). Math/max 6/9 → 8/9 (+2). Math/min 6/9 → 8/9 (+2). conformance.sh: 148/148.