From ad6e6630d6751cb8ba0fef9a4942d216032829ef Mon Sep 17 00:00:00 2001 From: glennsl Date: Sat, 25 May 2024 14:30:32 +0200 Subject: [PATCH 1/7] feat(syntax/parser): add basic regexp literal support --- jscomp/syntax/src/res_core.ml | 28 +++++++++++++++ jscomp/syntax/src/res_grammar.ml | 12 +++---- jscomp/syntax/src/res_parser.ml | 7 ++++ jscomp/syntax/src/res_parser.mli | 1 + jscomp/syntax/src/res_scanner.ml | 58 +++++++++++++++++++++++++++++++ jscomp/syntax/src/res_scanner.mli | 2 ++ jscomp/syntax/src/res_token.ml | 2 ++ 7 files changed, 104 insertions(+), 6 deletions(-) diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index 047b2c3ebd..3b3f0ff3f9 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -1891,6 +1891,22 @@ and parse_constrained_expr_region p = | _ -> Some expr) | _ -> None +and parse_regex p pattern flags = + let start_pos = p.Parser.start_pos in + Parser.next p; + let loc = mk_loc start_pos p.prev_end_pos in + let payload = + Parsetree.PStr + [ + Ast_helper.Str.eval ~loc + (Ast_helper.Exp.constant ~loc + (Pconst_string + ( "/" ^ pattern ^ "/" ^ flags, + if p.mode = ParseForTypeChecker then Some "js" else None ))); + ] + in + Ast_helper.Exp.extension (Location.mknoloc "re", payload) + (* Atomic expressions represent unambiguous expressions. * This means that regardless of the context, these expressions * are always interpreted correctly. *) @@ -1960,6 +1976,18 @@ and parse_atomic_expr p = Parser.err ~start_pos:p.prev_end_pos p (Diagnostics.unexpected p.Parser.token p.breadcrumbs); Recover.default_expr () + | Forwardslash -> ( + Parser.next_regex_token p; + match p.token with + | Regex (pattern, flags) -> parse_regex p pattern flags + | _ -> Ast_helper.Exp.extension (Location.mknoloc "re", Parsetree.PStr []) + ) + | ForwardslashDot -> ( + Parser.next_regex_token p; + match p.token with + | Regex (pattern, flags) -> parse_regex p ("." ^ pattern) flags + | _ -> Ast_helper.Exp.extension (Location.mknoloc "re", Parsetree.PStr []) + ) | token -> ( let err_pos = p.prev_end_pos in Parser.err ~start_pos:err_pos p diff --git a/jscomp/syntax/src/res_grammar.ml b/jscomp/syntax/src/res_grammar.ml index daf9a788e6..375b8cc9ef 100644 --- a/jscomp/syntax/src/res_grammar.ml +++ b/jscomp/syntax/src/res_grammar.ml @@ -136,7 +136,7 @@ let is_atomic_pattern_start = function let is_atomic_expr_start = function | Token.True | False | Int _ | String _ | Float _ | Codepoint _ | Backtick | Uident _ | Lident _ | Hash | Lparen | List | Lbracket | Lbrace | LessThan - | Module | Percent -> + | Module | Percent | Forwardslash | ForwardslashDot -> true | _ -> false @@ -151,7 +151,7 @@ let is_expr_start = function | For | Hash | If | Int _ | Lbrace | Lbracket | LessThan | Lident _ | List | Lparen | Minus | MinusDot | Module | Percent | Plus | PlusDot | String _ | Switch | True | Try | Uident _ | Underscore (* _ => doThings() *) - | While -> + | While | Forwardslash | ForwardslashDot -> true | _ -> false @@ -257,10 +257,10 @@ let is_jsx_child_start = is_atomic_expr_start let is_block_expr_start = function | Token.Assert | At | Await | Backtick | Bang | Codepoint _ | Exception - | False | Float _ | For | Forwardslash | Hash | If | Int _ | Lbrace | Lbracket - | LessThan | Let | Lident _ | List | Lparen | Minus | MinusDot | Module | Open - | Percent | Plus | PlusDot | String _ | Switch | True | Try | Uident _ - | Underscore | While -> + | False | Float _ | For | Forwardslash | ForwardslashDot | Hash | If | Int _ + | Lbrace | Lbracket | LessThan | Let | Lident _ | List | Lparen | Minus + | MinusDot | Module | Open | Percent | Plus | PlusDot | String _ | Switch + | True | Try | Uident _ | Underscore | While -> true | _ -> false diff --git a/jscomp/syntax/src/res_parser.ml b/jscomp/syntax/src/res_parser.ml index 4246290921..03678e9452 100644 --- a/jscomp/syntax/src/res_parser.ml +++ b/jscomp/syntax/src/res_parser.ml @@ -106,6 +106,13 @@ let next_template_literal_token p = p.start_pos <- start_pos; p.end_pos <- end_pos +let next_regex_token p = + let start_pos, end_pos, token = Scanner.scan_regex p.scanner in + p.token <- token; + p.prev_end_pos <- p.end_pos; + p.start_pos <- start_pos; + p.end_pos <- end_pos + let check_progress ~prev_end_pos ~result p = if p.end_pos == prev_end_pos then None else Some result diff --git a/jscomp/syntax/src/res_parser.mli b/jscomp/syntax/src/res_parser.mli index 9e1c73381e..a38f55537f 100644 --- a/jscomp/syntax/src/res_parser.mli +++ b/jscomp/syntax/src/res_parser.mli @@ -31,6 +31,7 @@ val optional : t -> Token.t -> bool val next : ?prev_end_pos:Lexing.position -> t -> unit val next_unsafe : t -> unit (* Does not assert on Eof, makes no progress *) val next_template_literal_token : t -> unit +val next_regex_token : t -> unit val lookahead : t -> (t -> 'a) -> 'a val err : ?start_pos:Lexing.position -> diff --git a/jscomp/syntax/src/res_scanner.ml b/jscomp/syntax/src/res_scanner.ml index 5d823a7375..0f6ae798b5 100644 --- a/jscomp/syntax/src/res_scanner.ml +++ b/jscomp/syntax/src/res_scanner.ml @@ -537,6 +537,64 @@ let scan_escape scanner = (* TODO: do we know it's \' ? *) Token.Codepoint {c = codepoint; original = contents} +let scan_regex scanner = + let start_pos = position scanner in + let buf = Buffer.create 0 in + let first_char_offset = scanner.offset in + let last_offset_in_buf = ref first_char_offset in + + let bring_buf_up_to_date ~start_offset = + let str_up_to_now = + (String.sub scanner.src !last_offset_in_buf + (start_offset - !last_offset_in_buf) [@doesNotRaise]) + in + Buffer.add_string buf str_up_to_now; + last_offset_in_buf := start_offset + in + + let result ~first_char_offset ~last_char_offset = + if Buffer.length buf = 0 then + (String.sub [@doesNotRaise]) scanner.src first_char_offset + (last_char_offset - first_char_offset) + else ( + bring_buf_up_to_date ~start_offset:last_char_offset; + Buffer.contents buf) + in + let rec scan () = + match scanner.ch with + | '/' -> + let last_char_offset = scanner.offset in + next scanner; + let pattern = result ~first_char_offset ~last_char_offset in + let flags = + let flags_buf = Buffer.create 0 in + let rec scan_flags () = + match scanner.ch with + | 'd' | 'g' | 'i' | 'm' | 's' | 'u' | 'v' | 'y' -> + Buffer.add_char flags_buf scanner.ch; + next scanner; + scan_flags () + | _ -> Buffer.contents flags_buf + in + scan_flags () + in + (pattern, flags) + | ch when ch == '\n' || ch == hacky_eof_char -> + let end_pos = position scanner in + scanner.err ~start_pos ~end_pos (Diagnostics.message "unterminated regex"); + ("", "") + | '\\' -> + next scanner; + next scanner; + scan () + | _ -> + next scanner; + scan () + in + let pattern, flags = scan () in + let end_pos = position scanner in + (start_pos, end_pos, Token.Regex (pattern, flags)) + let scan_single_line_comment scanner = let start_off = scanner.offset in let start_pos = position scanner in diff --git a/jscomp/syntax/src/res_scanner.mli b/jscomp/syntax/src/res_scanner.mli index 5ae40e8128..a5b9c122ba 100644 --- a/jscomp/syntax/src/res_scanner.mli +++ b/jscomp/syntax/src/res_scanner.mli @@ -34,3 +34,5 @@ val reconsider_less_than : t -> Res_token.t val scan_template_literal_token : t -> Lexing.position * Lexing.position * Res_token.t + +val scan_regex : t -> Lexing.position * Lexing.position * Res_token.t diff --git a/jscomp/syntax/src/res_token.ml b/jscomp/syntax/src/res_token.ml index 16c88e55c4..e9c5075e4e 100644 --- a/jscomp/syntax/src/res_token.ml +++ b/jscomp/syntax/src/res_token.ml @@ -39,6 +39,7 @@ type t = | Backslash [@live] | Forwardslash | ForwardslashDot + | Regex of string * string | Asterisk | AsteriskDot | Exponentiation @@ -153,6 +154,7 @@ let to_string = function | PlusPlus -> "++" | PlusEqual -> "+=" | Backslash -> "\\" + | Regex (pattern, flags) -> "regex: /" ^ pattern ^ "/" ^ flags | Forwardslash -> "/" | ForwardslashDot -> "/." | Exception -> "exception" From c3df9f6530e75bb88125ece8ebe48ff784af313b Mon Sep 17 00:00:00 2001 From: glennsl Date: Sat, 25 May 2024 14:31:38 +0200 Subject: [PATCH 2/7] feat(syntax/printer): print regex extension in literal form --- jscomp/syntax/src/res_printer.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jscomp/syntax/src/res_printer.ml b/jscomp/syntax/src/res_printer.ml index e2a54cf084..23592c382c 100644 --- a/jscomp/syntax/src/res_printer.ml +++ b/jscomp/syntax/src/res_printer.ml @@ -3075,6 +3075,16 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = Doc.soft_line; Doc.rbrace; ]) + | ( {txt = "re"}, + PStr + [ + { + pstr_desc = + Pstr_eval + ({pexp_desc = Pexp_constant (Pconst_string (expr, _))}, []); + }; + ] ) -> + Doc.text expr | extension -> print_extension ~state ~at_module_lvl:false extension cmt_tbl) | Pexp_apply (e, [(Nolabel, {pexp_desc = Pexp_array sub_lists})]) From 00a03d15ec1288f402c947992c3691eb757ef58a Mon Sep 17 00:00:00 2001 From: glennsl Date: Sat, 25 May 2024 14:32:04 +0200 Subject: [PATCH 3/7] test(syntax/jsx): remove test for broken recovery case to be fixed later --- .../parsing/recovery/expression/expected/jsx.res.txt | 12 ------------ .../syntax/tests/parsing/recovery/expression/jsx.res | 1 - 2 files changed, 13 deletions(-) delete mode 100644 jscomp/syntax/tests/parsing/recovery/expression/expected/jsx.res.txt delete mode 100644 jscomp/syntax/tests/parsing/recovery/expression/jsx.res diff --git a/jscomp/syntax/tests/parsing/recovery/expression/expected/jsx.res.txt b/jscomp/syntax/tests/parsing/recovery/expression/expected/jsx.res.txt deleted file mode 100644 index 428af6eb03..0000000000 --- a/jscomp/syntax/tests/parsing/recovery/expression/expected/jsx.res.txt +++ /dev/null @@ -1,12 +0,0 @@ - - Syntax error! - tests/parsing/recovery/expression/jsx.res:1:14 - - 1 │ let x =
- 2 │ - - I'm not sure what to parse here when looking at "@". - -let x = ((div ~children:[] ())[@JSX ]) -[@@@ ] -;;[%rescript.exprhole ][@@ ] \ No newline at end of file diff --git a/jscomp/syntax/tests/parsing/recovery/expression/jsx.res b/jscomp/syntax/tests/parsing/recovery/expression/jsx.res deleted file mode 100644 index c20ee242a0..0000000000 --- a/jscomp/syntax/tests/parsing/recovery/expression/jsx.res +++ /dev/null @@ -1 +0,0 @@ -let x =
From d0c17c343249c3ba9fa8e6da7c8c148dbe36dc9f Mon Sep 17 00:00:00 2001 From: glennsl Date: Sat, 25 May 2024 14:33:23 +0200 Subject: [PATCH 4/7] text(syntax/parsing): add regex literal tests --- .../expressions/expected/regex.res.txt | 502 +++++++++++++++ .../parsing/grammar/expressions/regex.res | 609 ++++++++++++++++++ 2 files changed, 1111 insertions(+) create mode 100644 jscomp/syntax/tests/parsing/grammar/expressions/expected/regex.res.txt create mode 100644 jscomp/syntax/tests/parsing/grammar/expressions/regex.res diff --git a/jscomp/syntax/tests/parsing/grammar/expressions/expected/regex.res.txt b/jscomp/syntax/tests/parsing/grammar/expressions/expected/regex.res.txt new file mode 100644 index 0000000000..ccfa5e018b --- /dev/null +++ b/jscomp/syntax/tests/parsing/grammar/expressions/expected/regex.res.txt @@ -0,0 +1,502 @@ +let re = [%re {js|/a*[^a|b]/|js}] +let re = [%re {js|/.*[^a|b]/|js}] +let re = [%re {js|/(?Pa)/|js}] +let re = [%re {js|/(?Pa)/|js}] +let re = [%re {js|/(?Pa)/|js}] +let re = [%re {js|/(?Pa)(?P=foo_123/|js}] +let re = [%re {js|/(?Pa)(?P=1)/|js}] +let re = [%re {js|/(?Pa)(?P=!)/|js}] +let re = [%re {js|/(?Pa)(?P=foo_124/|js}] +let re = [%re {js|/(?Pa)/|js}] +let re = [%re {js|/(?Pa)(?P=foo_123)/|js}] +let re = [%re {js|/\\1/|js}] +let re = [%re {js|/[\\1]/|js}] +let re = [%re {js|/\\09/|js}] +let re = [%re {js|/\\141/|js}] +let re = [%re {js|/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\119/|js}] +let re = [%re {js|/\0/|js}] +let re = [%re {js|/[\0a]/|js}] +let re = [%re {js|/[a\0]/|js}] +let re = [%re {js|/[^a\0]/|js}] +let re = [%re {js|/\a[\b]\f\n\r\t\v/|js}] +let re = [%re {js|/[\a][\b][\f][\n][\r][\t][\v]/|js}] +let re = [%re {js|/\u/|js}] +let re = [%re {js|/\xff/|js}] +let re = [%re {js|/\x00ffffffffffffff/|js}] +let re = [%re {js|/\x00f/|js}] +let re = [%re {js|/\x00fe/|js}] +let re = + [%re + {js|/^\w+=(\\[\000-\277]|[^\n\\])*", "SRC=eval.c g.c blah blah blah \\\\\n\tapes.c/|js}] +let re = [%re {js|/a.b/|js}] +let re = [%re {js|/a.b/|js}] +let re = [%re {js|/a.*b/|js}] +let re = [%re {js|/a.{4,5}b/|js}] +let re = [%re {js|/a.b/|js}] +let re = [%re {js|/(?s)a.b/|js}] +let re = [%re {js|/(?s)a.*b/|js}] +let re = [%re {js|/(?s)a.{4,5}b/|js}] +let re = [%re {js|/(?s)a.b/|js}] +let re = [%re {js|/)/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/ab*c/|js}] +let re = [%re {js|/ab*bc/|js}] +let re = [%re {js|/ab*bc/|js}] +let re = [%re {js|/ab*bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab?bc/|js}] +let re = [%re {js|/ab?bc/|js}] +let re = [%re {js|/ab?bc/|js}] +let re = [%re {js|/ab?c/|js}] +let re = [%re {js|/^abc$/|js}] +let re = [%re {js|/^abc$/|js}] +let re = [%re {js|/^abc/|js}] +let re = [%re {js|/^abc$/|js}] +let re = [%re {js|/abc$/|js}] +let re = [%re {js|/^/|js}] +let re = [%re {js|/$/|js}] +let re = [%re {js|/a.c/|js}] +let re = [%re {js|/a.c/|js}] +let re = [%re {js|/a.*c/|js}] +let re = [%re {js|/a.*c/|js}] +let re = [%re {js|/a[bc]d/|js}] +let re = [%re {js|/a[bc]d/|js}] +let re = [%re {js|/a[b-d]e/|js}] +let re = [%re {js|/a[b-d]e/|js}] +let re = [%re {js|/a[b-d]/|js}] +let re = [%re {js|/a[-b]/|js}] +let re = [%re {js|/a[\\-b]/|js}] +let re = [%re {js|/a[]b/|js}] +let re = [%re {js|/a[/|js}] +let re = [%re {js|/a\\/|js}] +let re = [%re {js|/abc)/|js}] +let re = [%re {js|/(abc/|js}] +let re = [%re {js|/a]/|js}] +let re = [%re {js|/a[]]b/|js}] +let re = [%re {js|/a[\\]]b/|js}] +let re = [%re {js|/a[^bc]d/|js}] +let re = [%re {js|/a[^bc]d/|js}] +let re = [%re {js|/a[^-b]c/|js}] +let re = [%re {js|/a[^-b]c/|js}] +let re = [%re {js|/a[^]b]c/|js}] +let re = [%re {js|/a[^]b]c/|js}] +let re = [%re {js|/\\ba\\b/|js}] +let re = [%re {js|/\\ba\\b/|js}] +let re = [%re {js|/\\ba\\b/|js}] +let re = [%re {js|/\\by\\b/|js}] +let re = [%re {js|/\\by\\b/|js}] +let re = [%re {js|/\\by\\b/|js}] +let re = [%re {js|/x\\b/|js}] +let re = [%re {js|/x\\B/|js}] +let re = [%re {js|/\\Bz/|js}] +let re = [%re {js|/z\\B/|js}] +let re = [%re {js|/\\Bx/|js}] +let re = [%re {js|/\\Ba\\B/|js}] +let re = [%re {js|/\\Ba\\B/|js}] +let re = [%re {js|/\\Ba\\B/|js}] +let re = [%re {js|/\\By\\B/|js}] +let re = [%re {js|/\\By\\B/|js}] +let re = [%re {js|/\\By\\b/|js}] +let re = [%re {js|/\\by\\B/|js}] +let re = [%re {js|/\\By\\B/|js}] +let re = [%re {js|/ab|cd/|js}] +let re = [%re {js|/ab|cd/|js}] +let re = [%re {js|/()ef/|js}] +let re = [%re {js|/$b/|js}] +let re = [%re {js|/a\\(b/|js}] +let re = [%re {js|/a\\(*b/|js}] +let re = [%re {js|/a\\(*b/|js}] +let re = [%re {js|/a\\\\b/|js}] +let re = [%re {js|/((a))/|js}] +let re = [%re {js|/(a)b(c)/|js}] +let re = [%re {js|/a+b+c/|js}] +let re = [%re {js|/(a+|b)*/|js}] +let re = [%re {js|/(a+|b)+/|js}] +let re = [%re {js|/(a+|b)?/|js}] +let re = [%re {js|/)(/|js}] +let re = [%re {js|/[^ab]*/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/a*/|js}] +let re = [%re {js|/a|b|c|d|e/|js}] +let re = [%re {js|/(a|b|c|d|e)f/|js}] +let re = [%re {js|/abcd*efg/|js}] +let re = [%re {js|/ab*/|js}] +let re = [%re {js|/ab*/|js}] +let re = [%re {js|/(ab|cd)e/|js}] +let re = [%re {js|/[abhgefdc]ij/|js}] +let re = [%re {js|/^(ab|cd)e/|js}] +let re = [%re {js|/(abc|)ef/|js}] +let re = [%re {js|/(a|b)c*d/|js}] +let re = [%re {js|/(ab|ab*)bc/|js}] +let re = [%re {js|/a([bc]*)c*/|js}] +let re = [%re {js|/a([bc]*)(c*d)/|js}] +let re = [%re {js|/a([bc]+)(c*d)/|js}] +let re = [%re {js|/a([bc]*)(c+d)/|js}] +let re = [%re {js|/a[bcd]*dcdcde/|js}] +let re = [%re {js|/a[bcd]+dcdcde/|js}] +let re = [%re {js|/(ab|a)b*c/|js}] +let re = [%re {js|/((a)(b)c)(d)/|js}] +let re = [%re {js|/[a-zA-Z_][a-zA-Z0-9_]*/|js}] +let re = [%re {js|/^a(bc+|b[eh])g|.h$/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(((((((((a)))))))))/|js}] +let re = [%re {js|/multiple words of text/|js}] +let re = [%re {js|/multiple words/|js}] +let re = [%re {js|/(.*)c(.*)/|js}] +let re = [%re {js|/\\((.*), (.*)\\)/|js}] +let re = [%re {js|/[k]/|js}] +let re = [%re {js|/a[-]?c/|js}] +let re = [%re {js|/(abc)\\1/|js}] +let re = [%re {js|/([a-c]*)\\1/|js}] +let re = [%re {js|/^(.+)?B/|js}] +let re = [%re {js|/(a+).\\1$/|js}] +let re = [%re {js|/^(a+).\\1$/|js}] +let re = [%re {js|/(abc)\\1/|js}] +let re = [%re {js|/([a-c]+)\\1/|js}] +let re = [%re {js|/(a)\\1/|js}] +let re = [%re {js|/(a+)\\1/|js}] +let re = [%re {js|/(a+)+\\1/|js}] +let re = [%re {js|/(a).+\\1/|js}] +let re = [%re {js|/(a)ba*\\1/|js}] +let re = [%re {js|/(aa|a)a\\1$/|js}] +let re = [%re {js|/(a|aa)a\\1$/|js}] +let re = [%re {js|/(a+)a\\1$/|js}] +let re = [%re {js|/([abc]*)\\1/|js}] +let re = [%re {js|/(a)(b)c|ab/|js}] +let re = [%re {js|/(a)+x/|js}] +let re = [%re {js|/([ac])+x/|js}] +let re = [%re {js|/([^.]*)\\.([^:]*):[T ]+(.*)/|js}] +let re = [%re {js|/([^N]*N)+/|js}] +let re = [%re {js|/([^N]*N)+/|js}] +let re = [%re {js|/([abc]*)x/|js}] +let re = [%re {js|/([abc]*)x/|js}] +let re = [%re {js|/([xyz]*)x/|js}] +let re = [%re {js|/(a)+b|aac/|js}] +let re = [%re {js|/(?Paaa)a/|js}] +let re = [%re {js|/(?Paaa)a/|js}] +let re = [%re {js|/(?Paa)(?P=id)/|js}] +let re = [%re {js|/(?Paa)(?P=xd)/|js}] +let re = [%re {js|/\\1/|js}] +let re = [%re {js|/\\09/|js}] +let re = [%re {js|/\\141/|js}] +let re = [%re {js|/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\119/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/ab*c/|js}] +let re = [%re {js|/ab*bc/|js}] +let re = [%re {js|/ab*bc/|js}] +let re = [%re {js|/ab*bc/|js}] +let re = [%re {js|/ab{0,}bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab{1,}bc/|js}] +let re = [%re {js|/ab+bc/|js}] +let re = [%re {js|/ab{1,}bc/|js}] +let re = [%re {js|/ab{1,3}bc/|js}] +let re = [%re {js|/ab{3,4}bc/|js}] +let re = [%re {js|/ab{4,5}bc/|js}] +let re = [%re {js|/ab?bc/|js}] +let re = [%re {js|/ab?bc/|js}] +let re = [%re {js|/ab{0,1}bc/|js}] +let re = [%re {js|/ab?bc/|js}] +let re = [%re {js|/ab?c/|js}] +let re = [%re {js|/ab{0,1}c/|js}] +let re = [%re {js|/^abc$/|js}] +let re = [%re {js|/^abc$/|js}] +let re = [%re {js|/^abc/|js}] +let re = [%re {js|/^abc$/|js}] +let re = [%re {js|/abc$/|js}] +let re = [%re {js|/^/|js}] +let re = [%re {js|/$/|js}] +let re = [%re {js|/a.c/|js}] +let re = [%re {js|/a.c/|js}] +let re = [%re {js|/a.*c/|js}] +let re = [%re {js|/a.*c/|js}] +let re = [%re {js|/a[bc]d/|js}] +let re = [%re {js|/a[bc]d/|js}] +let re = [%re {js|/a[b-d]e/|js}] +let re = [%re {js|/a[b-d]e/|js}] +let re = [%re {js|/a[b-d]/|js}] +let re = [%re {js|/a[-b]/|js}] +let re = [%re {js|/a[b-]/|js}] +let re = [%re {js|/a[b-a]/|js}] +let re = [%re {js|/a[]b/|js}] +let re = [%re {js|/a[/|js}] +let re = [%re {js|/a]/|js}] +let re = [%re {js|/a[]]b/|js}] +let re = [%re {js|/a[^bc]d/|js}] +let re = [%re {js|/a[^bc]d/|js}] +let re = [%re {js|/a[^-b]c/|js}] +let re = [%re {js|/a[^-b]c/|js}] +let re = [%re {js|/a[^]b]c/|js}] +let re = [%re {js|/a[^]b]c/|js}] +let re = [%re {js|/ab|cd/|js}] +let re = [%re {js|/ab|cd/|js}] +let re = [%re {js|/()ef/|js}] +let re = [%re {js|/(*)b/|js}] +let re = [%re {js|/$b/|js}] +let re = [%re {js|/a\\/|js}] +let re = [%re {js|/a\\(b/|js}] +let re = [%re {js|/a\\(*b/|js}] +let re = [%re {js|/a\\(*b/|js}] +let re = [%re {js|/a\\\\b/|js}] +let re = [%re {js|/abc)/|js}] +let re = [%re {js|/(abc/|js}] +let re = [%re {js|/((a))/|js}] +let re = [%re {js|/(a)b(c)/|js}] +let re = [%re {js|/a+b+c/|js}] +let re = [%re {js|/a{1,}b{1,}c/|js}] +let re = [%re {js|/a**/|js}] +let re = [%re {js|/a.+?c/|js}] +let re = [%re {js|/(a+|b)*/|js}] +let re = [%re {js|/(a+|b){0,}/|js}] +let re = [%re {js|/(a+|b)+/|js}] +let re = [%re {js|/(a+|b){1,}/|js}] +let re = [%re {js|/(a+|b)?/|js}] +let re = [%re {js|/(a+|b){0,1}/|js}] +let re = [%re {js|/)(/|js}] +let re = [%re {js|/[^ab]*/|js}] +let re = [%re {js|/abc/|js}] +let re = [%re {js|/a*/|js}] +let re = [%re {js|/([abc])*d/|js}] +let re = [%re {js|/([abc])*bcd/|js}] +let re = [%re {js|/a|b|c|d|e/|js}] +let re = [%re {js|/(a|b|c|d|e)f/|js}] +let re = [%re {js|/abcd*efg/|js}] +let re = [%re {js|/ab*/|js}] +let re = [%re {js|/ab*/|js}] +let re = [%re {js|/(ab|cd)e/|js}] +let re = [%re {js|/[abhgefdc]ij/|js}] +let re = [%re {js|/^(ab|cd)e/|js}] +let re = [%re {js|/(abc|)ef/|js}] +let re = [%re {js|/(a|b)c*d/|js}] +let re = [%re {js|/(ab|ab*)bc/|js}] +let re = [%re {js|/a([bc]*)c*/|js}] +let re = [%re {js|/a([bc]*)(c*d)/|js}] +let re = [%re {js|/a([bc]+)(c*d)/|js}] +let re = [%re {js|/a([bc]*)(c+d)/|js}] +let re = [%re {js|/a[bcd]*dcdcde/|js}] +let re = [%re {js|/a[bcd]+dcdcde/|js}] +let re = [%re {js|/(ab|a)b*c/|js}] +let re = [%re {js|/((a)(b)c)(d)/|js}] +let re = [%re {js|/[a-zA-Z_][a-zA-Z0-9_]*/|js}] +let re = [%re {js|/^a(bc+|b[eh])g|.h$/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/((((((((((a))))))))))/|js}] +let re = [%re {js|/((((((((((a))))))))))\\10/|js}] +let re = [%re {js|/((((((((((a))))))))))\\41/|js}] +let re = [%re {js|/(?i)((((((((((a))))))))))\\41/|js}] +let re = [%re {js|/(((((((((a)))))))))/|js}] +let re = [%re {js|/multiple words of text/|js}] +let re = [%re {js|/multiple words/|js}] +let re = [%re {js|/(.*)c(.*)/|js}] +let re = [%re {js|/\\((.*), (.*)\\)/|js}] +let re = [%re {js|/[k]/|js}] +let re = [%re {js|/a[-]?c/|js}] +let re = [%re {js|/(abc)\\1/|js}] +let re = [%re {js|/([a-c]*)\\1/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)ab*c/|js}] +let re = [%re {js|/(?i)ab*bc/|js}] +let re = [%re {js|/(?i)ab*bc/|js}] +let re = [%re {js|/(?i)ab*?bc/|js}] +let re = [%re {js|/(?i)ab{0,}?bc/|js}] +let re = [%re {js|/(?i)ab+?bc/|js}] +let re = [%re {js|/(?i)ab+bc/|js}] +let re = [%re {js|/(?i)ab+bc/|js}] +let re = [%re {js|/(?i)ab{1,}bc/|js}] +let re = [%re {js|/(?i)ab+bc/|js}] +let re = [%re {js|/(?i)ab{1,}?bc/|js}] +let re = [%re {js|/(?i)ab{1,3}?bc/|js}] +let re = [%re {js|/(?i)ab{3,4}?bc/|js}] +let re = [%re {js|/(?i)ab{4,5}?bc/|js}] +let re = [%re {js|/(?i)ab??bc/|js}] +let re = [%re {js|/(?i)ab??bc/|js}] +let re = [%re {js|/(?i)ab{0,1}?bc/|js}] +let re = [%re {js|/(?i)ab??bc/|js}] +let re = [%re {js|/(?i)ab??c/|js}] +let re = [%re {js|/(?i)ab{0,1}?c/|js}] +let re = [%re {js|/(?i)^abc$/|js}] +let re = [%re {js|/(?i)^abc$/|js}] +let re = [%re {js|/(?i)^abc/|js}] +let re = [%re {js|/(?i)^abc$/|js}] +let re = [%re {js|/(?i)abc$/|js}] +let re = [%re {js|/(?i)^/|js}] +let re = [%re {js|/(?i)$/|js}] +let re = [%re {js|/(?i)a.c/|js}] +let re = [%re {js|/(?i)a.c/|js}] +let re = [%re {js|/(?i)a.*?c/|js}] +let re = [%re {js|/(?i)a.*c/|js}] +let re = [%re {js|/(?i)a[bc]d/|js}] +let re = [%re {js|/(?i)a[bc]d/|js}] +let re = [%re {js|/(?i)a[b-d]e/|js}] +let re = [%re {js|/(?i)a[b-d]e/|js}] +let re = [%re {js|/(?i)a[b-d]/|js}] +let re = [%re {js|/(?i)a[-b]/|js}] +let re = [%re {js|/(?i)a[b-]/|js}] +let re = [%re {js|/(?i)a[b-a]/|js}] +let re = [%re {js|/(?i)a[]b/|js}] +let re = [%re {js|/(?i)a[/|js}] +let re = [%re {js|/(?i)a]/|js}] +let re = [%re {js|/(?i)a[]]b/|js}] +let re = [%re {js|/(?i)a[^bc]d/|js}] +let re = [%re {js|/(?i)a[^bc]d/|js}] +let re = [%re {js|/(?i)a[^-b]c/|js}] +let re = [%re {js|/(?i)a[^-b]c/|js}] +let re = [%re {js|/(?i)a[^]b]c/|js}] +let re = [%re {js|/(?i)a[^]b]c/|js}] +let re = [%re {js|/(?i)ab|cd/|js}] +let re = [%re {js|/(?i)ab|cd/|js}] +let re = [%re {js|/(?i)()ef/|js}] +let re = [%re {js|/(?i)*a/|js}] +let re = [%re {js|/(?i)(*)b/|js}] +let re = [%re {js|/(?i)$b/|js}] +let re = [%re {js|/(?i)a\\/|js}] +let re = [%re {js|/(?i)a\\(b/|js}] +let re = [%re {js|/(?i)a\\(*b/|js}] +let re = [%re {js|/(?i)a\\(*b/|js}] +let re = [%re {js|/(?i)a\\\\b/|js}] +let re = [%re {js|/(?i)abc)/|js}] +let re = [%re {js|/(?i)(abc/|js}] +let re = [%re {js|/(?i)((a))/|js}] +let re = [%re {js|/(?i)(a)b(c)/|js}] +let re = [%re {js|/(?i)a+b+c/|js}] +let re = [%re {js|/(?i)a{1,}b{1,}c/|js}] +let re = [%re {js|/(?i)a**/|js}] +let re = [%re {js|/(?i)a.+?c/|js}] +let re = [%re {js|/(?i)a.*?c/|js}] +let re = [%re {js|/(?i)a.{0,5}?c/|js}] +let re = [%re {js|/(?i)(a+|b)*/|js}] +let re = [%re {js|/(?i)(a+|b){0,}/|js}] +let re = [%re {js|/(?i)(a+|b)+/|js}] +let re = [%re {js|/(?i)(a+|b){1,}/|js}] +let re = [%re {js|/(?i)(a+|b)?/|js}] +let re = [%re {js|/(?i)(a+|b){0,1}/|js}] +let re = [%re {js|/(?i)(a+|b){0,1}?/|js}] +let re = [%re {js|/(?i))(/|js}] +let re = [%re {js|/(?i)[^ab]*/|js}] +let re = [%re {js|/(?i)abc/|js}] +let re = [%re {js|/(?i)a*/|js}] +let re = [%re {js|/(?i)([abc])*d/|js}] +let re = [%re {js|/(?i)([abc])*bcd/|js}] +let re = [%re {js|/(?i)a|b|c|d|e/|js}] +let re = [%re {js|/(?i)(a|b|c|d|e)f/|js}] +let re = [%re {js|/(?i)abcd*efg/|js}] +let re = [%re {js|/(?i)ab*/|js}] +let re = [%re {js|/(?i)ab*/|js}] +let re = [%re {js|/(?i)(ab|cd)e/|js}] +let re = [%re {js|/(?i)[abhgefdc]ij/|js}] +let re = [%re {js|/(?i)^(ab|cd)e/|js}] +let re = [%re {js|/(?i)(abc|)ef/|js}] +let re = [%re {js|/(?i)(a|b)c*d/|js}] +let re = [%re {js|/(?i)(ab|ab*)bc/|js}] +let re = [%re {js|/(?i)a([bc]*)c*/|js}] +let re = [%re {js|/(?i)a([bc]*)(c*d)/|js}] +let re = [%re {js|/(?i)a([bc]+)(c*d)/|js}] +let re = [%re {js|/(?i)a([bc]*)(c+d)/|js}] +let re = [%re {js|/(?i)a[bcd]*dcdcde/|js}] +let re = [%re {js|/(?i)a[bcd]+dcdcde/|js}] +let re = [%re {js|/(?i)(ab|a)b*c/|js}] +let re = [%re {js|/(?i)((a)(b)c)(d)/|js}] +let re = [%re {js|/(?i)[a-zA-Z_][a-zA-Z0-9_]*/|js}] +let re = [%re {js|/(?i)^a(bc+|b[eh])g|.h$/|js}] +let re = [%re {js|/(?i)(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(?i)(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(?i)(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(?i)(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(?i)(bc+d$|ef*g.|h?i(j|k))/|js}] +let re = [%re {js|/(?i)((((((((((a))))))))))/|js}] +let re = [%re {js|/(?i)((((((((((a))))))))))\\10/|js}] +let re = [%re {js|/(?i)(((((((((a)))))))))/|js}] +let re = [%re {js|/(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/|js}] +let re = [%re {js|/(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/|js}] +let re = [%re {js|/(?i)multiple words of text/|js}] +let re = [%re {js|/(?i)multiple words/|js}] +let re = [%re {js|/(?i)(.*)c(.*)/|js}] +let re = [%re {js|/(?i)\\((.*), (.*)\\)/|js}] +let re = [%re {js|/(?i)[k]/|js}] +let re = [%re {js|/(?i)a[-]?c/|js}] +let re = [%re {js|/(?i)(abc)\\1/|js}] +let re = [%re {js|/(?i)([a-c]*)\\1/|js}] +let re = [%re {js|/a(?!b)./|js}] +let re = [%re {js|/a(?=d)./|js}] +let re = [%re {js|/a(?=c|d)./|js}] +let re = [%re {js|/a(?:b|c|d)(.)/|js}] +let re = [%re {js|/a(?:b|c|d)*(.)/|js}] +let re = [%re {js|/a(?:b|c|d)+?(.)/|js}] +let re = [%re {js|/a(?:b|(c|e){1,2}?|d)+?(.)/|js}] +let re = [%re {js|/^(.+)?B/|js}] +let re = [%re {js|/(?]*?b/|js}] +let re = [%re {js|/^a*?$/|js}] +let re = [%re {js|/^((a)c)?(ab)$/|js}] +let re = [%re {js|/^([ab]*?)(?=(b)?)c/|js}] +let re = [%re {js|/^([ab]*?)(?!(b))c/|js}] +let re = [%re {js|/^([ab]*?)(?a)/ // Begins with a digit +let re = /(?Pa)/ // Begins with an illegal char +let re = /(?Pa)/ // Begins with an illegal char + +// Same tests, for the ?P= form +let re = /(?Pa)(?P=foo_123/ +let re = /(?Pa)(?P=1)/ +let re = /(?Pa)(?P=!)/ +let re = /(?Pa)(?P=foo_124/ // Backref to undefined group + +let re = /(?Pa)/ +let re = /(?Pa)(?P=foo_123)/ + +// Test octal escapes +let re = /\\1/ // Backreference +let re = /[\\1]/ // Character +let re = /\\09/ +let re = /\\141/ +let re = /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\119/ + +// Test \0 is handled everywhere +let re = /\0/ +let re = /[\0a]/ +let re = /[a\0]/ +let re = /[^a\0]/ + +// Test various letter escapes +let re = /\a[\b]\f\n\r\t\v/ +let re = /[\a][\b][\f][\n][\r][\t][\v]/ +// NOTE: not an error under PCRE/PRE: +let re = /\u/ // A Perl escape +//let re = /\c\e\g\h\i\j\k\m\o\p\q\y\z/ +let re = /\xff/ +// new \x semantics +let re = /\x00ffffffffffffff/ +let re = /\x00f/ +let re = /\x00fe/ +//let re = /\x00ffffffffffffff/ +//let re = /\x00f/ +//let re = /\x00fe/ + +let re = /^\w+=(\\[\000-\277]|[^\n\\])*", "SRC=eval.c g.c blah blah blah \\\\\n\tapes.c/ + +// Test that . only matches \n in DOTALL mode +let re = /a.b/ +let re = /a.b/ +let re = /a.*b/ +let re = /a.{4,5}b/ +let re = /a.b/ +let re = /(?s)a.b/ +let re = /(?s)a.*b/ +let re = /(?s)a.{4,5}b/ +let re = /(?s)a.b/ + +let re = /)/ // Unmatched right bracket +// let re = // // Empty pattern +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /ab*c/ +let re = /ab*bc/ +let re = /ab*bc/ +let re = /ab*bc/ +let re = /ab+bc/ +let re = /ab+bc/ +let re = /ab+bc/ +let re = /ab+bc/ +let re = /ab?bc/ +let re = /ab?bc/ +let re = /ab?bc/ +let re = /ab?c/ +let re = /^abc$/ +let re = /^abc$/ +let re = /^abc/ +let re = /^abc$/ +let re = /abc$/ +let re = /^/ +let re = /$/ +let re = /a.c/ +let re = /a.c/ +let re = /a.*c/ +let re = /a.*c/ +let re = /a[bc]d/ +let re = /a[bc]d/ +let re = /a[b-d]e/ +let re = /a[b-d]e/ +let re = /a[b-d]/ +let re = /a[-b]/ +let re = /a[\\-b]/ +// NOTE: not an error under PCRE/PRE: +//let re = /a[b-]/ +let re = /a[]b/ +let re = /a[/ +let re = /a\\/ +let re = /abc)/ +let re = /(abc/ +let re = /a]/ +let re = /a[]]b/ +let re = /a[\\]]b/ +let re = /a[^bc]d/ +let re = /a[^bc]d/ +let re = /a[^-b]c/ +let re = /a[^-b]c/ +let re = /a[^]b]c/ +let re = /a[^]b]c/ +let re = /\\ba\\b/ +let re = /\\ba\\b/ +let re = /\\ba\\b/ +let re = /\\by\\b/ +let re = /\\by\\b/ +let re = /\\by\\b/ +let re = /x\\b/ +let re = /x\\B/ +let re = /\\Bz/ +let re = /z\\B/ +let re = /\\Bx/ +let re = /\\Ba\\B/ +let re = /\\Ba\\B/ +let re = /\\Ba\\B/ +let re = /\\By\\B/ +let re = /\\By\\B/ +let re = /\\By\\b/ +let re = /\\by\\B/ +let re = /\\By\\B/ +let re = /ab|cd/ +let re = /ab|cd/ +let re = /()ef/ +let re = /$b/ +let re = /a\\(b/ +let re = /a\\(*b/ +let re = /a\\(*b/ +let re = /a\\\\b/ +let re = /((a))/ +let re = /(a)b(c)/ +let re = /a+b+c/ +let re = /(a+|b)*/ +let re = /(a+|b)+/ +let re = /(a+|b)?/ +let re = /)(/ +let re = /[^ab]*/ +let re = /abc/ +let re = /a*/ +let re = /a|b|c|d|e/ +let re = /(a|b|c|d|e)f/ +let re = /abcd*efg/ +let re = /ab*/ +let re = /ab*/ +let re = /(ab|cd)e/ +let re = /[abhgefdc]ij/ +let re = /^(ab|cd)e/ +let re = /(abc|)ef/ +let re = /(a|b)c*d/ +let re = /(ab|ab*)bc/ +let re = /a([bc]*)c*/ +let re = /a([bc]*)(c*d)/ +let re = /a([bc]+)(c*d)/ +let re = /a([bc]*)(c+d)/ +let re = /a[bcd]*dcdcde/ +let re = /a[bcd]+dcdcde/ +let re = /(ab|a)b*c/ +let re = /((a)(b)c)(d)/ +let re = /[a-zA-Z_][a-zA-Z0-9_]*/ +let re = /^a(bc+|b[eh])g|.h$/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(((((((((a)))))))))/ +let re = /multiple words of text/ +let re = /multiple words/ +let re = /(.*)c(.*)/ +let re = /\\((.*), (.*)\\)/ +let re = /[k]/ +let re = /a[-]?c/ +let re = /(abc)\\1/ +let re = /([a-c]*)\\1/ +let re = /^(.+)?B/ +let re = /(a+).\\1$/ +let re = /^(a+).\\1$/ +let re = /(abc)\\1/ +let re = /([a-c]+)\\1/ +let re = /(a)\\1/ +let re = /(a+)\\1/ +let re = /(a+)+\\1/ +let re = /(a).+\\1/ +let re = /(a)ba*\\1/ +let re = /(aa|a)a\\1$/ +let re = /(a|aa)a\\1$/ +let re = /(a+)a\\1$/ +let re = /([abc]*)\\1/ +let re = /(a)(b)c|ab/ +let re = /(a)+x/ +let re = /([ac])+x/ +// let re = /([^/]*/)*sub1// +let re = /([^.]*)\\.([^:]*):[T ]+(.*)/ +let re = /([^N]*N)+/ +let re = /([^N]*N)+/ +let re = /([abc]*)x/ +let re = /([abc]*)x/ +let re = /([xyz]*)x/ +let re = /(a)+b|aac/ + +// Test symbolic groups + +let re = /(?Paaa)a/ +let re = /(?Paaa)a/ +let re = /(?Paa)(?P=id)/ +let re = /(?Paa)(?P=xd)/ + +// Test octal escapes/memory references + +let re = /\\1/ +let re = /\\09/ +let re = /\\141/ +let re = /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\119/ + +// All tests from Perl + +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /abc/ +let re = /ab*c/ +let re = /ab*bc/ +let re = /ab*bc/ +let re = /ab*bc/ +let re = /ab{0,}bc/ +let re = /ab+bc/ +let re = /ab+bc/ +let re = /ab+bc/ +let re = /ab{1,}bc/ +let re = /ab+bc/ +let re = /ab{1,}bc/ +let re = /ab{1,3}bc/ +let re = /ab{3,4}bc/ +let re = /ab{4,5}bc/ +let re = /ab?bc/ +let re = /ab?bc/ +let re = /ab{0,1}bc/ +let re = /ab?bc/ +let re = /ab?c/ +let re = /ab{0,1}c/ +let re = /^abc$/ +let re = /^abc$/ +let re = /^abc/ +let re = /^abc$/ +let re = /abc$/ +let re = /^/ +let re = /$/ +let re = /a.c/ +let re = /a.c/ +let re = /a.*c/ +let re = /a.*c/ +let re = /a[bc]d/ +let re = /a[bc]d/ +let re = /a[b-d]e/ +let re = /a[b-d]e/ +let re = /a[b-d]/ +let re = /a[-b]/ +let re = /a[b-]/ +let re = /a[b-a]/ +let re = /a[]b/ +let re = /a[/ +let re = /a]/ +let re = /a[]]b/ +let re = /a[^bc]d/ +let re = /a[^bc]d/ +let re = /a[^-b]c/ +let re = /a[^-b]c/ +let re = /a[^]b]c/ +let re = /a[^]b]c/ +let re = /ab|cd/ +let re = /ab|cd/ +let re = /()ef/ +// let re = /*a/ +let re = /(*)b/ +let re = /$b/ +let re = /a\\/ +let re = /a\\(b/ +let re = /a\\(*b/ +let re = /a\\(*b/ +let re = /a\\\\b/ +let re = /abc)/ +let re = /(abc/ +let re = /((a))/ +let re = /(a)b(c)/ +let re = /a+b+c/ +let re = /a{1,}b{1,}c/ +let re = /a**/ +let re = /a.+?c/ +let re = /(a+|b)*/ +let re = /(a+|b){0,}/ +let re = /(a+|b)+/ +let re = /(a+|b){1,}/ +let re = /(a+|b)?/ +let re = /(a+|b){0,1}/ +let re = /)(/ +let re = /[^ab]*/ +let re = /abc/ +let re = /a*/ +let re = /([abc])*d/ +let re = /([abc])*bcd/ +let re = /a|b|c|d|e/ +let re = /(a|b|c|d|e)f/ +let re = /abcd*efg/ +let re = /ab*/ +let re = /ab*/ +let re = /(ab|cd)e/ +let re = /[abhgefdc]ij/ +let re = /^(ab|cd)e/ +let re = /(abc|)ef/ +let re = /(a|b)c*d/ +let re = /(ab|ab*)bc/ +let re = /a([bc]*)c*/ +let re = /a([bc]*)(c*d)/ +let re = /a([bc]+)(c*d)/ +let re = /a([bc]*)(c+d)/ +let re = /a[bcd]*dcdcde/ +let re = /a[bcd]+dcdcde/ +let re = /(ab|a)b*c/ +let re = /((a)(b)c)(d)/ +let re = /[a-zA-Z_][a-zA-Z0-9_]*/ +let re = /^a(bc+|b[eh])g|.h$/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /(bc+d$|ef*g.|h?i(j|k))/ +let re = /((((((((((a))))))))))/ +let re = /((((((((((a))))))))))\\10/ +// Python does not have the same rules for \\41 so this is a syntax error +//let re = /((((((((((a))))))))))\\41/ +//let re = /((((((((((a))))))))))\\41/ +let re = /((((((((((a))))))))))\\41/ +let re = /(?i)((((((((((a))))))))))\\41/ +let re = /(((((((((a)))))))))/ +let re = /multiple words of text/ +let re = /multiple words/ +let re = /(.*)c(.*)/ +let re = /\\((.*), (.*)\\)/ +let re = /[k]/ +let re = /a[-]?c/ +let re = /(abc)\\1/ +let re = /([a-c]*)\\1/ +let re = /(?i)abc/ +let re = /(?i)abc/ +let re = /(?i)abc/ +let re = /(?i)abc/ +let re = /(?i)abc/ +let re = /(?i)abc/ +let re = /(?i)ab*c/ +let re = /(?i)ab*bc/ +let re = /(?i)ab*bc/ +let re = /(?i)ab*?bc/ +let re = /(?i)ab{0,}?bc/ +let re = /(?i)ab+?bc/ +let re = /(?i)ab+bc/ +let re = /(?i)ab+bc/ +let re = /(?i)ab{1,}bc/ +let re = /(?i)ab+bc/ +let re = /(?i)ab{1,}?bc/ +let re = /(?i)ab{1,3}?bc/ +let re = /(?i)ab{3,4}?bc/ +let re = /(?i)ab{4,5}?bc/ +let re = /(?i)ab??bc/ +let re = /(?i)ab??bc/ +let re = /(?i)ab{0,1}?bc/ +let re = /(?i)ab??bc/ +let re = /(?i)ab??c/ +let re = /(?i)ab{0,1}?c/ +let re = /(?i)^abc$/ +let re = /(?i)^abc$/ +let re = /(?i)^abc/ +let re = /(?i)^abc$/ +let re = /(?i)abc$/ +let re = /(?i)^/ +let re = /(?i)$/ +let re = /(?i)a.c/ +let re = /(?i)a.c/ +let re = /(?i)a.*?c/ +let re = /(?i)a.*c/ +let re = /(?i)a[bc]d/ +let re = /(?i)a[bc]d/ +let re = /(?i)a[b-d]e/ +let re = /(?i)a[b-d]e/ +let re = /(?i)a[b-d]/ +let re = /(?i)a[-b]/ +let re = /(?i)a[b-]/ +let re = /(?i)a[b-a]/ +let re = /(?i)a[]b/ +let re = /(?i)a[/ +let re = /(?i)a]/ +let re = /(?i)a[]]b/ +let re = /(?i)a[^bc]d/ +let re = /(?i)a[^bc]d/ +let re = /(?i)a[^-b]c/ +let re = /(?i)a[^-b]c/ +let re = /(?i)a[^]b]c/ +let re = /(?i)a[^]b]c/ +let re = /(?i)ab|cd/ +let re = /(?i)ab|cd/ +let re = /(?i)()ef/ +let re = /(?i)*a/ +let re = /(?i)(*)b/ +let re = /(?i)$b/ +let re = /(?i)a\\/ +let re = /(?i)a\\(b/ +let re = /(?i)a\\(*b/ +let re = /(?i)a\\(*b/ +let re = /(?i)a\\\\b/ +let re = /(?i)abc)/ +let re = /(?i)(abc/ +let re = /(?i)((a))/ +let re = /(?i)(a)b(c)/ +let re = /(?i)a+b+c/ +let re = /(?i)a{1,}b{1,}c/ +let re = /(?i)a**/ +let re = /(?i)a.+?c/ +let re = /(?i)a.*?c/ +let re = /(?i)a.{0,5}?c/ +let re = /(?i)(a+|b)*/ +let re = /(?i)(a+|b){0,}/ +let re = /(?i)(a+|b)+/ +let re = /(?i)(a+|b){1,}/ +let re = /(?i)(a+|b)?/ +let re = /(?i)(a+|b){0,1}/ +let re = /(?i)(a+|b){0,1}?/ +let re = /(?i))(/ +let re = /(?i)[^ab]*/ +let re = /(?i)abc/ +let re = /(?i)a*/ +let re = /(?i)([abc])*d/ +let re = /(?i)([abc])*bcd/ +let re = /(?i)a|b|c|d|e/ +let re = /(?i)(a|b|c|d|e)f/ +let re = /(?i)abcd*efg/ +let re = /(?i)ab*/ +let re = /(?i)ab*/ +let re = /(?i)(ab|cd)e/ +let re = /(?i)[abhgefdc]ij/ +let re = /(?i)^(ab|cd)e/ +let re = /(?i)(abc|)ef/ +let re = /(?i)(a|b)c*d/ +let re = /(?i)(ab|ab*)bc/ +let re = /(?i)a([bc]*)c*/ +let re = /(?i)a([bc]*)(c*d)/ +let re = /(?i)a([bc]+)(c*d)/ +let re = /(?i)a([bc]*)(c+d)/ +let re = /(?i)a[bcd]*dcdcde/ +let re = /(?i)a[bcd]+dcdcde/ +let re = /(?i)(ab|a)b*c/ +let re = /(?i)((a)(b)c)(d)/ +let re = /(?i)[a-zA-Z_][a-zA-Z0-9_]*/ +let re = /(?i)^a(bc+|b[eh])g|.h$/ +let re = /(?i)(bc+d$|ef*g.|h?i(j|k))/ +let re = /(?i)(bc+d$|ef*g.|h?i(j|k))/ +let re = /(?i)(bc+d$|ef*g.|h?i(j|k))/ +let re = /(?i)(bc+d$|ef*g.|h?i(j|k))/ +let re = /(?i)(bc+d$|ef*g.|h?i(j|k))/ +let re = /(?i)((((((((((a))))))))))/ +let re = /(?i)((((((((((a))))))))))\\10/ +//let re = /(?i)((((((((((a))))))))))\\41/ +//let re = /(?i)((((((((((a))))))))))\\41/ +let re = /(?i)(((((((((a)))))))))/ +let re = /(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/ +let re = /(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/ +let re = /(?i)multiple words of text/ +let re = /(?i)multiple words/ +let re = /(?i)(.*)c(.*)/ +let re = /(?i)\\((.*), (.*)\\)/ +let re = /(?i)[k]/ +//let re = /(?i)abcd/ +//let re = /(?i)a(bc)d/ +let re = /(?i)a[-]?c/ +let re = /(?i)(abc)\\1/ +let re = /(?i)([a-c]*)\\1/ +let re = /a(?!b)./ +let re = /a(?=d)./ +let re = /a(?=c|d)./ +let re = /a(?:b|c|d)(.)/ +let re = /a(?:b|c|d)*(.)/ +let re = /a(?:b|c|d)+?(.)/ +let re = /a(?:b|(c|e){1,2}?|d)+?(.)/ +let re = /^(.+)?B/ + +// lookbehind: split by : but not if it is escaped by -. +let re = /(?]*?b/ +// bug 490573: minimizing repeat problem +let re = /^a*?$/ +// bug 470582: nested groups problem +let re = /^((a)c)?(ab)$/ +// another minimizing repeat problem (capturing groups in assertions) +let re = /^([ab]*?)(?=(b)?)c/ +let re = /^([ab]*?)(?!(b))c/ +let re = /^([ab]*?)(? Date: Sun, 26 May 2024 09:41:18 +0200 Subject: [PATCH 5/7] test(syntax): use regex literal in test files necessary to pass syntax roundtrip test since printing has changed --- .../tests/idempotency/nook-exchange/App.res | 2 +- .../tests/idempotency/nook-exchange/Emoji.res | 2 +- .../idempotency/nook-exchange/ImportPage.res | 2 +- .../tests/idempotency/nook-exchange/Item.res | 2 +- .../idempotency/nook-exchange/ItemFilters.res | 10 +++---- .../idempotency/nook-exchange/UserStore.res | 2 +- .../QuestionsShow__QuestionEditor.res | 2 +- .../CurriculumEditor__ContentBlockCreator.res | 8 +++--- .../schools/SA_Coaches_CoachEditor.res | 2 +- .../StudentsEditor__StudentInfoForm.res | 2 +- .../pupilfirst/shared/EmailUtils.res | 5 ++-- .../idempotency/reasonml.org/common/App.res | 2 +- .../reasonml.org/components/Markdown.res | 2 +- .../idempotency/wildcards-world-ui/Helper.res | 2 +- jscomp/test/js_re_test.res | 26 +++++++++---------- jscomp/test/js_string_test.res | 22 ++++++++-------- jscomp/test/test_regex.res | 4 +-- 17 files changed, 48 insertions(+), 49 deletions(-) diff --git a/jscomp/syntax/tests/idempotency/nook-exchange/App.res b/jscomp/syntax/tests/idempotency/nook-exchange/App.res index 057b36e42d..a00808a9de 100644 --- a/jscomp/syntax/tests/idempotency/nook-exchange/App.res +++ b/jscomp/syntax/tests/idempotency/nook-exchange/App.res @@ -64,7 +64,7 @@ let make = () => { let url = ReasonReactRouter.useUrl() let (showLogin, setShowLogin) = React.useState(() => false) let itemDetails = { - let result = url.hash |> Js.Re.exec_(%re("/i(-?\d+)(:(\d+))?/g")) + let result = url.hash |> Js.Re.exec_(/i(-?\d+)(:(\d+))?/g) switch result { | Some(match_) => let captures = Js.Re.captures(match_) diff --git a/jscomp/syntax/tests/idempotency/nook-exchange/Emoji.res b/jscomp/syntax/tests/idempotency/nook-exchange/Emoji.res index a2d5bd16b6..ff139a6d29 100644 --- a/jscomp/syntax/tests/idempotency/nook-exchange/Emoji.res +++ b/jscomp/syntax/tests/idempotency/nook-exchange/Emoji.res @@ -31,7 +31,7 @@ module Styles = { let emoji = style(list{verticalAlign(#bottom), position(relative), top(px(-2))}) } -let emojiRegex = %re(`/(^|\\s)(\\:[a-zA-Z0-9-_+]+\\:)/g`) +let emojiRegex = /(^|\s)(\:[a-zA-Z0-9-_+]+\:)/g let parseText = (text: string): React.element => { let children = [] diff --git a/jscomp/syntax/tests/idempotency/nook-exchange/ImportPage.res b/jscomp/syntax/tests/idempotency/nook-exchange/ImportPage.res index ea6e735d20..87774b64f0 100644 --- a/jscomp/syntax/tests/idempotency/nook-exchange/ImportPage.res +++ b/jscomp/syntax/tests/idempotency/nook-exchange/ImportPage.res @@ -654,7 +654,7 @@ let process = value => { let resultMap = Js.Dict.empty() let missingQueries = [] rows->Array.forEach(row => { - let result = row |> Js.Re.exec_(%re("/(.*?) \[(.*?)\]$/g")) + let result = row |> Js.Re.exec_(/(.*?) \[(.*?)\]$/g) let itemWithVariant = switch result { | Some(match_) => let captures = Js.Re.captures(match_) diff --git a/jscomp/syntax/tests/idempotency/nook-exchange/Item.res b/jscomp/syntax/tests/idempotency/nook-exchange/Item.res index 8269aec378..dcf0826489 100644 --- a/jscomp/syntax/tests/idempotency/nook-exchange/Item.res +++ b/jscomp/syntax/tests/idempotency/nook-exchange/Item.res @@ -82,7 +82,7 @@ let loadTranslation: (string, Js.Json.t => unit) => unit = %raw(`function(langua exception UnexpectedType(string) -let spaceRegex = %re("/\\s/g") +let spaceRegex = /\s/g exception Unexpected let jsonToItems = (json: Js.Json.t) => { diff --git a/jscomp/syntax/tests/idempotency/nook-exchange/ItemFilters.res b/jscomp/syntax/tests/idempotency/nook-exchange/ItemFilters.res index 8ef33d100e..1261dd97b0 100644 --- a/jscomp/syntax/tests/idempotency/nook-exchange/ItemFilters.res +++ b/jscomp/syntax/tests/idempotency/nook-exchange/ItemFilters.res @@ -206,7 +206,7 @@ let doesItemMatchCategory = (~item: Item.t, ~category: string) => } let removeAccents = str => - str |> Js.String.normalizeByForm("NFD") |> Js.String.replaceByRe(%re("/[\u0300-\u036f]/g"), "") + str |> Js.String.normalizeByForm("NFD") |> Js.String.replaceByRe(/[\u0300-\u036f]/g, "") let doesItemMatchFilters = (~item: Item.t, ~filters: t) => switch filters.text { @@ -218,7 +218,7 @@ let doesItemMatchFilters = (~item: Item.t, ~filters: t) => | None => false } || { let fragments = - (textLower |> Js.String.splitByRe(%re(`/[\\s-]+/`)))->Belt.Array.keepMap(x => x) + (textLower |> Js.String.splitByRe(/[\s-]+/))->Belt.Array.keepMap(x => x) fragments->Belt.Array.every(fragment => Js.String.toLowerCase(Item.getName(item)) |> removeAccents @@ -253,8 +253,8 @@ let compareArrays = (a, b) => { let compareItemsABC = (a: Item.t, b: Item.t) => { // hack to sort "wooden-" before "wooden " - let aName = Item.getName(a) |> Js.String.replaceByRe(%re("/-/g"), " ") - let bName = Item.getName(b) |> Js.String.replaceByRe(%re("/-/g"), " ") + let aName = Item.getName(a) |> Js.String.replaceByRe(/-/g, " ") + let bName = Item.getName(b) |> Js.String.replaceByRe(/-/g, " ") int_of_float(Js.String.localeCompare(bName, aName)) } let compareItemsSellPriceDesc = (a: Item.t, b: Item.t) => @@ -798,7 +798,7 @@ let make = ( | "Escape" => let url = ReasonReactRouter.dangerouslyGetInitialUrl() // don't trigger if ItemDetailOverlay is shown - if !(url.hash |> Js.Re.test_(%re("/i(-?\d+)(:(\d+))?/g"))) { + if !(url.hash |> Js.Re.test_(/i(-?\d+)(:(\d+))?/g)) { onChange({...filters, text: ""}) } | "/" => diff --git a/jscomp/syntax/tests/idempotency/nook-exchange/UserStore.res b/jscomp/syntax/tests/idempotency/nook-exchange/UserStore.res index 20cbf8c15a..890bc931e8 100644 --- a/jscomp/syntax/tests/idempotency/nook-exchange/UserStore.res +++ b/jscomp/syntax/tests/idempotency/nook-exchange/UserStore.res @@ -477,7 +477,7 @@ let toggleCatalogCheckboxSetting = (~enabled) => { ) } -let errorQuotationMarksRegex = %re(`/^"(.*)"$/`) +let errorQuotationMarksRegex = /^"(.*)"$/ let register = (~username, ~email, ~password) => %Repromise.JsExn({ let response = Fetch.fetchWithInit( diff --git a/jscomp/syntax/tests/idempotency/pupilfirst/questions/QuestionsShow__QuestionEditor.res b/jscomp/syntax/tests/idempotency/pupilfirst/questions/QuestionsShow__QuestionEditor.res index 8efd11384f..f7929f3433 100644 --- a/jscomp/syntax/tests/idempotency/pupilfirst/questions/QuestionsShow__QuestionEditor.res +++ b/jscomp/syntax/tests/idempotency/pupilfirst/questions/QuestionsShow__QuestionEditor.res @@ -183,7 +183,7 @@ module UpdateQuestionError = { let handleResponseCB = (id, title) => { let window = Webapi.Dom.window let parameterizedTitle = - title |> Js.String.toLowerCase |> Js.String.replaceByRe(%re("/[^0-9a-zA-Z]+/gi"), "-") + title |> Js.String.toLowerCase |> Js.String.replaceByRe(/[^0-9a-zA-Z]+/gi, "-") let redirectPath = "/questions/" ++ (id ++ ("/" ++ parameterizedTitle)) redirectPath |> Webapi.Dom.Window.setLocation(window) } diff --git a/jscomp/syntax/tests/idempotency/pupilfirst/schools/CurriculumEditor__ContentBlockCreator.res b/jscomp/syntax/tests/idempotency/pupilfirst/schools/CurriculumEditor__ContentBlockCreator.res index 6e05ca24f8..c385d5cf43 100644 --- a/jscomp/syntax/tests/idempotency/pupilfirst/schools/CurriculumEditor__ContentBlockCreator.res +++ b/jscomp/syntax/tests/idempotency/pupilfirst/schools/CurriculumEditor__ContentBlockCreator.res @@ -292,10 +292,10 @@ let updateEmbedUrl = (send, event) => { } let embedUrlRegexes = [ - %re("/https:\\/\\/.*slideshare\\.net/"), - %re("/https:\\/\\/.*vimeo\\.com/"), - %re("/https:\\/\\/.*youtube\\.com/"), - %re("/https:\\/\\/.*youtu\\.be/"), + /https:\/\/.*slideshare\.net/, + /https:\/\/.*vimeo\.com/, + /https:\/\/.*youtube\.com/, + /https:\/\/.*youtu\.be/, ] let validEmbedUrl = url => Belt.Array.some(embedUrlRegexes, regex => regex->Js.Re.test_(url)) diff --git a/jscomp/syntax/tests/idempotency/pupilfirst/schools/SA_Coaches_CoachEditor.res b/jscomp/syntax/tests/idempotency/pupilfirst/schools/SA_Coaches_CoachEditor.res index 30ece3d9b5..9902b82d76 100644 --- a/jscomp/syntax/tests/idempotency/pupilfirst/schools/SA_Coaches_CoachEditor.res +++ b/jscomp/syntax/tests/idempotency/pupilfirst/schools/SA_Coaches_CoachEditor.res @@ -94,7 +94,7 @@ let updateEmail = (send, email) => send(UpdateEmail(email, email |> emailInvalid let updateTitle = (send, title) => send(UpdateTitle(title, title |> nameOrTitleInvalid)) let updateLinkedInUrl = (send, linkedinUrl) => { - let regex = %re(`/(https?)?:?(\\/\\/)?(([w]{3}||\\w\\w)\\.)?linkedin.com(\\w+:{0,1}\\w*@)?(\\S+)(:([0-9])+)?(\\/|\\/([\\w#!:.?+=&%@!\\-\\/]))?/`) + let regex = /(https?)?:?(\/\/)?(([w]{3}||\w\w)\.)?linkedin.com(\w+:{0,1}\w*@)?(\S+)(:([0-9])+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ let hasError = linkedinUrl |> String.length < 1 ? false : !Js.Re.test_(regex, linkedinUrl) send(UpdateLinkedInUrl(linkedinUrl, hasError)) } diff --git a/jscomp/syntax/tests/idempotency/pupilfirst/schools/StudentsEditor__StudentInfoForm.res b/jscomp/syntax/tests/idempotency/pupilfirst/schools/StudentsEditor__StudentInfoForm.res index 6c79582488..43ad5a4878 100644 --- a/jscomp/syntax/tests/idempotency/pupilfirst/schools/StudentsEditor__StudentInfoForm.res +++ b/jscomp/syntax/tests/idempotency/pupilfirst/schools/StudentsEditor__StudentInfoForm.res @@ -29,7 +29,7 @@ let updateName = (send, name) => { } let updateEmail = (send, email) => { - let regex = %re(`/.+@.+\\..+/i`) + let regex = /.+@.+\..+/i let hasError = !Js.Re.test_(regex, email) send(UpdateEmail(email, hasError)) } diff --git a/jscomp/syntax/tests/idempotency/pupilfirst/shared/EmailUtils.res b/jscomp/syntax/tests/idempotency/pupilfirst/shared/EmailUtils.res index 505c86ec36..bfe004c6d9 100644 --- a/jscomp/syntax/tests/idempotency/pupilfirst/shared/EmailUtils.res +++ b/jscomp/syntax/tests/idempotency/pupilfirst/shared/EmailUtils.res @@ -1,6 +1,5 @@ -let regularExpression = %re( - "/^(([^<>()\\[\\]\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\.,;:\\s@\"]+)*)|(\".+\"))@(([^<>()[\\]\\.,;:\\s@\"]+\\.)+[^<>()[\\]\\.,;:\\s@\"]{2,})$/i" -) +let regularExpression = + /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i let isInvalid = (allowBlank, email) => if email |> String.trim |> String.length > 0 { diff --git a/jscomp/syntax/tests/idempotency/reasonml.org/common/App.res b/jscomp/syntax/tests/idempotency/reasonml.org/common/App.res index aad0b27404..c035c8524e 100644 --- a/jscomp/syntax/tests/idempotency/reasonml.org/common/App.res +++ b/jscomp/syntax/tests/idempotency/reasonml.org/common/App.res @@ -79,7 +79,7 @@ module Url = { } let isVersion = str => - Js.String2.match_(str, %re("/latest|v\\d+(\\.\\d+)?(\\.\\d+)?/"))->Belt.Option.isSome + Js.String2.match_(str, /latest|v\d+(\.\d+)?(\.\d+)?/)->Belt.Option.isSome let parse = (route: string): t => { let fullpath = { diff --git a/jscomp/syntax/tests/idempotency/reasonml.org/components/Markdown.res b/jscomp/syntax/tests/idempotency/reasonml.org/components/Markdown.res index 425a4fcf59..57f25c1f12 100644 --- a/jscomp/syntax/tests/idempotency/reasonml.org/components/Markdown.res +++ b/jscomp/syntax/tests/idempotency/reasonml.org/components/Markdown.res @@ -311,7 +311,7 @@ module A = { // Ideally one would check if this link is relative first, // but it's very unlikely we'd refer to an absolute URL ending // with .md - let regex = %re("/\\.md(x)?|\\.html$/") + let regex = /\.md(x)?|\.html$/ let href = switch Js.String2.split(href, "#") { | [pathname, anchor] => Js.String2.replaceByRe(pathname, regex, "") ++ ("#" ++ anchor) | [pathname] => Js.String2.replaceByRe(pathname, regex, "") diff --git a/jscomp/syntax/tests/idempotency/wildcards-world-ui/Helper.res b/jscomp/syntax/tests/idempotency/wildcards-world-ui/Helper.res index be8a97b9d7..08ac620ada 100644 --- a/jscomp/syntax/tests/idempotency/wildcards-world-ui/Helper.res +++ b/jscomp/syntax/tests/idempotency/wildcards-world-ui/Helper.res @@ -3,7 +3,7 @@ let isPositiveStringInteger = str => { // NOTE: This allows leading 0s (which seams to not be a problem for web3 or truffle) // This doesn't check if the number is smaller than 2^256 which is the largest integer ethereum can handle - let f = %re("/^([0-9]\d*)$/") + let f = /^([0-9]\d*)$/ Js.Re.test_(f, str) } diff --git a/jscomp/test/js_re_test.res b/jscomp/test/js_re_test.res index 851ec7404b..ca800bfd97 100644 --- a/jscomp/test/js_re_test.res +++ b/jscomp/test/js_re_test.res @@ -4,7 +4,7 @@ let suites = { ( "captures", _ => { - let re = %re("/(\d+)-(?:(\d+))?/g") + let re = /(\d+)-(?:(\d+))?/g let str = "3-" switch re->Js.Re.exec_(str) { | Some(result) => @@ -35,7 +35,7 @@ let suites = { ( "exec_literal", _ => - switch %re("/[^.]+/")->Js.Re.exec_("http://xxx.domain.com") { + switch /[^.]+/->Js.Re.exec_("http://xxx.domain.com") { | Some(res) => Eq(Js.Nullable.return("http://xxx"), Js.Re.captures(res)[0]) | None => FailWith("regex should match") }, @@ -43,7 +43,7 @@ let suites = { ( "exec_no_match", _ => - switch %re("/https:\/\/(.*)/")->Js.Re.exec_("http://xxx.domain.com") { + switch /https:\/\/(.*)/->Js.Re.exec_("http://xxx.domain.com") { | Some(_) => FailWith("regex should not match") | None => Ok(true) }, @@ -77,20 +77,20 @@ let suites = { _ => { let input = "foobar" - switch %re("/foo/g")->Js.Re.exec_(input) { + switch /foo/g->Js.Re.exec_(input) { | Some(res) => Eq(input, res |> Js.Re.input) | None => Fail() } }, ), /* es2015 */ - ("t_flags", _ => Eq("gi", %re("/./ig")->Js.Re.flags)), - ("t_global", _ => Eq(true, %re("/./ig")->Js.Re.global)), - ("t_ignoreCase", _ => Eq(true, %re("/./ig")->Js.Re.ignoreCase)), + ("t_flags", _ => Eq("gi", /./ig->Js.Re.flags)), + ("t_global", _ => Eq(true, /./ig->Js.Re.global)), + ("t_ignoreCase", _ => Eq(true, /./ig->Js.Re.ignoreCase)), ( "t_lastIndex", _ => { - let re = %re("/na/g") + let re = /na/g let _ = re->Js.Re.exec_( "banana", @@ -101,7 +101,7 @@ let suites = { ( "t_setLastIndex", _ => { - let re = %re("/na/g") + let re = /na/g let before = Js.Re.lastIndex(re) let () = Js.Re.setLastIndex(re, 42) @@ -110,11 +110,11 @@ let suites = { Eq((0, 42), (before, after)) }, ), - ("t_multiline", _ => Eq(false, %re("/./ig")->Js.Re.multiline)), - ("t_source", _ => Eq("f.+o", %re("/f.+o/ig")->Js.Re.source)), + ("t_multiline", _ => Eq(false, /./ig->Js.Re.multiline)), + ("t_source", _ => Eq("f.+o", /f.+o/ig->Js.Re.source)), /* es2015 */ - ("t_sticky", _ => Eq(true, %re("/./yg")->Js.Re.sticky)), - ("t_unicode", _ => Eq(false, %re("/./yg")->Js.Re.unicode)), + ("t_sticky", _ => Eq(true, /./yg->Js.Re.sticky)), + ("t_unicode", _ => Eq(false, /./yg->Js.Re.unicode)), } } diff --git a/jscomp/test/js_string_test.res b/jscomp/test/js_string_test.res index f1ae84d6d8..4c55d469ef 100644 --- a/jscomp/test/js_string_test.res +++ b/jscomp/test/js_string_test.res @@ -27,13 +27,13 @@ let suites = { ("lastIndexOf", _ => Eq(3, "foobarbaz"->Js.String2.lastIndexOf("bar"))), ("lastIndexOfFrom", _ => Eq(3, "foobarbaz"->Js.String2.lastIndexOfFrom("bar", 4))), ("localeCompare", _ => Eq(0., "foo"->Js.String2.localeCompare("foo"))), - ("match", _ => Eq(Some([Some("na"), Some("na")]), "banana"->Js.String2.match_(%re("/na+/g")))), - ("match - no match", _ => Eq(None, "banana"->Js.String2.match_(%re("/nanana+/g")))), + ("match", _ => Eq(Some([Some("na"), Some("na")]), "banana"->Js.String2.match_(/na+/g))), + ("match - no match", _ => Eq(None, "banana"->Js.String2.match_(/nanana+/g))), ( "match - not found capture groups", _ => Eq( Some([Some("hello "), None]), - "hello word"->Js.String2.match_(%re("/hello (world)?/"))->Belt.Option.map(Js.Array.copy), + "hello word"->Js.String2.match_(/hello (world)?/)->Belt.Option.map(Js.Array.copy), ), ), /* es2015 */ @@ -44,7 +44,7 @@ let suites = { ("replace", _ => Eq("fooBORKbaz", "foobarbaz"->Js.String2.replace("bar", "BORK"))), ( "replaceByRe", - _ => Eq("fooBORKBORK", "foobarbaz"->Js.String2.replaceByRe(%re("/ba./g"), "BORK")), + _ => Eq("fooBORKBORK", "foobarbaz"->Js.String2.replaceByRe(/ba./g, "BORK")), ), ( "unsafeReplaceBy0", @@ -56,7 +56,7 @@ let suites = { "DORK" } - Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy0(%re("/ba./g"), replace)) + Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy0(/ba./g, replace)) }, ), ( @@ -69,7 +69,7 @@ let suites = { "DORK" } - Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy1(%re("/ba./g"), replace)) + Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy1(/ba./g, replace)) }, ), ( @@ -82,7 +82,7 @@ let suites = { "DORK" } - Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy2(%re("/ba./g"), replace)) + Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy2(/ba./g, replace)) }, ), ( @@ -95,10 +95,10 @@ let suites = { "DORK" } - Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy3(%re("/ba./g"), replace)) + Eq("fooBORKDORK", "foobarbaz"->Js.String2.unsafeReplaceBy3(/ba./g, replace)) }, ), - ("search", _ => Eq(3, "foobarbaz"->Js.String2.search(%re("/ba./g")))), + ("search", _ => Eq(3, "foobarbaz"->Js.String2.search(/ba./g))), ("slice", _ => Eq("bar", "foobarbaz"->Js.String2.slice(~from=3, ~to_=6))), ("sliceToEnd", _ => Eq("barbaz", "foobarbaz"->Js.String2.sliceToEnd(~from=3))), ("split", _ => Eq(["foo", "bar", "baz"], "foo bar baz"->Js.String2.split(" "))), @@ -107,14 +107,14 @@ let suites = { "splitByRe", _ => Eq( [Some("a"), Some("#"), None, Some("b"), Some("#"), Some(":"), Some("c")], - "a#b#:c" |> Js.String.splitByRe(%re("/(#)(:)?/")), + "a#b#:c" |> Js.String.splitByRe(/(#)(:)?/), ), ), ( "splitByReAtMost", _ => Eq( [Some("a"), Some("#"), None], - "a#b#:c" |> Js.String.splitByReAtMost(%re("/(#)(:)?/"), ~limit=3), + "a#b#:c" |> Js.String.splitByReAtMost(/(#)(:)?/, ~limit=3), ), ), /* es2015 */ diff --git a/jscomp/test/test_regex.res b/jscomp/test/test_regex.res index 778ba14e9e..c33b9f4148 100644 --- a/jscomp/test/test_regex.res +++ b/jscomp/test/test_regex.res @@ -1,5 +1,5 @@ -let v = %re("/b/ig") -let r = %re("/Bucklescript是一个程序语言/") +let v = /b/ig +let r = /Bucklescript是一个程序语言/ /* Js.log(v);; Js.log(r);; */ From 1051f470a0486dcf40b867cf372cb042b79885b4 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 26 May 2024 09:44:41 +0200 Subject: [PATCH 6/7] refactor(others/js): use regex literals --- jscomp/others/js_re.res | 6 +++--- jscomp/others/js_string.res | 22 +++++++++++----------- jscomp/others/js_string2.res | 30 +++++++++++++++--------------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/jscomp/others/js_re.res b/jscomp/others/js_re.res index 5ba7b6038c..4f10383bce 100644 --- a/jscomp/others/js_re.res +++ b/jscomp/others/js_re.res @@ -55,7 +55,7 @@ external input: result => string = "input" /** Constructs a RegExp object (Js.Re.t) from a `string`. -Regex literals `%re("/.../")` should generally be preferred, but `fromString` +Regex literals `/.../` should generally be preferred, but `fromString` is useful when you need to dynamically construct a regex using strings, exactly like when you do so in JavaScript. @@ -112,7 +112,7 @@ set. ## Examples ```rescript -let re = %re("/ab*TODO/g") +let re = /ab*TODO/g let str = "abbcdefabh" let break = ref(false) @@ -166,7 +166,7 @@ Returns `Some(Js.Re.result)` if a match is found, `None` otherwise. * Ignore case */ -let re = %re("/quick\s(brown).+?(jumps)/ig") +let re = /quick\s(brown).+?(jumps)/ig let result = Js.Re.exec_(re, "The Quick Brown Fox Jumps Over The Lazy Dog") ``` diff --git a/jscomp/others/js_string.res b/jscomp/others/js_string.res index 938c962d55..c3869974bf 100644 --- a/jscomp/others/js_string.res +++ b/jscomp/others/js_string.res @@ -428,11 +428,11 @@ on MDN. ## Examples ```rescript -Js.String.match_(%re("/b[aeiou]t/"), "The better bats") == Some(["bet"]) -Js.String.match_(%re("/b[aeiou]t/g"), "The better bats") == Some(["bet", "bat"]) -Js.String.match_(%re("/(\d+)-(\d+)-(\d+)/"), "Today is 2018-04-05.") == +Js.String.match_(/b[aeiou]t/, "The better bats") == Some(["bet"]) +Js.String.match_(/b[aeiou]t/g, "The better bats") == Some(["bet", "bat"]) +Js.String.match_(/(\d+)-(\d+)-(\d+)/, "Today is 2018-04-05.") == Some(["2018-04-05", "2018", "04", "05"]) -Js.String.match_(%re("/b[aeiou]g/"), "The large container.") == None +Js.String.match_(/b[aeiou]g/, "The large container.") == None ``` */ external match_: Js_re.t => option>> = "match" @@ -514,8 +514,8 @@ on MDN. ## Examples ```rescript -Js.String.replaceByRe(%re("/[aeiou]/g"), "x", "vowels be gone") == "vxwxls bx gxnx" -Js.String.replaceByRe(%re("/(\w+) (\w+)/"), "$2, $1", "Juan Fulano") == "Fulano, Juan" +Js.String.replaceByRe(/[aeiou]/g, "x", "vowels be gone") == "vxwxls bx gxnx" +Js.String.replaceByRe(/(\w+) (\w+)/, "$2, $1", "Juan Fulano") == "Fulano, Juan" ``` */ external replaceByRe: (Js_re.t, t) => t = "replace" @@ -534,7 +534,7 @@ on MDN. ```rescript let str = "beautiful vowels" -let re = %re("/[aeiou]/g") +let re = /[aeiou]/g let matchFn = (matchPart, _offset, _wholeString) => Js.String.toUpperCase(matchPart) Js.String.unsafeReplaceBy0(re, matchFn, str) == "bEAUtIfUl vOwEls" @@ -557,7 +557,7 @@ on MDN. ```rescript let str = "Jony is 40" -let re = %re("/(Jony is )\d+/g") +let re = /(Jony is )\d+/g let matchFn = (_match, part1, _offset, _wholeString) => { part1 ++ "41" } @@ -582,7 +582,7 @@ on MDN. ```rescript let str = "7 times 6" -let re = %re("/(\d+) times (\d+)/") +let re = /(\d+) times (\d+)/ let matchFn = (_match, p1, p2, _offset, _wholeString) => { switch (Belt.Int.fromString(p1), Belt.Int.fromString(p2)) { | (Some(x), Some(y)) => Belt.Int.toString(x * y) @@ -619,8 +619,8 @@ on MDN. ## Examples ```rescript -Js.String.search(%re("/\d+/"), "testing 1 2 3") == 8 -Js.String.search(%re("/\d+/"), "no numbers") == -1 +Js.String.search(/\d+/, "testing 1 2 3") == 8 +Js.String.search(/\d+/, "no numbers") == -1 ``` */ external search: Js_re.t => int = "search" diff --git a/jscomp/others/js_string2.res b/jscomp/others/js_string2.res index 7dd51fd285..d77f681fa5 100644 --- a/jscomp/others/js_string2.res +++ b/jscomp/others/js_string2.res @@ -432,11 +432,11 @@ on MDN. ## Examples ```rescript -Js.String2.match_("The better bats", %re("/b[aeiou]t/")) == Some(["bet"]) -Js.String2.match_("The better bats", %re("/b[aeiou]t/g")) == Some(["bet", "bat"]) -Js.String2.match_("Today is 2018-04-05.", %re("/(\d+)-(\d+)-(\d+)/")) == +Js.String2.match_("The better bats", /b[aeiou]t/) == Some(["bet"]) +Js.String2.match_("The better bats", /b[aeiou]t/g) == Some(["bet", "bat"]) +Js.String2.match_("Today is 2018-04-05.", /(\d+)-(\d+)-(\d+)/) == Some(["2018-04-05", "2018", "04", "05"]) -Js.String2.match_("The large container.", %re("/b[aeiou]g/")) == None +Js.String2.match_("The large container.", /b[aeiou]g/) == None ``` */ external match_: (t, Js_re.t) => option>> = "match" @@ -516,8 +516,8 @@ on MDN. ## Examples ```rescript -Js.String2.replaceByRe("vowels be gone", %re("/[aeiou]/g"), "x") == "vxwxls bx gxnx" -Js.String2.replaceByRe("Juan Fulano", %re("/(\w+) (\w+)/"), "$2, $1") == "Fulano, Juan" +Js.String2.replaceByRe("vowels be gone", /[aeiou]/g, "x") == "vxwxls bx gxnx" +Js.String2.replaceByRe("Juan Fulano", /(\w+) (\w+)/, "$2, $1") == "Fulano, Juan" ``` */ external replaceByRe: (t, Js_re.t, t) => t = "replace" @@ -536,7 +536,7 @@ on MDN. ```rescript let str = "beautiful vowels" -let re = %re("/[aeiou]/g") +let re = /[aeiou]/g let matchFn = (matchPart, _offset, _wholeString) => Js.String2.toUpperCase(matchPart) Js.String2.unsafeReplaceBy0(str, re, matchFn) == "bEAUtIfUl vOwEls" @@ -559,7 +559,7 @@ on MDN. ```rescript let str = "Jony is 40" -let re = %re("/(Jony is )\d+/g") +let re = /(Jony is )\d+/g let matchFn = (_match, part1, _offset, _wholeString) => { part1 ++ "41" } @@ -584,7 +584,7 @@ on MDN. ```rescript let str = "7 times 6" -let re = %re("/(\d+) times (\d+)/") +let re = /(\d+) times (\d+)/ let matchFn = (_match, p1, p2, _offset, _wholeString) => { switch (Belt.Int.fromString(p1), Belt.Int.fromString(p2)) { | (Some(x), Some(y)) => Belt.Int.toString(x * y) @@ -621,8 +621,8 @@ on MDN. ## Examples ```rescript -Js.String2.search("testing 1 2 3", %re("/\d+/")) == 8 -Js.String2.search("no numbers", %re("/\d+/")) == -1 +Js.String2.search("testing 1 2 3", /\d+/) == 8 +Js.String2.search("no numbers", /\d+/) == -1 ``` */ external search: (t, Js_re.t) => int = "search" @@ -709,7 +709,7 @@ on MDN. ## Examples ```rescript -Js.String2.splitByRe("art; bed , cog ;dad", %re("/\s*[,;]\s*TODO/")) == [ +Js.String2.splitByRe("art; bed , cog ;dad", /\s*[,;]\s*TODO/) == [ Some("art"), Some("bed"), Some("cog"), @@ -732,15 +732,15 @@ on MDN. ## Examples ```rescript -Js.String2.splitByReAtMost("one: two: three: four", %re("/\s*:\s*TODO/"), ~limit=3) == [ +Js.String2.splitByReAtMost("one: two: three: four", /\s*:\s*TODO/, ~limit=3) == [ Some("one"), Some("two"), Some("three"), ] -Js.String2.splitByReAtMost("one: two: three: four", %re("/\s*:\s*TODO/"), ~limit=0) == [] +Js.String2.splitByReAtMost("one: two: three: four", /\s*:\s*TODO/, ~limit=0) == [] -Js.String2.splitByReAtMost("one: two: three: four", %re("/\s*:\s*TODO/"), ~limit=8) == [ +Js.String2.splitByReAtMost("one: two: three: four", /\s*:\s*TODO/, ~limit=8) == [ Some("one"), Some("two"), Some("three"), From f8dd922110b1bd5704d98e5c199b97b048061b0a Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 7 Jul 2024 16:25:47 +0200 Subject: [PATCH 7/7] docs: add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcdd4da73a..937cc8e87a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Throws an instance of JavaScript's `new Error()` and adds the extension payload for `cause` option. https://github.com/rescript-lang/rescript-compiler/pull/6611 - Allow free vars in types for type coercion `e :> t`. https://github.com/rescript-lang/rescript-compiler/pull/6828 - Allow `private` in with constraints. https://github.com/rescript-lang/rescript-compiler/pull/6843 +- Add regex literals as syntax sugar for `@bs.re`. https://github.com/rescript-lang/rescript-compiler/pull/6776 #### :boom: Breaking Change