From 7c63fd8a7f6d1b8e99ac6a20bac8b298aeb0ce62 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 9 May 2026 00:24:45 +0000 Subject: [PATCH] js-on-sx: RegExp constructor wraps existing regex stub --- lib/js/runtime.sx | 71 ++++++++++++++++++++++++++++++++++++++++++++++- plans/js-on-sx.md | 2 ++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 77cf1dda..922a5bfc 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -991,6 +991,72 @@ (define SuppressedError :js-undefined) +(define + RegExp + {:length 2 + :name "RegExp" + :__callable__ + (fn + (&rest args) + (let + ((this (js-this))) + (let + ((pattern-arg (if (= (len args) 0) "" (nth args 0))) + (flags-arg + (if (>= (len args) 2) (nth args 1) :js-undefined))) + (let + ((src + (cond + ((js-regex? pattern-arg) (get pattern-arg "source")) + ((js-undefined? pattern-arg) "") + ((= pattern-arg nil) "") + (else (js-to-string pattern-arg)))) + (fl + (cond + ((js-undefined? flags-arg) + (if (js-regex? pattern-arg) (get pattern-arg "flags") "")) + ((= flags-arg nil) "") + (else (js-to-string flags-arg))))) + (let + ((rx (js-regex-new src fl))) + (cond + ((not (= (type-of this) "dict")) rx) + (else + (begin + (for-each + (fn (k) (dict-set! this k (get rx k))) + (keys rx)) + this)))))))) + :prototype + {:test + (fn (s) + (let ((rx (js-this)) (str (js-to-string s))) + (js-regex-stub-test rx str))) + :exec + (fn (s) + (let ((rx (js-this)) (str (js-to-string s))) + (js-regex-stub-exec rx str))) + :toString + (fn () + (let ((rx (js-this))) + (str "/" (get rx "source") "/" (get rx "flags")))) + :compile + (fn (&rest args) + (let ((rx (js-this))) + (cond + ((>= (len args) 1) + (let + ((src (js-to-string (nth args 0))) + (fl (if (>= (len args) 2) (js-to-string (nth args 1)) ""))) + (let + ((rx2 (js-regex-new src fl))) + (begin + (for-each + (fn (k) (dict-set! rx k (get rx2 k))) + (keys rx2)) + rx)))) + (else rx))))}}) + (define js-str-startswith? (fn @@ -5693,6 +5759,7 @@ (dict-set! Map "__proto__" (get js-function-global "prototype")) (dict-set! Set "__proto__" (get js-function-global "prototype")) (dict-set! Date "__proto__" (get js-function-global "prototype")) + (dict-set! RegExp "__proto__" (get js-function-global "prototype")) (dict-set! __js_ctor_proto__ (js-ctor-id TypeError) Error) (dict-set! __js_ctor_proto__ (js-ctor-id RangeError) Error) (dict-set! __js_ctor_proto__ (js-ctor-id SyntaxError) Error) @@ -5728,11 +5795,13 @@ (dict-set! (get Map "prototype") "__proto__" (get Object "prototype")) (dict-set! (get Set "prototype") "__proto__" (get Object "prototype")) (dict-set! (get Date "prototype") "__proto__" (get Object "prototype")) + (dict-set! (get RegExp "prototype") "__proto__" (get Object "prototype")) + (dict-set! (get RegExp "prototype") "constructor" RegExp) (dict-set! (get js-function-global "prototype") "__proto__" (get Object "prototype")) (dict-set! (get Number "prototype") "__js_number_value__" 0) (dict-set! (get String "prototype") "__js_string_value__" "") (dict-set! (get Boolean "prototype") "__js_boolean_value__" false)) -(define js-global {:undefined js-undefined :JSON JSON :parseInt parseInt :Object Object :isNaN js-global-is-nan :Infinity inf :NaN 0 :String String :Boolean Boolean :Array Array :Math Math :parseFloat parseFloat :Number Number :console console :isFinite js-global-is-finite :Map Map :Set Set :Date Date}) +(define js-global {:undefined js-undefined :JSON JSON :parseInt parseInt :Object Object :isNaN js-global-is-nan :Infinity inf :NaN 0 :String String :Boolean Boolean :Array Array :Math Math :parseFloat parseFloat :Number Number :console console :isFinite js-global-is-finite :Map Map :Set Set :Date Date :RegExp RegExp}) (set! js-global-this js-global) diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index c004e609..66dc217c 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-09 — **`RegExp` constructor exposed as a global.** Was undefined — every test in `built-ins/RegExp` died at `new RegExp(...)` with ReferenceError. The internals (`js-regex-new`, `js-regex?`, `js-regex-stub-test`, `js-regex-stub-exec`) already existed for regex literals; this iteration just wraps them as a JS-visible constructor with the dict-with-`__callable__` pattern. Constructor handles `new RegExp(/x/, "g")` (re-flags an existing regex), `new RegExp(pattern)` and `new RegExp(pattern, flags)`. Prototype methods: `test`, `exec`, `toString`, `compile` (matching the stub semantics — substring search with `i` flag honoured, no real regex engine). Added `RegExp` to `js-global` and the post-init `__proto__` chain. Result: built-ins/RegExp 0/30 → 1/30; the rest still need a real regex engine (or fail on character-class escapes / lookaheads / etc.). conformance.sh: 148/148. + - 2026-05-08 — **`js-is-space?` recognises the full ES whitespace set** (was only ` \t\n\r`). `parseFloat(" 1.1")`, `parseFloat(" 1.1")`, etc. now strip leading whitespace correctly per spec. Added: form feed (12), vertical tab (11), NBSP (160), Ogham space mark (5760), the en/em-width run 8192–8202, line/paragraph separator (8232/8233), narrow no-break space (8239), medium math space (8287), ideographic space (12288), ZWNBSP/BOM (65279). Single helper used by every trim/whitespace path (`parseFloat`, `parseInt`, `String.prototype.trim*`, `js-string-to-number`, JSON parse-ws). Result: built-ins/parseFloat 15/30 → 17/30. String/Number/parseInt unchanged. conformance.sh: 148/148. - 2026-05-08 — **NativeError prototype chain wired: `Object.getPrototypeOf(EvalError) === Error`, `Error.prototype.constructor === Error`, `[object Error]` brand.** Three pieces: (1) `js-object-tostring-class` now recognises `__js_error_data__` (returns `"[object Error]"`), `__js_is_date__` (`"[object Date]"`), `__map_keys__` / `__set_items__` (`"[object Map]"` / `"[object Set]"`) — these were all falling through to `"[object Object]"`. (2) New `__js_ctor_proto__` side-table maps lambda-ctor identity → its [[Prototype]] constructor; `js-object-get-prototype-of` consults it for non-dict callables. Populated for all six native error subclasses (TypeError/RangeError/SyntaxError/ReferenceError/URIError/EvalError) → Error. (3) Each subclass's `prototype.__proto__` set to `Error.prototype`, and `Error.prototype` gets `name`, `message`, `constructor` populated; each subclass prototype also gets its own `name` and `constructor`. Result: built-ins/NativeErrors 14/30 → 27/30 (+13), built-ins/Error 11/30 → 17/30 (+6). Object/Map/Array unchanged. conformance.sh: 148/148.