js-on-sx: regex literal lex+parse+transpile+runtime stub
Lexer: js-regex-context? disambiguates / based on prior token;
read-regex handles [...] classes and \ escapes. Emits
{:type "regex" :value {:pattern :flags}}.
Parser: new primary branch → (js-regex pat flags).
Transpile: (js-regex-new pat flags).
Runtime: js-regex? predicate, js-regex-new builds tagged dict with
source/flags/global/ignoreCase/multiline/sticky/unicode/dotAll/
hasIndices/lastIndex. js-regex-invoke-method dispatches .test/.exec/
.toString. js-invoke-method detects regex receivers. Stub engine
uses js-string-index-of; __js_regex_platform__ + override! let a
real engine plug in later.
Runner: repeatable --filter flags (OR'd).
308/310 unit (+30 regex tests), 148/148 slice unchanged.
This commit is contained in:
126
lib/js/test.sh
126
lib/js/test.sh
@@ -745,6 +745,90 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 938)
|
||||
(eval "(js-eval \"`[${''}-${''}]`\")")
|
||||
|
||||
;; ── Phase 11.regex: regex literal lexing ────────────────────────
|
||||
;; Simple regex at start of file
|
||||
(epoch 1000)
|
||||
(eval "(get (nth (js-tokenize \"/abc/\") 0) :type)")
|
||||
(epoch 1001)
|
||||
(eval "(get (get (nth (js-tokenize \"/abc/\") 0) :value) :pattern)")
|
||||
(epoch 1002)
|
||||
(eval "(get (get (nth (js-tokenize \"/abc/\") 0) :value) :flags)")
|
||||
;; With flags
|
||||
(epoch 1003)
|
||||
(eval "(get (get (nth (js-tokenize \"/a+/gi\") 0) :value) :flags)")
|
||||
;; Character class with embedded /
|
||||
(epoch 1004)
|
||||
(eval "(get (get (nth (js-tokenize \"/[/]/\") 0) :value) :pattern)")
|
||||
;; Escaped /
|
||||
(epoch 1005)
|
||||
(eval "(get (get (nth (js-tokenize \"/a\\\\/b/\") 0) :value) :pattern)")
|
||||
;; After `return` keyword → regex
|
||||
(epoch 1006)
|
||||
(eval "(get (nth (js-tokenize \"return /x/\") 1) :type)")
|
||||
;; After `=` op → regex
|
||||
(epoch 1007)
|
||||
(eval "(get (nth (js-tokenize \"x = /y/\") 2) :type)")
|
||||
;; After ident `x` → division (not regex)
|
||||
(epoch 1008)
|
||||
(eval "(get (nth (js-tokenize \"a/b\") 1) :type)")
|
||||
(epoch 1009)
|
||||
(eval "(get (nth (js-tokenize \"a/b\") 1) :value)")
|
||||
;; After `)` → division
|
||||
(epoch 1010)
|
||||
(eval "(get (nth (js-tokenize \"(a)/b\") 3) :type)")
|
||||
;; After number → division
|
||||
(epoch 1011)
|
||||
(eval "(get (nth (js-tokenize \"1/2\") 1) :type)")
|
||||
;; Regex /= must still be division-assignment in expr context
|
||||
(epoch 1012)
|
||||
(eval "(get (nth (js-tokenize \"x/=2\") 1) :type)")
|
||||
(epoch 1013)
|
||||
(eval "(get (nth (js-tokenize \"x/=2\") 1) :value)")
|
||||
;; Inside function body after statement separator
|
||||
(epoch 1014)
|
||||
(eval "(get (nth (js-tokenize \"; /abc/\") 1) :type)")
|
||||
;; After `throw`
|
||||
(epoch 1015)
|
||||
(eval "(get (nth (js-tokenize \"throw /x/\") 1) :type)")
|
||||
|
||||
;; ── Phase 11.regex: parser ──────────────────────────────────────
|
||||
(epoch 1020)
|
||||
(eval "(first (js-parse-expr \"/abc/\"))")
|
||||
(epoch 1021)
|
||||
(eval "(nth (js-parse-expr \"/foo/gi\") 1)")
|
||||
(epoch 1022)
|
||||
(eval "(nth (js-parse-expr \"/foo/gi\") 2)")
|
||||
|
||||
;; ── Phase 11.regex: transpile ───────────────────────────────────
|
||||
(epoch 1030)
|
||||
(eval "(first (js-transpile (js-parse-expr \"/abc/\")))")
|
||||
|
||||
;; ── Phase 11.regex: runtime — regex object shape ───────────────
|
||||
(epoch 1040)
|
||||
(eval "(get (js-regex-new \"ab\" \"g\") :source)")
|
||||
(epoch 1041)
|
||||
(eval "(get (js-regex-new \"ab\" \"g\") :flags)")
|
||||
(epoch 1042)
|
||||
(eval "(get (js-regex-new \"ab\" \"g\") :global)")
|
||||
(epoch 1043)
|
||||
(eval "(js-regex? (js-regex-new \"ab\" \"\"))")
|
||||
|
||||
;; .source / .flags / .global etc via property access
|
||||
(epoch 1050)
|
||||
(eval "(js-eval \"/abc/g.source\")")
|
||||
(epoch 1051)
|
||||
(eval "(js-eval \"/abc/gi.flags\")")
|
||||
(epoch 1052)
|
||||
(eval "(js-eval \"/abc/g.global\")")
|
||||
(epoch 1053)
|
||||
(eval "(js-eval \"/abc/i.ignoreCase\")")
|
||||
|
||||
;; .test() via stub: substring-based
|
||||
(epoch 1060)
|
||||
(eval "(js-eval \"/foo/.test('hello foo')\")")
|
||||
(epoch 1061)
|
||||
(eval "(js-eval \"/zzz/.test('hello')\")")
|
||||
|
||||
EPOCHS
|
||||
|
||||
OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||
@@ -1144,6 +1228,48 @@ check 936 'bare ${42}' '"42"'
|
||||
check 937 "expr in interp" '"len is 12"'
|
||||
check 938 "empty interps" '"[-]"'
|
||||
|
||||
# ── Phase 11.regex: lexer ────────────────────────────────────────
|
||||
check 1000 "regex at sof → type" '"regex"'
|
||||
check 1001 "regex pattern" '"abc"'
|
||||
check 1002 "regex empty flags" '""'
|
||||
check 1003 "regex with gi flags" '"gi"'
|
||||
check 1004 "regex class with /" '"[/]"'
|
||||
check 1005 "regex escaped /" '"a\\/b"'
|
||||
check 1006 "after return → regex" '"regex"'
|
||||
check 1007 "after = → regex" '"regex"'
|
||||
check 1008 "after ident → op" '"op"'
|
||||
check 1009 "after ident div value" '"/"'
|
||||
check 1010 "after ) → op" '"op"'
|
||||
check 1011 "after number → op" '"op"'
|
||||
check 1012 "x/=2 is /=-assign" '"op"'
|
||||
check 1013 "x/=2 /= op value" '"/="'
|
||||
check 1014 "after ; → regex" '"regex"'
|
||||
check 1015 "after throw → regex" '"regex"'
|
||||
|
||||
# ── Phase 11.regex: parser ───────────────────────────────────────
|
||||
check 1020 "parse /abc/ head" 'js-regex'
|
||||
check 1021 "parse pattern arg" '"foo"'
|
||||
check 1022 "parse flags arg" '"gi"'
|
||||
|
||||
# ── Phase 11.regex: transpile ────────────────────────────────────
|
||||
check 1030 "transpile uses js-regex-new" 'js-regex-new'
|
||||
|
||||
# ── Phase 11.regex: runtime obj ──────────────────────────────────
|
||||
check 1040 "regex source" '"ab"'
|
||||
check 1041 "regex flags" '"g"'
|
||||
check 1042 "regex global true" 'true'
|
||||
check 1043 "js-regex? true" 'true'
|
||||
|
||||
# ── Phase 11.regex: property access ──────────────────────────────
|
||||
check 1050 "literal .source" '"abc"'
|
||||
check 1051 "literal .flags" '"gi"'
|
||||
check 1052 "literal .global" 'true'
|
||||
check 1053 "literal .ignoreCase" 'true'
|
||||
|
||||
# ── Phase 11.regex: test() ───────────────────────────────────────
|
||||
check 1060 "test match" 'true'
|
||||
check 1061 "test no match" 'false'
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "✓ $PASS/$TOTAL JS-on-SX tests passed"
|
||||
|
||||
Reference in New Issue
Block a user