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:
@@ -91,6 +91,7 @@
|
||||
(cond
|
||||
((and (js-promise? recv) (js-promise-builtin-method? key))
|
||||
(js-invoke-promise-method recv key args))
|
||||
((js-regex? recv) (js-regex-invoke-method recv key args))
|
||||
(else
|
||||
(let
|
||||
((m (js-get-prop recv key)))
|
||||
@@ -1593,4 +1594,96 @@
|
||||
|
||||
(define __drain (fn () (js-drain-microtasks!) :js-undefined))
|
||||
|
||||
(define __js_regex_platform__ (dict))
|
||||
|
||||
(define
|
||||
js-regex-platform-override!
|
||||
(fn (op impl) (dict-set! __js_regex_platform__ op impl)))
|
||||
|
||||
(define
|
||||
js-regex?
|
||||
(fn (v) (and (dict? v) (contains? (keys v) "__js_regex__"))))
|
||||
|
||||
(define
|
||||
js-regex-has-flag?
|
||||
(fn (flags ch) (>= (js-string-index-of flags ch 0) 0)))
|
||||
|
||||
(define
|
||||
js-regex-new
|
||||
(fn
|
||||
(pattern flags)
|
||||
(let
|
||||
((rx (dict))
|
||||
(fl (if (js-undefined? flags) "" (if (= flags nil) "" flags))))
|
||||
(dict-set! rx "__js_regex__" true)
|
||||
(dict-set! rx "source" pattern)
|
||||
(dict-set! rx "flags" fl)
|
||||
(dict-set! rx "global" (js-regex-has-flag? fl "g"))
|
||||
(dict-set! rx "ignoreCase" (js-regex-has-flag? fl "i"))
|
||||
(dict-set! rx "multiline" (js-regex-has-flag? fl "m"))
|
||||
(dict-set! rx "sticky" (js-regex-has-flag? fl "y"))
|
||||
(dict-set! rx "unicode" (js-regex-has-flag? fl "u"))
|
||||
(dict-set! rx "dotAll" (js-regex-has-flag? fl "s"))
|
||||
(dict-set! rx "hasIndices" (js-regex-has-flag? fl "d"))
|
||||
(dict-set! rx "lastIndex" 0)
|
||||
rx)))
|
||||
|
||||
(define
|
||||
js-regex-stub-test
|
||||
(fn
|
||||
(rx s)
|
||||
(let
|
||||
((src (get rx "source")) (ci (get rx "ignoreCase")))
|
||||
(let
|
||||
((hay (if ci (js-lower-case s) s))
|
||||
(needle (if ci (js-lower-case src) src)))
|
||||
(>= (js-string-index-of hay needle 0) 0)))))
|
||||
|
||||
(define
|
||||
js-regex-stub-exec
|
||||
(fn
|
||||
(rx s)
|
||||
(let
|
||||
((src (get rx "source")) (ci (get rx "ignoreCase")))
|
||||
(let
|
||||
((hay (if ci (js-lower-case s) s))
|
||||
(needle (if ci (js-lower-case src) src)))
|
||||
(let
|
||||
((idx (js-string-index-of hay needle 0)))
|
||||
(if
|
||||
(= idx -1)
|
||||
nil
|
||||
(let
|
||||
((matched (js-string-slice s idx (+ idx (len src))))
|
||||
(res (list)))
|
||||
(append! res matched)
|
||||
(dict-set! res "index" idx)
|
||||
(dict-set! res "input" s)
|
||||
res)))))))
|
||||
|
||||
(define
|
||||
js-regex-invoke-method
|
||||
(fn
|
||||
(rx name args)
|
||||
(cond
|
||||
((= name "test")
|
||||
(let
|
||||
((impl (get __js_regex_platform__ "test"))
|
||||
(arg (if (= (len args) 0) "" (js-to-string (nth args 0)))))
|
||||
(if
|
||||
(js-undefined? impl)
|
||||
(js-regex-stub-test rx arg)
|
||||
(impl rx arg))))
|
||||
((= name "exec")
|
||||
(let
|
||||
((impl (get __js_regex_platform__ "exec"))
|
||||
(arg (if (= (len args) 0) "" (js-to-string (nth args 0)))))
|
||||
(if
|
||||
(js-undefined? impl)
|
||||
(js-regex-stub-exec rx arg)
|
||||
(impl rx arg))))
|
||||
((= name "toString")
|
||||
(str "/" (get rx "source") "/" (get rx "flags")))
|
||||
(else js-undefined))))
|
||||
|
||||
(define js-global {:console console :Math Math :NaN 0 :Infinity (/ 1 0) :undefined js-undefined})
|
||||
|
||||
Reference in New Issue
Block a user