js-on-sx: relational ops ToPrimitive operands + NaN-safe le/ge
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 42s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 42s
This commit is contained in:
@@ -1876,6 +1876,8 @@
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
((or (= (type-of v) "lambda") (= (type-of v) "function") (= (type-of v) "component"))
|
||||
(let ((s (js-to-string v))) s))
|
||||
((not (= (type-of v) "dict")) v)
|
||||
((contains? (keys v) "__js_string_value__")
|
||||
(get v "__js_string_value__"))
|
||||
@@ -2076,16 +2078,37 @@
|
||||
js-lt
|
||||
(fn
|
||||
(a b)
|
||||
(cond
|
||||
((and (= (type-of a) "string") (= (type-of b) "string"))
|
||||
(js-str-lt a b))
|
||||
(else (< (js-to-number a) (js-to-number b))))))
|
||||
(let
|
||||
((ap (js-add-unwrap a)) (bp (js-add-unwrap b)))
|
||||
(cond
|
||||
((and (= (type-of ap) "string") (= (type-of bp) "string"))
|
||||
(js-str-lt ap bp))
|
||||
(else
|
||||
(let
|
||||
((an (js-to-number ap)) (bn (js-to-number bp)))
|
||||
(cond
|
||||
((or (js-number-is-nan an) (js-number-is-nan bn)) false)
|
||||
(else (< an bn)))))))))
|
||||
|
||||
(define js-gt (fn (a b) (js-lt b a)))
|
||||
|
||||
(define js-le (fn (a b) (not (js-lt b a))))
|
||||
(define
|
||||
js-le
|
||||
(fn
|
||||
(a b)
|
||||
(let
|
||||
((ap (js-add-unwrap a)) (bp (js-add-unwrap b)))
|
||||
(cond
|
||||
((and (= (type-of ap) "string") (= (type-of bp) "string"))
|
||||
(or (js-str-lt ap bp) (= ap bp)))
|
||||
(else
|
||||
(let
|
||||
((an (js-to-number ap)) (bn (js-to-number bp)))
|
||||
(cond
|
||||
((or (js-number-is-nan an) (js-number-is-nan bn)) false)
|
||||
(else (<= an bn)))))))))
|
||||
|
||||
(define js-ge (fn (a b) (not (js-lt a b))))
|
||||
(define js-ge (fn (a b) (js-le b a)))
|
||||
|
||||
(define
|
||||
js-str-lt
|
||||
|
||||
@@ -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-09 — **Relational operators ToPrimitive their operands (string-vs-numeric decision); `<= / >=` short-circuit to false on NaN.** `js-lt` was checking only `(type-of)` for `"string"` to pick the string-compare branch, so `{} < function(){return 1}` fell into `(< NaN NaN)` (returning false) while `{}.toString() < fn.toString()` returned true (lex). Reused `js-add-unwrap` (now extended to coerce lambda/function/component to their `js-to-string` representation, matching the function's `[object Function]` / `function () { [native code] }` semantics) so both operands are first reduced to primitives. Added explicit NaN check in the numeric branch of `js-lt` and `js-le`. `js-le` no longer does `(not (js-lt b a))` — that gave the wrong answer on NaN (NaN ≤ x must be false, not !(x < NaN) = true). `js-ge` similarly switched to `(js-le b a)`. Result: language/expressions/less-than 23/30 → 24/30, greater-than 23/30 → 24/30, addition 24/30 → 25/30. Object 30/30 maintained. conformance.sh: 148/148.
|
||||
|
||||
- 2026-05-09 — **`Error(msg)` / `TypeError(msg)` / etc. (called without `new`) now return a proper instance.** Was checking `(if (= (type-of this) "dict") <init> nil)` and falling through to return undefined when called as a plain function — but per spec, every Error subclass must return a new instance regardless of `new`. Refactored each constructor to `(js-error-init! (js-error-receiver Ctor) "Name" args)`: `js-error-receiver` returns `this` if it's a dict (the `new`-call case) and otherwise re-enters via `js-new-call ctor (list)` to create a properly-prototyped instance; `js-error-init!` sets `message`, `name`, `__js_error_data__`. Cleaner than the seven near-identical duplicated bodies. Result: built-ins/Error 17/30 → 22/30 (+5), language/expressions/instanceof 18/30 → 20/30. NativeErrors holds at 27/30. conformance.sh: 148/148.
|
||||
|
||||
- 2026-05-09 — **`typeof <undeclaredIdent>` returns `"undefined"` instead of throwing ReferenceError.** Per JS spec, `typeof` on an unresolvable Reference is special-cased — it must return `"undefined"` without throwing. We were transpiling `typeof X` to `(js-typeof <symbol-X>)`, and the symbol lookup itself errored for undeclared globals. New transpiler branch in `js-transpile-unop`: when the operand is a `js-ident`, emit `(if (or (env-has? (current-env) "name") (dict-has? js-global "name")) (js-typeof <name>) "undefined")` — checks both the lexical env (for local var/let/const/parameters) and the global object, and only references the symbol when the if branch is taken (SX `if` is lazy, so the unbound symbol in the false branch never errors). Result: language/expressions/typeof 9/13 → 10/13, built-ins/Object 29/30 → 30/30 (full pass — the `S15.2.1.1_A2_T11.js` test was using `typeof obj` on an undeclared name). conformance.sh: 148/148.
|
||||
|
||||
Reference in New Issue
Block a user