diff options
author | Karl Berry <karl@freefriends.org> | 2012-02-28 00:40:17 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2012-02-28 00:40:17 +0000 |
commit | ed49b3dfe19b91f9fd96ab70fe95dcda8fba24c8 (patch) | |
tree | 0eb59527efd68f813d629e7d0977fe31d8d6419f /Master/texmf-dist/tex/latex/l3experimental | |
parent | b1436d6ee293a02df32a18832d21c54348335565 (diff) |
l3experimental 3471 (26feb12)
git-svn-id: svn://tug.org/texlive/trunk@25523 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/l3experimental')
8 files changed, 4892 insertions, 1799 deletions
diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3dt/l3dt.sty b/Master/texmf-dist/tex/latex/l3experimental/l3dt/l3dt.sty index 5346944521c..99bd83e7764 100644 --- a/Master/texmf-dist/tex/latex/l3experimental/l3dt/l3dt.sty +++ b/Master/texmf-dist/tex/latex/l3experimental/l3dt/l3dt.sty @@ -47,7 +47,7 @@ %% ----------------------------------------------------------------------- %% \RequirePackage{expl3} -\GetIdInfo$Id: l3dt.dtx 3251 2012-01-28 09:42:44Z joseph $ +\GetIdInfo$Id: l3dt.dtx 3459 2012-02-26 08:58:53Z joseph $ {L3 Experimental data tables} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3sort/l3sort.sty b/Master/texmf-dist/tex/latex/l3experimental/l3sort/l3sort.sty index 4de96fa88a3..b24bacd3794 100644 --- a/Master/texmf-dist/tex/latex/l3experimental/l3sort/l3sort.sty +++ b/Master/texmf-dist/tex/latex/l3experimental/l3sort/l3sort.sty @@ -47,7 +47,7 @@ %% ----------------------------------------------------------------------- %% \RequirePackage{expl3} -\GetIdInfo$Id: l3sort.dtx 3295 2012-02-02 09:30:14Z joseph $ +\GetIdInfo$Id: l3sort.dtx 3467 2012-02-26 15:39:35Z bruno $ {L3 Experimental sorting functions} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty new file mode 100644 index 00000000000..60abf42cd5d --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty @@ -0,0 +1,2824 @@ +%% +%% This is file `l3regex-trace.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3regex.dtx (with options: `package,trace') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3regex.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3experimental bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{expl3} +\GetIdInfo$Id: l3regex.dtx 3463 2012-02-26 15:05:14Z bruno $ + {L3 Experimental Regular Expressions} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\RequirePackage{l3tl-build, l3tl-analysis, l3flag, l3str} +\cs_generate_variant:Nn \tl_to_str:n { V } +\cs_new:Npn \regex_tmp:w { } +\tl_new:N \l_regex_internal_a_tl +\tl_new:N \l_regex_internal_b_tl +\int_new:N \l_regex_internal_a_int +\int_new:N \l_regex_internal_b_int +\int_new:N \l_regex_internal_c_int +\bool_new:N \l_regex_internal_bool +\seq_new:N \l_regex_internal_seq +\tl_new:N \g_regex_internal_tl +\tl_const:Nn \c_regex_no_match_regex + { + \regex_branch:n + { \regex_class:NnnnN \c_true_bool { } { 1 } { 0 } \c_true_bool } + } +\int_new:N \l_regex_balance_int +\cs_new_protected:Npn \regex_break_true:w + #1 \regex_break_point:TF #2 #3 {#2} +\cs_new_protected:Npn \regex_break_point:TF #1 #2 { #2 } +\cs_new_protected:Npn \regex_item_reverse:n #1 + { + #1 + \regex_break_point:TF { } \regex_break_true:w + } +\cs_new_protected:Npn \regex_item_caseful_equal:n #1 + { + \if_num:w #1 = \l_regex_current_char_int + \exp_after:wN \regex_break_true:w + \fi: + } +\cs_new_protected:Npn \regex_item_caseful_range:nn #1 #2 + { + \reverse_if:N \if_num:w #1 > \l_regex_current_char_int + \reverse_if:N \if_num:w #2 < \l_regex_current_char_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w + \fi: + \fi: + } +\cs_new_protected:Npn \regex_item_caseless_equal:n #1 + { + \if_num:w #1 = \l_regex_current_char_int + \exp_after:wN \regex_break_true:w + \fi: + \if_num:w \l_regex_case_changed_char_int = \c_max_int + \regex_compute_case_changed_char: + \fi: + \if_num:w #1 = \l_regex_case_changed_char_int + \exp_after:wN \regex_break_true:w + \fi: + } +\cs_new_protected:Npn \regex_item_caseless_range:nn #1 #2 + { + \reverse_if:N \if_num:w #1 > \l_regex_current_char_int + \reverse_if:N \if_num:w #2 < \l_regex_current_char_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w + \fi: + \fi: + \if_num:w \l_regex_case_changed_char_int = \c_max_int + \regex_compute_case_changed_char: + \fi: + \reverse_if:N \if_num:w #1 > \l_regex_case_changed_char_int + \reverse_if:N \if_num:w #2 < \l_regex_case_changed_char_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \regex_compute_case_changed_char: + { + \int_set_eq:NN \l_regex_case_changed_char_int \l_regex_current_char_int + \if_num:w \l_regex_current_char_int < \c_ninety_one + \if_num:w \l_regex_current_char_int < \c_sixty_five + \else: + \int_add:Nn \l_regex_case_changed_char_int { \c_thirty_two } + \fi: + \else: + \if_num:w \l_regex_current_char_int < \c_one_hundred_twenty_three + \if_num:w \l_regex_current_char_int < \c_ninety_seven + \else: + \int_sub:Nn \l_regex_case_changed_char_int { \c_thirty_two } + \fi: + \fi: + \fi: + } +\cs_new_eq:NN \regex_item_equal:n ? +\cs_new_eq:NN \regex_item_range:nn ? +\cs_new_protected:Npn \regex_item_catcode_aux: + { + " + \if_case:w \l_regex_current_catcode_int + 1 \or: 4 \or: 10 \or: 40 + \or: 100 \or: \or: 1000 \or: 4000 + \or: 10000 \or: \or: 100000 \or: 400000 + \or: 1000000 \or: 4000000 \else: 1*\c_zero + \fi: + } +\cs_new_protected:Npn \regex_item_catcode:nT #1 + { + \if_int_odd:w \int_eval:w #1 / \regex_item_catcode_aux: \int_eval_end: + \exp_after:wN \use:n + \else: + \exp_after:wN \use_none:n + \fi: + } +\cs_new_protected:Npn \regex_item_catcode_reverse:nT #1#2 + { \regex_item_catcode:nT {#1} { \regex_item_reverse:n {#2} } } +\cs_new_protected:Npn \regex_item_exact:nn #1#2 + { + \if_num:w #1 = \l_regex_current_catcode_int + \if_num:w #2 = \l_regex_current_char_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w + \fi: + \fi: + } +\cs_new_protected:Npn \regex_item_exact_cs:c #1 + { + \int_compare:nNnTF \l_regex_current_catcode_int = \c_zero + { + \str_if_eq:xxTF + { + \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N + \tex_the:D \tex_toks:D \l_regex_current_pos_int + } + { #1 } + { \regex_break_true:w } { } + } + { } + } +\cs_new_protected:Npn \regex_item_cs:n #1 + { + \int_compare:nNnT \l_regex_current_catcode_int = \c_zero + { + \group_begin: + \regex_single_match: + \regex_disable_submatches: + \regex_build_for_cs:n {#1} + \bool_set_eq:NN \l_regex_saved_success_bool \g_regex_success_bool + \exp_args:Nx \regex_match:n + { + \exp_after:wN \exp_after:wN + \exp_after:wN \cs_to_str:N + \tex_the:D \tex_toks:D \l_regex_current_pos_int + } + \if_meaning:w \c_true_bool \g_regex_success_bool + \group_insert_after:N \regex_break_true:w + \fi: + \bool_gset_eq:NN \g_regex_success_bool \l_regex_saved_success_bool + \group_end: + } + } +\cs_new_protected_nopar:Npn \regex_prop_d: + { \regex_item_caseful_range:nn \c_forty_eight { 57 } } % 0--9 +\cs_new_protected_nopar:Npn \regex_prop_h: + { + \regex_item_caseful_equal:n \c_thirty_two % space + \regex_item_caseful_equal:n \c_nine % tab + } +\cs_new_protected_nopar:Npn \regex_prop_s: + { + \regex_item_caseful_equal:n \c_thirty_two % space + \regex_item_caseful_equal:n \c_nine % tab + \regex_item_caseful_equal:n \c_ten % lf + \regex_item_caseful_equal:n \c_twelve % ff + \regex_item_caseful_equal:n \c_thirteen % cr + } +\cs_new_protected_nopar:Npn \regex_prop_v: + { \regex_item_caseful_range:nn \c_ten \c_thirteen } % lf, vtab, ff, cr +\cs_new_protected_nopar:Npn \regex_prop_w: + { + \regex_item_caseful_range:nn \c_ninety_seven { 122 } % a--z + \regex_item_caseful_range:nn \c_sixty_five { 90 } % A--Z + \regex_item_caseful_range:nn \c_forty_eight { 57 } % 0--9 + \regex_item_caseful_equal:n { 95 } % _ + } +\cs_new_protected_nopar:Npn \regex_prop_N: + { \regex_item_reverse:n { \regex_item_caseful_equal:n \c_ten } } +\cs_new_protected_nopar:Npn \regex_posix_alnum: + { \regex_posix_alpha: \regex_posix_digit: } +\cs_new_protected_nopar:Npn \regex_posix_alpha: + { \regex_posix_lower: \regex_posix_upper: } +\cs_new_protected_nopar:Npn \regex_posix_ascii: + { \regex_item_caseful_range:nn \c_zero \c_one_hundred_twenty_seven } +\cs_new_eq:NN \regex_posix_blank: \regex_prop_h: +\cs_new_protected_nopar:Npn \regex_posix_cntrl: + { + \regex_item_caseful_range:nn \c_zero { 31 } + \regex_item_caseful_equal:n \c_one_hundred_twenty_seven + } +\cs_new_eq:NN \regex_posix_digit: \regex_prop_d: +\cs_new_protected_nopar:Npn \regex_posix_graph: + { \regex_item_caseful_range:nn { 33 } { 126 } } +\cs_new_protected_nopar:Npn \regex_posix_lower: + { \regex_item_caseful_range:nn \c_ninety_seven { 122 } } +\cs_new_protected_nopar:Npn \regex_posix_print: + { \regex_item_caseful_range:nn \c_thirty_two { 126 } } +\cs_new_protected_nopar:Npn \regex_posix_punct: + { + \regex_item_caseful_range:nn { 33 } { 47 } + \regex_item_caseful_range:nn { 58 } { 64 } + \regex_item_caseful_range:nn { 91 } { 96 } + \regex_item_caseful_range:nn { 123 } { 126 } + } +\cs_new_protected_nopar:Npn \regex_posix_space: + { + \regex_item_caseful_equal:n \c_thirty_two + \regex_item_caseful_range:nn \c_nine \c_thirteen + } +\cs_new_protected_nopar:Npn \regex_posix_upper: + { \regex_item_caseful_range:nn \c_sixty_five { 90 } } +\cs_new_eq:NN \regex_posix_word: \regex_prop_w: +\cs_new_protected_nopar:Npn \regex_posix_xdigit: + { + \regex_posix_digit: + \regex_item_caseful_range:nn \c_sixty_five { 70 } + \regex_item_caseful_range:nn \c_ninety_seven { 102 } + } +\cs_new_protected:Npn \regex_escape_use:nnnn #1#2#3#4 + { + \trace_push:nnn { regex } { 1 } { regex_escape_use:nnnn } + \tl_set_build:Nw \l_regex_internal_a_tl + \cs_set_nopar:Npn \regex_escape_unescaped:N ##1 { #1 } + \cs_set_nopar:Npn \regex_escape_escaped:N ##1 { #2 } + \cs_set_nopar:Npn \regex_escape_raw:N ##1 { #3 } + \int_set:Nn \tex_escapechar:D { 92 } + \str_gset_other:Nn \g_regex_internal_tl { #4 } + \tl_set:Nx \l_regex_internal_b_tl + { + \exp_after:wN \regex_escape_loop:N \g_regex_internal_tl + { break } \prg_break_point:n { } + } + \tl_build_one:o \l_regex_internal_b_tl + \tl_build_end: + \trace_pop:nnn { regex } { 1 } { regex_escape_use:nnnn } + \l_regex_internal_a_tl + } +\cs_new:Npn \regex_escape_loop:N #1 + { + \cs_if_exist_use:cF { regex_escape_\token_to_str:N #1:w } + { \regex_escape_unescaped:N #1 } + \regex_escape_loop:N + } +\cs_new_nopar:cpn { regex_escape_ \c_backslash_str :w } + \regex_escape_loop:N #1 + { + \cs_if_exist_use:cF { regex_escape_/\token_to_str:N #1:w } + { \regex_escape_escaped:N #1 } + \regex_escape_loop:N + } +\cs_new_eq:NN \regex_escape_unescaped:N ? +\cs_new_eq:NN \regex_escape_escaped:N ? +\cs_new_eq:NN \regex_escape_raw:N ? +\cs_new_eq:NN \regex_escape_break:w \prg_map_break: +\cs_new_nopar:cpn { regex_escape_/break:w } + { + \if_false: { \fi: } + \msg_kernel_error:nn { regex } { trailing-backslash } + \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: + } +\cs_new_nopar:cpn { regex_escape_~:w } { } +\cs_new_nopar:cpx { regex_escape_/a:w } + { \exp_not:N \regex_escape_raw:N \iow_char:N \^^G } +\cs_new_nopar:cpx { regex_escape_/t:w } + { \exp_not:N \regex_escape_raw:N \iow_char:N \^^I } +\cs_new_nopar:cpx { regex_escape_/n:w } + { \exp_not:N \regex_escape_raw:N \iow_char:N \^^J } +\cs_new_nopar:cpx { regex_escape_/f:w } + { \exp_not:N \regex_escape_raw:N \iow_char:N \^^L } +\cs_new_nopar:cpx { regex_escape_/r:w } + { \exp_not:N \regex_escape_raw:N \iow_char:N \^^M } +\cs_new_nopar:cpx { regex_escape_/e:w } + { \exp_not:N \regex_escape_raw:N \iow_char:N \^^[ } +\cs_new:cpn { regex_escape_/x:w } \regex_escape_loop:N + { + \exp_after:wN \regex_escape_x_end:w + \int_value:w "0 \regex_escape_x_test:N + } +\cs_new:Npn \regex_escape_x_end:w #1 ; + { + \int_compare:nNnTF {#1} < \c_two_hundred_fifty_six + { + \exp_last_unbraced:Nf \regex_escape_raw:N + { \str_output_byte:n {#1} } + } + { \regex_escape_x_large:n {#1} } + } +\group_begin: + \char_set_catcode_other:n { 0 } + \cs_new:Npn \regex_escape_x_large:n #1 + { + \if_false: { \fi: } + \tl_build_one:o \l_regex_internal_b_tl + \int_compare:nNnTF {#1} > \c_max_char_int + { + \msg_kernel_error:nnx { regex } { x-overflow } {#1} + \tl_set:Nx \l_regex_internal_b_tl + { \if_false: } \fi: \regex_escape_loop:N + } + { + \char_set_lccode:nn { \c_zero } {#1} + \tl_to_lowercase:n + { + \tl_set:Nx \l_regex_internal_b_tl + { \if_false: } \fi: + \regex_escape_raw:N ^^@ + \regex_escape_loop:N + } + } + } +\group_end: +\cs_new:Npn \regex_escape_x_test:N #1 + { + \str_if_eq:xxTF {#1} { break } { ; } + { + \if_charcode:w \c_space_token #1 + \exp_after:wN \regex_escape_x_test:N + \else: + \exp_after:wN \regex_escape_x_test_ii:N + \exp_after:wN #1 + \fi: + } + } +\cs_new:Npn \regex_escape_x_test_ii:N #1 + { + \if_charcode:w \c_lbrace_str #1 + \exp_after:wN \regex_escape_x_loop:N + \else: + \str_aux_hexadecimal_use:NTF #1 + { \exp_after:wN \regex_escape_x_ii:N } + { ; \exp_after:wN \regex_escape_loop:N \exp_after:wN #1 } + \fi: + } +\cs_new:Npn \regex_escape_x_ii:N #1 + { + \str_if_eq:xxTF {#1} { break } { ; } + { + \str_aux_hexadecimal_use:NTF #1 + { ; \regex_escape_loop:N } + { ; \regex_escape_loop:N #1 } + } + } +\cs_new:Npn \regex_escape_x_loop:N #1 + { + \str_aux_hexadecimal_use:NTF #1 + { \regex_escape_x_loop:N } + { + \token_if_eq_charcode:NNTF \c_space_token #1 + { \regex_escape_x_loop:N } + { + ; + \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #1 + { \regex_escape_loop:N } + { + \if_false: { \fi: } + \tl_build_one:o \l_regex_internal_b_tl + \msg_kernel_error:nn { regex } { x-missing-rbrace } {#1} + \tl_set:Nx \l_regex_internal_b_tl + { \if_false: } \fi: \regex_escape_loop:N #1 + } + } + } + } +\prg_new_conditional:Npnn \regex_char_if_special:N #1 { TF } + { + \if_num:w `#1 < \c_ninety_one + \if_num:w `#1 < \c_fifty_eight + \if_num:w `#1 < \c_forty_eight + \if_num:w `#1 < \c_thirty_two + \prg_return_false: \else: \prg_return_true: \fi: + \else: \prg_return_false: \fi: + \else: + \if_num:w `#1 < \c_sixty_five + \prg_return_true: \else: \prg_return_false: \fi: + \fi: + \else: + \if_num:w `#1 < \c_one_hundred_twenty_three + \if_num:w `#1 < \c_ninety_seven + \prg_return_true: \else: \prg_return_false: \fi: + \else: + \if_num:w `#1 < \c_one_hundred_twenty_seven + \prg_return_true: \else: \prg_return_false: \fi: + \fi: + \fi: + } +\prg_new_conditional:Npnn \regex_char_if_alphanumeric:N #1 { TF } + { + \if_num:w `#1 < \c_ninety_one + \if_num:w `#1 < \c_fifty_eight + \if_num:w `#1 < \c_forty_eight + \prg_return_false: \else: \prg_return_true: \fi: + \else: + \if_num:w `#1 < \c_sixty_five + \prg_return_false: \else: \prg_return_true: \fi: + \fi: + \else: + \if_num:w `#1 < \c_one_hundred_twenty_three + \if_num:w `#1 < \c_ninety_seven + \prg_return_false: \else: \prg_return_true: \fi: + \else: + \prg_return_false: + \fi: + \fi: + } +\int_new:N \l_regex_group_level_int +\int_new:N \l_regex_mode_int +\int_new:N \l_regex_catcodes_int +\int_new:N \l_regex_default_catcodes_int +\bool_new:N \l_regex_catcodes_bool +\int_const:Nn \c_regex_catcode_C_int { "1 } +\int_const:Nn \c_regex_catcode_B_int { "4 } +\int_const:Nn \c_regex_catcode_E_int { "10 } +\int_const:Nn \c_regex_catcode_M_int { "40 } +\int_const:Nn \c_regex_catcode_T_int { "100 } +\int_const:Nn \c_regex_catcode_P_int { "1000 } +\int_const:Nn \c_regex_catcode_U_int { "4000 } +\int_const:Nn \c_regex_catcode_D_int { "10000 } +\int_const:Nn \c_regex_catcode_S_int { "100000 } +\int_const:Nn \c_regex_catcode_L_int { "400000 } +\int_const:Nn \c_regex_catcode_O_int { "1000000 } +\int_const:Nn \c_regex_catcode_A_int { "4000000 } +\int_const:Nn \c_regex_all_catcodes_int { "5515155 } +\cs_new_eq:NN \l_regex_internal_regex \c_regex_no_match_regex +\seq_new:N \l_regex_show_prefix_seq +\int_new:N \l_regex_show_lines_int +\cs_new_protected:Npn \regex_get_digits:NTFw #1#2#3#4#5 + { + \regex_if_raw_digit:NNTF #4 #5 + { #1 = #5 \regex_get_digits_loop:nw {#2} } + { #3 #4 #5 } + } +\cs_new:Npn \regex_get_digits_loop:nw #1#2#3 + { + \regex_if_raw_digit:NNTF #2 #3 + { #3 \regex_get_digits_loop:nw {#1} } + { \scan_stop: #1 #2 #3 } + } +\prg_new_conditional:Npnn \regex_if_raw_digit:NN #1#2 { TF } + { + \if_meaning:w \regex_compile_raw:N #1 + \if_int_compare:w \c_one < 1 #2 \exp_stop_f: + \prg_return_true: + \else: + \prg_return_false: + \fi: + \else: + \prg_return_false: + \fi: + } +\cs_new_nopar:Npn \regex_if_in_class:TF + { + \if_int_odd:w \l_regex_mode_int + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + } +\cs_new_nopar:Npn \regex_if_in_cs:TF + { + \if_int_odd:w \l_regex_mode_int + \exp_after:wN \use_ii:nn + \else: + \if_int_compare:w \l_regex_mode_int < \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN \use_i:nn + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \use_ii:nn + \fi: + \fi: + } +\cs_new_nopar:Npn \regex_if_in_class_or_catcode:TF + { + \if_int_odd:w \l_regex_mode_int + \exp_after:wN \use_i:nn + \else: + \if_int_compare:w \l_regex_mode_int > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN \use_i:nn + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \use_ii:nn + \fi: + \fi: + } +\cs_new_nopar:Npn \regex_if_within_catcode:TF + { + \if_int_compare:w \l_regex_mode_int > \c_zero + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + } +\cs_new_protected:Npn \regex_chk_c_allowed:T + { + \if_num:w \l_regex_mode_int = \c_zero + \exp_after:wN \use:n + \else: + \if_num:w \l_regex_mode_int = \c_three + \exp_after:wN \exp_after:wN \exp_after:wN \use:n + \else: + \msg_kernel_error:nn { regex } { c-bad-mode } + \exp_after:wN \exp_after:wN \exp_after:wN \use_none:n + \fi: + \fi: + } +\cs_new_protected:Npn \regex_mode_quit_c: + { + \if_num:w \l_regex_mode_int = \c_two + \l_regex_mode_int = \c_zero + \else: + \if_num:w \l_regex_mode_int = \c_six + \l_regex_mode_int = \c_three + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \regex_compile:w + { + \tl_set_build_x:Nw \l_regex_internal_regex + \int_zero:N \l_regex_group_level_int + \int_set_eq:NN \l_regex_default_catcodes_int \c_regex_all_catcodes_int + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \cs_set_nopar:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } + \cs_set_nopar:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } + \tl_build_one:n { \regex_branch:n { \if_false: } \fi: } + } +\cs_new_protected_nopar:Npn \regex_compile_end: + { + \regex_if_in_class:TF + { + \msg_kernel_error:nn { regex } { missing-rbrack } + \use:c { regex_compile_]: } + \prg_do_nothing: \prg_do_nothing: + } + { } + \if_num:w \l_regex_group_level_int > \c_zero + \msg_kernel_error:nnx { regex } { missing-rparen } + { \int_use:N \l_regex_group_level_int } + \prg_replicate:nn + { \l_regex_group_level_int } + { + \tl_build_one:n + { + \if_false: { \fi: } + \if_false: { \fi: } { 1 } { 0 } \c_true_bool + } + \tl_build_end: + \tl_build_one:o \l_regex_internal_regex + } + \fi: + \tl_build_one:n { \if_false: { \fi: } } + \tl_build_end: + } +\cs_new_protected:Npn \regex_compile:n #1 + { + \regex_compile:w + \int_set:Nn \tex_escapechar:D { 92 } + \int_set_eq:NN \l_regex_mode_int \c_zero + \regex_escape_use:nnnn + { + \regex_char_if_special:NTF ##1 + \regex_compile_special:N \regex_compile_raw:N ##1 + } + { + \regex_char_if_alphanumeric:NTF ##1 + \regex_compile_escaped:N \regex_compile_raw:N ##1 + } + { \regex_compile_raw:N ##1 } + { #1 } + \prg_do_nothing: \prg_do_nothing: + \prg_do_nothing: \prg_do_nothing: + \int_compare:nNnT \l_regex_mode_int < \c_zero + { + \msg_kernel_error:nn { regex } { c-missing-rbrace } + \regex_compile_end: + \regex_compile_one:x + { \regex_item_cs:n { \exp_not:o \l_regex_internal_regex } } + \prg_do_nothing: \prg_do_nothing: + \prg_do_nothing: \prg_do_nothing: + } + \regex_compile_end: + } +\cs_new_protected:Npn \regex_compile_special:N #1 + { + \cs_if_exist_use:cF { regex_compile_#1: } + { \regex_compile_raw:N #1 } + } +\cs_new_protected:Npn \regex_compile_escaped:N #1 + { + \cs_if_exist_use:cF { regex_compile_/#1: } + { \regex_compile_raw:N #1 } + } +\cs_new_protected:Npn \regex_compile_one:x #1 + { + \regex_mode_quit_c: + \regex_if_in_class:TF { } + { + \tl_build_one:n + { \regex_class:NnnnN \c_true_bool { \if_false: } \fi: } + } + \tl_build_one:x + { + \if_num:w \l_regex_catcodes_int < \c_regex_all_catcodes_int + \regex_item_catcode:nT { \int_use:N \l_regex_catcodes_int } + { \exp_not:N \exp_not:n {#1} } + \else: + \exp_not:N \exp_not:n {#1} + \fi: + } + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \regex_if_in_class:TF { } { \regex_compile_quantifier:w } + } +\cs_new_protected:Npn \regex_compile_abort_tokens:n #1 + { + \use:x + { + \exp_args:No \tl_map_function:nN { \tl_to_str:n {#1} } + \regex_compile_raw:N + } + } +\cs_generate_variant:Nn \regex_compile_abort_tokens:n { x } +\cs_new_protected:Npn \regex_compile_quantifier:w #1#2 + { + \token_if_eq_meaning:NNTF #1 \regex_compile_special:N + { + \cs_if_exist_use:cF { regex_compile_quantifier_#2:w } + { \regex_compile_quantifier_none: #1 #2 } + } + { \regex_compile_quantifier_none: #1 #2 } + } +\cs_new_protected:Npn \regex_compile_quantifier_none: + { \tl_build_one:n { \if_false: { \fi: } { 1 } { 0 } \c_false_bool } } +\cs_new_protected:Npn \regex_compile_quantifier_abort:xNN #1#2#3 + { + \regex_compile_quantifier_none: + \msg_kernel_warning:nnxx { regex } { invalid-quantifier } {#1} {#3} + \regex_compile_abort_tokens:x {#1} + #2 #3 + } +\cs_new_protected:Npn \regex_compile_quantifier_lazyness:nnNN #1#2#3#4 + { + \str_if_eq:nnTF { #3 #4 } { \regex_compile_special:N ? } + { \tl_build_one:n { \if_false: { \fi: } { #1 } { #2 } \c_true_bool } } + { + \tl_build_one:n { \if_false: { \fi: } { #1 } { #2 } \c_false_bool } + #3 #4 + } + } +\cs_new_protected_nopar:cpn { regex_compile_quantifier_?:w } + { \regex_compile_quantifier_lazyness:nnNN { 0 } { 1 } } +\cs_new_protected_nopar:cpn { regex_compile_quantifier_*:w } + { \regex_compile_quantifier_lazyness:nnNN { 0 } { -1 } } +\cs_new_protected_nopar:cpn { regex_compile_quantifier_+:w } + { \regex_compile_quantifier_lazyness:nnNN { 1 } { -1 } } +\cs_new_protected:cpn { regex_compile_quantifier_ \c_lbrace_str :w } + { + \regex_get_digits:NTFw \l_regex_internal_a_int + { \regex_compile_quantifier_braced_i:w } + { \regex_compile_quantifier_abort:xNN { \c_lbrace_str } } + } +\cs_new_protected:Npn \regex_compile_quantifier_braced_i:w #1#2 + { + \prg_case_str:xxn { #1 #2 } + { + { \regex_compile_special:N \c_rbrace_str } + { + \exp_args:No \regex_compile_quantifier_lazyness:nnNN + { \int_use:N \l_regex_internal_a_int } { 0 } + } + { \regex_compile_special:N , } + { + \regex_get_digits:NTFw \l_regex_internal_b_int + { \regex_compile_quantifier_braced_iii:w } + { \regex_compile_quantifier_braced_ii:w } + } + } + { + \regex_compile_quantifier_abort:xNN + { \c_lbrace_str \int_use:N \l_regex_internal_a_int } + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_quantifier_braced_ii:w #1#2 + { + \str_if_eq:xxTF + { #1 #2 } { \regex_compile_special:N \c_rbrace_str } + { + \exp_args:No \regex_compile_quantifier_lazyness:nnNN + { \int_use:N \l_regex_internal_a_int } { -1 } + } + { + \regex_compile_quantifier_abort:xNN + { \c_lbrace_str \int_use:N \l_regex_internal_a_int , } + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_quantifier_braced_iii:w #1#2 + { + \str_if_eq:xxTF + { #1 #2 } { \regex_compile_special:N \c_rbrace_str } + { + \if_num:w \l_regex_internal_a_int > \l_regex_internal_b_int + \msg_kernel_error:nnxx { regex } { backwards-quantifier } + { \int_use:N \l_regex_internal_a_int } + { \int_use:N \l_regex_internal_b_int } + \int_zero:N \l_regex_internal_b_int + \else: + \int_sub:Nn \l_regex_internal_b_int \l_regex_internal_a_int + \fi: + \exp_args:Noo \regex_compile_quantifier_lazyness:nnNN + { \int_use:N \l_regex_internal_a_int } + { \int_use:N \l_regex_internal_b_int } + } + { + \regex_compile_quantifier_abort:xNN + { + \c_lbrace_str + \int_use:N \l_regex_internal_a_int , + \int_use:N \l_regex_internal_b_int + } + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_raw_error:N #1 + { + \msg_kernel_error:nnx { regex } { bad-escape } {#1} + \regex_compile_raw:N #1 + } +\cs_new_protected:Npn \regex_compile_raw:N #1#2#3 + { + \regex_if_in_class:TF + { + \str_if_eq:nnTF {#2#3} { \regex_compile_special:N - } + { \regex_compile_range:Nw #1 } + { + \regex_compile_one:x + { \regex_item_equal:n { \int_value:w `#1 ~ } } + #2 #3 + } + } + { + \regex_compile_one:x + { \regex_item_equal:n { \int_value:w `#1 ~ } } + #2 #3 + } + } +\prg_new_protected_conditional:Npnn \regex_if_end_range:NN #1#2 { TF } + { + \if_meaning:w \regex_compile_raw:N #1 + \prg_return_true: + \else: + \if_meaning:w \regex_compile_special:N #1 + \if_charcode:w ] #2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + \else: + \prg_return_false: + \fi: + \fi: + } +\cs_new_protected:Npn \regex_compile_range:Nw #1#2#3 + { + \regex_if_end_range:NNTF #2 #3 + { + \if_num:w `#1 > `#3 \exp_stop_f: + \msg_kernel_error:nnxx { regex } { range-backwards } {#1} {#3} + \else: + \tl_build_one:x + { + \if_num:w `#1 = `#3 \exp_stop_f: + \regex_item_equal:n + \else: + \regex_item_range:nn { \int_value:w `#1 ~ } + \fi: + { \int_value:w `#3 ~ } + } + \fi: + } + { + \msg_kernel_warning:nnxx { regex } { range-missing-end } + {#1} { \c_backslash_str #3 } + \tl_build_one:x + { + \regex_item_equal:n { \int_value:w `#1 ~ } + \regex_item_equal:n { \int_value:w `- ~ } + } + #2#3 + } + } +\cs_new_protected_nopar:cpx { regex_compile_.: } + { + \exp_not:N \regex_if_in_class:TF + { \regex_compile_raw:N . } + { \regex_compile_one:x \exp_not:c { regex_prop_.: } } + } +\cs_new_protected_nopar:cpn { regex_prop_.: } + { + \if_num:w \l_regex_current_char_int > - \c_two + \exp_after:wN \regex_break_true:w + \fi: + } +\cs_set_protected:Npn \regex_tmp:w #1#2 + { + \cs_new_protected_nopar:cpx { regex_compile_/#1: } + { \regex_compile_one:x \exp_not:c { regex_prop_#1: } } + \cs_new_protected_nopar:cpx { regex_compile_/#2: } + { + \regex_compile_one:x + { \regex_item_reverse:n \exp_not:c { regex_prop_#1: } } + } + } +\regex_tmp:w d D +\regex_tmp:w h H +\regex_tmp:w s S +\regex_tmp:w v V +\regex_tmp:w w W +\cs_new_protected_nopar:cpn { regex_compile_/N: } + { \regex_compile_one:x \regex_prop_N: } +\cs_new_protected:Npn \regex_compile_anchor:NF #1#2 + { + \regex_if_in_class_or_catcode:TF {#2} + { + \tl_build_one:n + { \regex_assertion:Nn \c_true_bool { \regex_anchor:N #1 } } + } + } +\cs_set_protected:Npn \regex_tmp:w #1#2 + { + \cs_new_protected_nopar:cpn { regex_compile_/#1: } + { \regex_compile_anchor:NF #2 { \regex_compile_raw_error:N #1 } } + } +\regex_tmp:w A \l_regex_min_pos_int +\regex_tmp:w G \l_regex_start_pos_int +\regex_tmp:w Z \l_regex_max_pos_int +\regex_tmp:w z \l_regex_max_pos_int +\cs_set_protected:Npn \regex_tmp:w #1#2 + { + \cs_new_protected_nopar:cpn { regex_compile_#1: } + { \regex_compile_anchor:NF #2 { \regex_compile_raw:N #1 } } + } +\exp_args:Nx \regex_tmp:w { \iow_char:N \^ } \l_regex_min_pos_int +\exp_args:Nx \regex_tmp:w { \iow_char:N \$ } \l_regex_max_pos_int +\cs_new_protected_nopar:cpn { regex_compile_/b: } + { + \regex_if_in_class_or_catcode:TF + { \regex_compile_raw_error:N b } + { + \tl_build_one:n + { \regex_assertion:Nn \c_true_bool { \regex_b_test: } } + } + } +\cs_new_protected_nopar:cpn { regex_compile_/B: } + { + \regex_if_in_class_or_catcode:TF + { \regex_compile_raw_error:N B } + { + \tl_build_one:n + { \regex_assertion:Nn \c_false_bool { \regex_b_test: } } + } + } +\cs_new_protected:cpn { regex_compile_]: } + { + \regex_if_in_class:TF + { + \if_num:w \l_regex_mode_int > \c_sixteen + \tl_build_one:n { \if_false: { \fi: } } + \fi: + \tex_advance:D \l_regex_mode_int - \c_fifteen + \tex_divide:D \l_regex_mode_int \c_thirteen + \if_int_odd:w \l_regex_mode_int \else: + \exp_after:wN \regex_compile_quantifier:w + \fi: + } + { \regex_compile_raw:N ] } + } +\cs_new_protected_nopar:cpn { regex_compile_[: } + { + \regex_if_in_class:TF + { \regex_compile_class_posix_test:w } + { + \regex_if_within_catcode:TF + { + \exp_after:wN \regex_compile_class_catcode:w + \int_use:N \l_regex_catcodes_int ; + } + { \regex_compile_class_normal:w } + } + } +\cs_new_protected_nopar:Npn \regex_compile_class_normal:w + { + \regex_compile_class:TFNN + { \regex_class:NnnnN \c_true_bool } + { \regex_class:NnnnN \c_false_bool } + } +\cs_new_protected:Npn \regex_compile_class_catcode:w #1; + { + \if_int_compare:w \l_regex_mode_int = \c_two + \tl_build_one:n + { \regex_class:NnnnN \c_true_bool { \if_false: } \fi: } + \fi: + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \regex_compile_class:TFNN + { \regex_item_catcode:nT {#1} } + { \regex_item_catcode_reverse:nT {#1} } + } +\cs_new_protected:Npn \regex_compile_class:TFNN #1#2#3#4 + { + \l_regex_mode_int = \int_value:w \l_regex_mode_int 3 \exp_stop_f: + \str_if_eq:nnTF { #3 #4 } { \regex_compile_special:N ^ } + { + \tl_build_one:n { #2 { \if_false: } \fi: } + \regex_compile_class_ii:NN + } + { + \tl_build_one:n { #1 { \if_false: } \fi: } + \regex_compile_class_ii:NN #3 #4 + } + } +\cs_new_protected:Npn \regex_compile_class_ii:NN #1#2 + { + \token_if_eq_charcode:NNTF #2 ] + { \regex_compile_raw:N #2 } + { #1 #2 } + } +\cs_new_protected:Npn \regex_compile_class_posix_test:w #1#2 + { + \token_if_eq_meaning:NNT \regex_compile_special:N #1 + { + \prg_case_str:nnn { #2 } + { + : { \regex_compile_class_posix:NNNNw } + = { \msg_kernel_warning:nnx { regex } { posix-unsupported } { = } } + . { \msg_kernel_warning:nnx { regex } { posix-unsupported } { . } } + } + { } + } + \regex_compile_raw:N [ #1 #2 + } +\cs_new_protected:Npn \regex_compile_class_posix:NNNNw #1#2#3#4#5#6 + { + \str_if_eq:nnTF { #5 #6 } { \regex_compile_special:N ^ } + { + \bool_set_false:N \l_regex_internal_bool + \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: + \regex_compile_class_posix_loop:w + } + { + \bool_set_true:N \l_regex_internal_bool + \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: + \regex_compile_class_posix_loop:w #5 #6 + } + } +\cs_new:Npn \regex_compile_class_posix_loop:w #1#2 + { + \token_if_eq_meaning:NNTF \regex_compile_raw:N #1 + { #2 \regex_compile_class_posix_loop:w } + { \if_false: { \fi: } \regex_compile_class_posix_end:w #1 #2 } + } +\cs_new_protected:Npn \regex_compile_class_posix_end:w #1#2#3#4 + { + \str_if_eq:nnTF { #1 #2 #3 #4 } + { \regex_compile_special:N : \regex_compile_special:N ] } + { + \cs_if_exist:cTF { regex_posix_ \l_regex_internal_a_tl : } + { + \regex_compile_one:x + { + \bool_if:NF \l_regex_internal_bool \regex_item_reverse:n + \exp_not:c { regex_posix_ \l_regex_internal_a_tl : } + } + } + { + \msg_kernel_warning:nnx { regex } { posix-unknown } + { \l_regex_internal_a_tl } + \regex_compile_abort_tokens:x + { + [: \bool_if:NF \l_regex_internal_bool { ^ } + \l_regex_internal_a_tl :] + } + } + } + { + \msg_kernel_error:nnxx { regex } { posix-missing-close } + { [: \l_regex_internal_a_tl } { #2 #4 } + \regex_compile_abort_tokens:x { [: \l_regex_internal_a_tl } + #1 #2 #3 #4 + } + } +\cs_new_protected:Npn \regex_compile_group_begin:N #1 + { + \tl_build_one:n { #1 { \if_false: } \fi: } + \regex_mode_quit_c: + \tl_set_build:Nw \l_regex_internal_regex + \int_set_eq:NN \l_regex_default_catcodes_int \l_regex_catcodes_int + \int_incr:N \l_regex_group_level_int + \tl_build_one:n { \regex_branch:n { \if_false: } \fi: } + } +\cs_new_protected:Npn \regex_compile_group_end: + { + \if_num:w \l_regex_group_level_int > \c_zero + \tl_build_one:n { \if_false: { \fi: } } + \tl_build_end: + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \tl_build_one:o \l_regex_internal_regex + \exp_after:wN \regex_compile_quantifier:w + \else: + \msg_kernel_warning:nn { regex } { extra-rparen } + \exp_after:wN \regex_compile_raw:N \exp_after:wN ) + \fi: + } +\cs_new_protected_nopar:cpn { regex_compile_(: } + { + \regex_if_in_class:TF { \regex_compile_raw:N ( } + { \regex_compile_lparen:w } + } +\cs_new_protected:Npn \regex_compile_lparen:w #1#2#3#4 + { + \str_if_eq:nnTF { #1 #2 } { \regex_compile_special:N ? } + { + \cs_if_exist_use:cF + { regex_compile_special_group_\token_to_str:N #4 :w } + { + \msg_kernel_warning:nnx { regex } { special-group-unknown } + { (? \token_to_str:N #4 } + \regex_compile_group_begin:N \regex_group:nnnN + \regex_compile_raw:N ? #3 #4 + } + } + { + \regex_compile_group_begin:N \regex_group:nnnN + #1 #2 #3 #4 + } + } +\cs_new_protected_nopar:cpn { regex_compile_|: } + { + \regex_if_in_class:TF { \regex_compile_raw:N | } + { + \tl_build_one:n + { \if_false: { \fi: } \regex_branch:n { \if_false: } \fi: } + } + } +\cs_new_protected_nopar:cpn { regex_compile_): } + { + \regex_if_in_class:TF { \regex_compile_raw:N ) } + { \regex_compile_group_end: } + } +\cs_new_protected_nopar:cpn { regex_compile_special_group_::w } + { \regex_compile_group_begin:N \regex_group_no_capture:nnnN } +\cs_new_protected_nopar:cpn { regex_compile_special_group_|:w } + { \regex_compile_group_begin:N \regex_group_resetting:nnnN } +\cs_new_protected:Npn \regex_compile_special_group_i:w #1#2 + { + \str_if_eq:nnTF { #1 #2 } { \regex_compile_special:N ) } + { + \cs_set_nopar:Npn \regex_item_equal:n { \regex_item_caseless_equal:n } + \cs_set_nopar:Npn \regex_item_range:nn { \regex_item_caseless_range:nn } + } + { + \msg_kernel_warning:nnx { regex } { unknown-option } { (?i #2 } + \regex_compile_raw:N ( + \regex_compile_raw:N ? + \regex_compile_raw:N i + #1 #2 + } + } +\cs_new_protected_nopar:cpn { regex_compile_special_group_-:w } #1#2#3#4 + { + \str_if_eq:nnTF { #1 #2 #3 #4 } + { \regex_compile_raw:N i \regex_compile_special:N ) } + { + \cs_set_nopar:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } + \cs_set_nopar:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } + } + { + \msg_kernel_warning:nnx { regex } { unknown-option } { (?-#2#4 } + \regex_compile_raw:N ( + \regex_compile_raw:N ? + \regex_compile_raw:N - + #1 #2 #3 #4 + } + } +\cs_new_protected:cpn { regex_compile_/c: } + { \regex_chk_c_allowed:T { \regex_compile_c_test:NN } } +\cs_new_protected:Npn \regex_compile_c_test:NN #1#2 + { + \token_if_eq_meaning:NNTF #1 \regex_compile_raw:N + { + \cs_if_exist:cTF { c_regex_catcode_#2_int } + { + \int_set_eq:Nc \l_regex_catcodes_int { c_regex_catcode_#2_int } + \l_regex_mode_int + = \if_case:w \l_regex_mode_int \c_two \else: \c_six \fi: + } + } + { \cs_if_exist_use:cF { regex_compile_c_#2:w } } + { + \msg_kernel_error:nnx { regex } { c-missing-category } {#2} + #1 #2 + } + } +\cs_new_protected:cpn { regex_compile_c_[:w } #1#2 + { + \l_regex_mode_int + = \if_case:w \l_regex_mode_int \c_two \else: \c_six \fi: + \int_zero:N \l_regex_catcodes_int + \str_if_eq:nnTF { #1 #2 } { \regex_compile_special:N ^ } + { + \bool_set_false:N \l_regex_catcodes_bool + \regex_compile_c_lbrack_loop:NN + } + { + \bool_set_true:N \l_regex_catcodes_bool + \regex_compile_c_lbrack_loop:NN + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_c_lbrack_loop:NN #1#2 + { + \token_if_eq_meaning:NNTF #1 \regex_compile_raw:N + { + \cs_if_exist:cTF { c_regex_catcode_#2_int } + { + \exp_args:Nc \regex_compile_c_lbrack_add:N + { c_regex_catcode_#2_int } + \regex_compile_c_lbrack_loop:NN + } + } + { + \token_if_eq_charcode:NNTF #2 ] + { \regex_compile_c_lbrack_end: } + } + { + \msg_kernel_error:nnx { regex } { c-missing-rbrack } {#2} + \regex_compile_c_lbrack_end: + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_c_lbrack_add:N #1 + { + \if_int_odd:w \int_eval:w \l_regex_catcodes_int / #1 \int_eval_end: + \else: + \tex_advance:D \l_regex_catcodes_int #1 + \fi: + } +\cs_new_protected_nopar:Npn \regex_compile_c_lbrack_end: + { + \if_meaning:w \c_false_bool \l_regex_catcodes_bool + \int_set:Nn \l_regex_catcodes_int + { \c_regex_all_catcodes_int - \l_regex_catcodes_int } + \fi: + } +\cs_new_protected_nopar:cpn { regex_compile_c_ \c_lbrace_str :w } + { + \regex_compile:w + \regex_disable_submatches: + \l_regex_mode_int + = - \if_case:w \l_regex_mode_int \c_two \else: \c_six \fi: + } +\cs_new_protected:cpn { regex_compile_ \c_rbrace_str : } + { + \regex_if_in_cs:TF + { + \regex_compile_end: + \regex_compile_one:x + { \regex_item_cs:n { \exp_not:o \l_regex_internal_regex } } + } + { \exp_after:wN \regex_compile_raw:N \c_rbrace_str } + } +\cs_new_protected:cpn { regex_compile_/u: } #1#2 + { + \regex_if_in_class_or_catcode:TF + { \regex_compile_raw_error:N u #1 #2 } + { + \str_if_eq:xxTF {#1#2} { \regex_compile_special:N \c_lbrace_str } + { + \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: + \regex_compile_u_loop:NN + } + { + \msg_kernel_error:nn { regex } { u-missing-lbrace } + \regex_compile_raw:N u #1 #2 + } + } + } +\cs_new:Npn \regex_compile_u_loop:NN #1#2 + { + \token_if_eq_meaning:NNTF #1 \regex_compile_raw:N + { #2 \regex_compile_u_loop:NN } + { + \token_if_eq_meaning:NNTF #1 \regex_compile_special:N + { + \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #2 + { \if_false: { \fi: } \regex_compile_u_end: } + { #2 \regex_compile_u_loop:NN } + } + { + \if_false: { \fi: } + \msg_kernel_error:nnx { regex } { u-missing-rbrace } {#2} + \regex_compile_u_end: + #1 #2 + } + } + } +\cs_new_protected:Npn \regex_compile_u_end: + { + \tl_set:Nv \l_regex_internal_a_tl { \l_regex_internal_a_tl } + \if_num:w \l_regex_mode_int = \c_zero + \regex_compile_u_not_cs: + \else: + \regex_compile_u_in_cs: + \fi: + } +\cs_new_protected:Npn \regex_compile_u_in_cs: + { + \exp_args:NNo \str_gset_other:Nn \g_regex_internal_tl + { \l_regex_internal_a_tl } + \tl_build_one:x + { + \tl_map_function:NN \g_regex_internal_tl + \regex_compile_u_in_cs_aux:n + } + } +\cs_new:Npn \regex_compile_u_in_cs_aux:n #1 + { + \regex_class:NnnnN \c_true_bool + { \regex_item_caseful_equal:n { \int_value:w `#1 } } + { 1 } { 0 } \c_false_bool + } +\cs_new_protected:Npn \regex_compile_u_not_cs: + { + \exp_args:No \tl_analysis_map_inline:nn { \l_regex_internal_a_tl } + { + \tl_build_one:n + { + \regex_class:NnnnN \c_true_bool + { + \if_num:w "##2 = \c_zero + \regex_item_exact_cs:c { \exp_after:wN \cs_to_str:N ##1 } + \else: + \regex_item_exact:nn { \int_value:w "##2 } { ##3 } + \fi: + } + { 1 } { 0 } \c_false_bool + } + } + } +\cs_new_protected_nopar:cpn { regex_compile_/K: } + { + \int_compare:nNnTF \l_regex_mode_int = \c_zero + { \tl_build_one:n { \regex_command_K: } } + { \regex_compile_raw_error:N K } + } +\cs_new_protected:Npn \regex_show_aux:Nx #1#2 + { + \tl_set_build:Nw \l_regex_internal_a_tl + \cs_set_protected_nopar:Npn \regex_branch:n + { + \seq_pop_right:NN \l_regex_show_prefix_seq \l_regex_internal_a_tl + \regex_show_one:n { +-branch } + \seq_put_right:No \l_regex_show_prefix_seq \l_regex_internal_a_tl + \use:n + } + \cs_set_protected_nopar:Npn \regex_group:nnnN + { \regex_show_group_aux:nnnnN { } } + \cs_set_protected_nopar:Npn \regex_group_no_capture:nnnN + { \regex_show_group_aux:nnnnN { ~(no~capture) } } + \cs_set_protected_nopar:Npn \regex_group_resetting:nnnN + { \regex_show_group_aux:nnnnN { ~(resetting) } } + \cs_set_eq:NN \regex_class:NnnnN \regex_show_class:NnnnN + \cs_set_protected_nopar:Npn \regex_command_K: + { \regex_show_one:n { reset~match~start~(\iow_char:N\\K) } } + \cs_set_protected:Npn \regex_assertion:Nn ##1##2 + { \regex_show_one:n { \bool_if:NF ##1 { negative~ } assertion:~##2 } } + \cs_set_nopar:Npn \regex_b_test: { word~boundary } + \cs_set_eq:NN \regex_anchor:N \regex_show_anchor_to_str:N + \cs_set_protected:Npn \regex_item_caseful_equal:n ##1 + { \regex_show_one:n { char~code~\int_eval:n{##1} } } + \cs_set_protected:Npn \regex_item_caseful_range:nn ##1##2 + { \regex_show_one:n { range~[\int_eval:n{##1}, \int_eval:n{##2}] } } + \cs_set_protected:Npn \regex_item_caseless_equal:n ##1 + { \regex_show_one:n { char~code~\int_eval:n{##1}~(caseless) } } + \cs_set_protected:Npn \regex_item_caseless_range:nn ##1##2 + { + \regex_show_one:n + { Range~[\int_eval:n{##1}, \int_eval:n{##2}]~(caseless) } + } + \cs_set_protected:Npn \regex_item_catcode:nT + { \regex_show_item_catcode:NnT \c_true_bool } + \cs_set_protected:Npn \regex_item_catcode_reverse:nT + { \regex_show_item_catcode:NnT \c_false_bool } + \cs_set_protected:Npn \regex_item_reverse:n + { \regex_show_scope:nn { Reversed~match } } + \cs_set_protected:Npn \regex_item_exact:nn ##1##2 + { \regex_show_one:n { char~##2,~catcode~##1 } } + \cs_set_protected:Npn \regex_item_exact_cs:c ##1 + { \regex_show_one:n { control~sequence~\iow_char:N\\##1 } } + \cs_set_protected:Npn \regex_item_cs:n + { \regex_show_scope:nn { control~sequence } } + \cs_set:cpn { regex_prop_.: } { \regex_show_one:n { any~token } } + \seq_clear:N \l_regex_show_prefix_seq + \regex_show_push:n { ~ } + #1 + \tl_build_end: + \msg_aux_show:x { > Compiled~regex~#2: \l_regex_internal_a_tl } + } +\cs_new_protected:Npn \regex_show_one:n #1 + { + \int_incr:N \l_regex_show_lines_int + \tl_build_one:x + { \iow_newline: \seq_use:N \l_regex_show_prefix_seq #1 } + } +\cs_new_protected:Npn \regex_show_push:n #1 + { \seq_put_right:Nx \l_regex_show_prefix_seq { #1 ~ } } +\cs_new_protected:Npn \regex_show_pop: + { \seq_pop_right:NN \l_regex_show_prefix_seq \l_regex_internal_a_tl } +\cs_new_protected:Npn \regex_show_scope:nn #1#2 + { + \regex_show_one:n {#1} + \regex_show_push:n { ~ } + #2 + \regex_show_pop: + } +\cs_new_protected:Npn \regex_show_group_aux:nnnnN #1#2#3#4#5 + { + \regex_show_one:n { ,-group~begin #1 } + \regex_show_push:n { | } + \use_ii:nn #2 + \regex_show_pop: + \regex_show_one:n + { `-group~end \regex_msg_repeated:nnN {#3} {#4} #5 } + } +\cs_set:Npn \regex_show_class:NnnnN #1#2#3#4#5 + { + \tl_set_build:Nw \l_regex_internal_a_tl + \int_zero:N \l_regex_show_lines_int + \regex_show_push:n {~} + #2 + \exp_last_unbraced:Nf + \prg_case_int:nnn { \l_regex_show_lines_int } + { + {0} + { + \tl_build_end: + \regex_show_one:n { \bool_if:NTF #1 { Fail } { Pass } } + } + {1} + { + \tl_build_end: + \bool_if:NTF #1 + { + #2 + \tl_build_one:n { \regex_msg_repeated:nnN {#3} {#4} #5 } + } + { + \regex_show_one:n + { Don't~match~\regex_msg_repeated:nnN {#3} {#4} #5 } + \tl_build_one:o \l_regex_internal_a_tl + } + } + } + { + \tl_build_end: + \regex_show_one:n + { + \bool_if:NTF #1 { M } { Don't~m } atch + \regex_msg_repeated:nnN {#3} {#4} #5 + } + \tl_build_one:o \l_regex_internal_a_tl + } + } +\cs_new:Npn \regex_show_anchor_to_str:N #1 + { + anchor~at~ + \prg_case_str:nnn { #1 } + { + { \l_regex_min_pos_int } { start~(\iow_char:N\\A) } + { \l_regex_start_pos_int } { start~of~match~(\iow_char:N\\G) } + { \l_regex_max_pos_int } { end~(\iow_char:N\\Z) } + } + { <error:~'#1'~not~recognized> } + } +\cs_new_protected:Npn \regex_show_item_catcode:NnT #1#2 + { + \seq_set_split:Nnn \l_regex_internal_seq { } { CBEMTPUDSLOA } + \seq_set_filter:NNn \l_regex_internal_seq \l_regex_internal_seq + { \int_if_odd_p:n { #2 / \int_use:c { c_regex_catcode_##1_int } } } + \regex_show_scope:nn + { + categories~\seq_use:N \l_regex_internal_seq, ~ + \bool_if:NF #1 { negative~ } class + } + } +\int_new:N \l_regex_min_state_int +\int_new:N \l_regex_max_state_int +\int_new:N \l_regex_left_state_int +\int_new:N \l_regex_right_state_int +\seq_new:N \l_regex_left_state_seq +\seq_new:N \l_regex_right_state_seq +\int_new:N \l_regex_capturing_group_int +\cs_new_protected:Npn \regex_build:n #1 + { + \regex_compile:n {#1} + \regex_build:N \l_regex_internal_regex + } +\cs_new_protected:Npn \regex_build:N #1 + { + \trace_push:nnn { regex } { 1 } { regex_build } + \int_set:Nn \tex_escapechar:D { 92 } + \int_zero:N \l_regex_capturing_group_int + \int_set_eq:NN \l_regex_max_state_int \l_regex_min_state_int + \regex_build_new_state: + \regex_build_new_state: + \regex_toks_put_right:Nn \l_regex_left_state_int + { \regex_action_start_wildcard: } + \regex_group:nnnN {#1} { 1 } { 0 } \c_false_bool + \regex_toks_put_right:Nn \l_regex_right_state_int + { \regex_action_success: } + \regex_trace_states:n { 2 } + \trace_pop:nnn { regex } { 1 } { regex_build } + } +\cs_new_protected:Npn \regex_build_for_cs:n #1 + { + \trace_push:nnn { regex } { 1 } { regex_build_for_cs } + \int_set_eq:NN \l_regex_max_state_int \l_regex_min_state_int + \regex_build_new_state: + \regex_build_new_state: + \regex_push_lr_states: + #1 + \regex_pop_lr_states: + \regex_toks_put_right:Nn \l_regex_right_state_int + { + \if_num:w \l_regex_current_pos_int = \l_regex_max_pos_int + \exp_after:wN \regex_action_success: + \fi: + } + \regex_trace_states:n { 2 } + \trace_pop:nnn { regex } { 1 } { regex_build_for_cs } + } +\cs_new_protected_nopar:Npn \regex_push_lr_states: + { + \seq_push:No \l_regex_left_state_seq + { \int_use:N \l_regex_left_state_int } + \seq_push:No \l_regex_right_state_seq + { \int_use:N \l_regex_right_state_int } + } +\cs_new_protected_nopar:Npn \regex_pop_lr_states: + { + \seq_pop:NN \l_regex_left_state_seq \l_regex_internal_a_tl + \int_set:Nn \l_regex_left_state_int \l_regex_internal_a_tl + \seq_pop:NN \l_regex_right_state_seq \l_regex_internal_a_tl + \int_set:Nn \l_regex_right_state_int \l_regex_internal_a_tl + } +\cs_new_protected:Npn \regex_toks_put_left:Nx #1#2 + { + \cs_set_nopar:Npx \regex_tmp:w { #2 } + \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 } + } +\cs_new_protected:Npn \regex_toks_put_right:Nx #1#2 + { + \cs_set_nopar:Npx \regex_tmp:w {#2} + \tex_toks:D #1 \exp_after:wN + { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w } + } +\cs_new_protected:Npn \regex_toks_put_right:Nn #1#2 + { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } } +\cs_new_protected:Npn \regex_build_transition_left:NNN #1#2#3 + { \regex_toks_put_left:Nx #2 { #1 { \int_eval:n { #3 - #2 } } } } +\cs_new_protected:Npn \regex_build_transition_right:nNn #1#2#3 + { \regex_toks_put_right:Nx #2 { #1 { \int_eval:n { #3 - #2 } } } } +\cs_new_protected_nopar:Npn \regex_build_new_state: + { + \trace:nnx { regex } { 2 } + { + regex~new~state~ + L=\int_use:N \l_regex_left_state_int ~ -> ~ + R=\int_use:N \l_regex_right_state_int ~ -> ~ + M=\int_use:N \l_regex_max_state_int ~ -> ~ + \int_eval:n { \l_regex_max_state_int + \c_one } + } + \tex_toks:D \l_regex_max_state_int { } + \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int + \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int + \int_incr:N \l_regex_max_state_int + } +\cs_new_protected:Npn \regex_build_transitions_lazyness:NNNNN #1#2#3#4#5 + { + \regex_build_new_state: + \regex_toks_put_right:Nx \l_regex_left_state_int + { + \if_meaning:w \c_true_bool #1 + #2 { \int_eval:n { #3 - \l_regex_left_state_int } } + #4 { \int_eval:n { #5 - \l_regex_left_state_int } } + \else: + #4 { \int_eval:n { #5 - \l_regex_left_state_int } } + #2 { \int_eval:n { #3 - \l_regex_left_state_int } } + \fi: + } + } +\cs_new_protected:Npn \regex_class:NnnnN #1#2#3#4#5 + { + \cs_set_nopar:Npx \regex_tests_action_cost:n ##1 + { + \exp_not:n { \exp_not:n {#2} } + \bool_if:NTF #1 + { \regex_break_point:TF { \regex_action_cost:n {##1} } { } } + { \regex_break_point:TF { } { \regex_action_cost:n {##1} } } + } + \if_case:w - #4 \exp_stop_f: + \regex_class_repeat:n {#3} + \or: \regex_class_repeat:nN {#3} #5 + \else: \regex_class_repeat:nnN {#3} {#4} #5 + \fi: + } +\cs_new:Npn \regex_tests_action_cost:n { \regex_action_cost:n } +\cs_new_protected:Npn \regex_class_repeat:n #1 + { + \prg_replicate:nn {#1} + { + \regex_build_new_state: + \regex_build_transition_right:nNn \regex_tests_action_cost:n + \l_regex_left_state_int \l_regex_right_state_int + } + } +\cs_new_protected:Npn \regex_class_repeat:nN #1#2 + { + \if_num:w #1 = \c_zero + \regex_build_transitions_lazyness:NNNNN #2 + \regex_action_free:n \l_regex_right_state_int + \regex_tests_action_cost:n \l_regex_left_state_int + \else: + \regex_class_repeat:n {#1} + \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int + \regex_build_transitions_lazyness:NNNNN #2 + \regex_action_free:n \l_regex_right_state_int + \regex_action_free:n \l_regex_internal_a_int + \fi: + } +\cs_new_protected:Npn \regex_class_repeat:nnN #1#2#3 + { + \regex_class_repeat:n {#1} + \int_set:Nn \l_regex_internal_a_int + { \l_regex_max_state_int + #2 - \c_one } + \prg_replicate:nn { #2 } + { + \regex_build_transitions_lazyness:NNNNN #3 + \regex_action_free:n \l_regex_internal_a_int + \regex_tests_action_cost:n \l_regex_right_state_int + } + } +\cs_new_protected:Npn \regex_group_aux:nnnnN #1#2#3#4#5 + { + \trace_push:nnn { regex } { 1 } { regex_group } + \if_num:w #3 = \c_zero + \regex_build_new_state: + \regex_build_transition_right:nNn \regex_action_free_group:n + \l_regex_left_state_int \l_regex_right_state_int + \fi: + \regex_build_new_state: + \regex_push_lr_states: + #2 + \regex_pop_lr_states: + \if_case:w - #4 \exp_stop_f: + \regex_group_repeat:nn {#1} {#3} + \or: \regex_group_repeat:nnN {#1} {#3} #5 + \else: \regex_group_repeat:nnnN {#1} {#3} {#4} #5 + \fi: + \trace_pop:nnn { regex } { 1 } { regex_group } + } +\cs_new_protected:Npn \regex_group:nnnN #1 + { + \exp_args:No \regex_group_aux:nnnnN + { \int_use:N \l_regex_capturing_group_int } + { + \int_incr:N \l_regex_capturing_group_int + #1 + } + } +\cs_new_protected_nopar:Npn \regex_group_no_capture:nnnN + { \regex_group_aux:nnnnN { -1 } } +\cs_new_protected:Npn \regex_group_resetting:nnnN #1 + { + \regex_group_aux:nnnnN { -1 } + { + \exp_args:Noo \regex_group_resetting_loop:nnNn + { \int_use:N \l_regex_capturing_group_int } + { \int_use:N \l_regex_capturing_group_int } + #1 + { ?? \prg_map_break:n } { } + \prg_break_point:n { } + } + } +\cs_new_protected:Npn \regex_group_resetting_loop:nnNn #1#2#3#4 + { + \use_none:nn #3 { \int_set:Nn \l_regex_capturing_group_int {#1} } + \int_set:Nn \l_regex_capturing_group_int {#2} + #3 {#4} + \exp_args:Nf \regex_group_resetting_loop:nnNn + { \int_max:nn {#1} { \l_regex_capturing_group_int } } + {#2} + } +\cs_new_protected:Npn \regex_branch:n #1 + { + \trace_push:nnn { regex } { 1 } { regex_branch } + \regex_build_new_state: + \seq_get:NN \l_regex_left_state_seq \l_regex_internal_a_tl + \int_set:Nn \l_regex_left_state_int \l_regex_internal_a_tl + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_left_state_int \l_regex_right_state_int + #1 + \seq_get:NN \l_regex_right_state_seq \l_regex_internal_a_tl + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_internal_a_tl + \trace_pop:nnn { regex } { 1 } { regex_branch } + } +\cs_new_protected:Npn \regex_group_repeat:nn #1#2 + { + \if_num:w #2 = \c_zero + \int_set:Nn \l_regex_max_state_int + { \l_regex_left_state_int - \c_one } + \regex_build_new_state: + \else: + \regex_group_repeat_aux:n {#2} + \regex_group_submatches:nNN {#1} + \l_regex_internal_a_int \l_regex_right_state_int + \regex_build_new_state: + \fi: + } +\cs_new_protected:Npn \regex_group_submatches:nNN #1#2#3 + { + \if_num:w #1 > \c_minus_one + \regex_toks_put_left:Nx #2 { \regex_action_submatch:n { #1 < } } + \regex_toks_put_left:Nx #3 { \regex_action_submatch:n { #1 > } } + \fi: + } +\cs_new_protected:Npn \regex_group_repeat_aux:n #1 + { + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_max_state_int + \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int + \int_set_eq:NN \l_regex_internal_b_int \l_regex_max_state_int + \if_num:w \int_eval:w #1 > \c_one + \int_set:Nn \l_regex_internal_c_int + { + ( #1 - \c_one ) + * ( \l_regex_internal_b_int - \l_regex_internal_a_int ) + } + \tex_advance:D \l_regex_right_state_int \l_regex_internal_c_int + \tex_advance:D \l_regex_max_state_int \l_regex_internal_c_int + \prg_replicate:nn \l_regex_internal_c_int + { + \tex_toks:D \l_regex_internal_b_int + = \tex_toks:D \l_regex_internal_a_int + \tex_advance:D \l_regex_internal_a_int \c_one + \tex_advance:D \l_regex_internal_b_int \c_one + } + \fi: + } +\cs_new_protected:Npn \regex_group_repeat:nnN #1#2#3 + { + \if_num:w #2 = \c_zero + \regex_group_submatches:nNN {#1} + \l_regex_left_state_int \l_regex_right_state_int + \int_set:Nn \l_regex_internal_a_int + { \l_regex_left_state_int - \c_one } + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_internal_a_int + \regex_build_new_state: + \if_meaning:w \c_true_bool #3 + \regex_build_transition_left:NNN \regex_action_free:n + \l_regex_internal_a_int \l_regex_right_state_int + \else: + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_internal_a_int \l_regex_right_state_int + \fi: + \else: + \regex_group_repeat_aux:n {#2} + \regex_group_submatches:nNN {#1} + \l_regex_internal_a_int \l_regex_right_state_int + \if_meaning:w \c_true_bool #3 + \regex_build_transition_right:nNn \regex_action_free_group:n + \l_regex_right_state_int \l_regex_internal_a_int + \else: + \regex_build_transition_left:NNN \regex_action_free_group:n + \l_regex_right_state_int \l_regex_internal_a_int + \fi: + \regex_build_new_state: + \fi: + } +\cs_new_protected:Npn \regex_group_repeat:nnnN #1#2#3#4 + { + \regex_group_submatches:nNN {#1} + \l_regex_left_state_int \l_regex_right_state_int + \regex_group_repeat_aux:n { #2 + #3 } + \if_meaning:w \c_true_bool #4 + \int_set_eq:NN \l_regex_left_state_int \l_regex_max_state_int + \prg_replicate:nn { #3 } + { + \int_sub:Nn \l_regex_left_state_int + { \l_regex_internal_b_int - \l_regex_internal_a_int } + \regex_build_transition_left:NNN \regex_action_free:n + \l_regex_left_state_int \l_regex_max_state_int + } + \else: + \prg_replicate:nn { #3 - \c_one } + { + \int_sub:Nn \l_regex_right_state_int + { \l_regex_internal_b_int - \l_regex_internal_a_int } + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_max_state_int + } + \if_num:w #2 = \c_zero + \int_set:Nn \l_regex_right_state_int + { \l_regex_left_state_int - \c_one } + \else: + \int_sub:Nn \l_regex_right_state_int + { \l_regex_internal_b_int - \l_regex_internal_a_int } + \fi: + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_max_state_int + \fi: + \regex_build_new_state: + } +\cs_new_protected:Npn \regex_assertion:Nn #1#2 + { + \regex_build_new_state: + \regex_toks_put_right:Nx \l_regex_left_state_int + { + \exp_not:n {#2} + \regex_break_point:TF + \bool_if:NF #1 { { } } + { + \regex_action_free:n + { + \int_eval:n + { \l_regex_right_state_int - \l_regex_left_state_int } + } + } + \bool_if:NT #1 { { } } + } + } +\cs_new_protected:Npn \regex_anchor:N #1 + { + \if_num:w #1 = \l_regex_current_pos_int + \exp_after:wN \regex_break_true:w + \fi: + } +\cs_new_protected_nopar:Npn \regex_b_test: + { + \group_begin: + \int_set_eq:NN \l_regex_current_char_int \l_regex_last_char_int + \regex_prop_w: + \regex_break_point:TF + { \group_end: \regex_item_reverse:n \regex_prop_w: } + { \group_end: \regex_prop_w: } + } +\cs_new_protected_nopar:Npn \regex_command_K: + { + \regex_build_new_state: + \regex_toks_put_right:Nx \l_regex_left_state_int + { + \regex_action_submatch:n { 0< } + \bool_set_true:N \l_regex_fresh_thread_bool + \regex_action_free:n + { \int_eval:n { \l_regex_right_state_int - \l_regex_left_state_int } } + \bool_set_false:N \l_regex_fresh_thread_bool + } + } +\int_new:N \l_regex_min_pos_int +\int_new:N \l_regex_max_pos_int +\int_new:N \l_regex_current_pos_int +\int_new:N \l_regex_start_pos_int +\int_new:N \l_regex_success_pos_int +\int_new:N \l_regex_current_char_int +\int_new:N \l_regex_current_catcode_int +\int_new:N \l_regex_last_char_int +\int_new:N \l_regex_case_changed_char_int +\int_new:N \l_regex_current_state_int +\prop_new:N \l_regex_current_submatches_prop +\prop_new:N \l_regex_success_submatches_prop +\int_new:N \l_regex_step_int +\int_new:N \l_regex_min_active_int +\int_new:N \l_regex_max_active_int +\tl_new:N \l_regex_every_match_tl +\bool_new:N \l_regex_fresh_thread_bool +\bool_new:N \l_regex_empty_success_bool +\cs_new_eq:NN \regex_if_two_empty_matches:F \use:n +\bool_new:N \g_regex_success_bool +\bool_new:N \l_regex_saved_success_bool +\bool_new:N \l_regex_match_success_bool +\cs_new_protected:Npn \regex_match:n #1 + { + \trace_push:nnx { regex } { 1 } { regex_match } + \trace:nnx { regex } { 1 } { analyzing~query~token~list } + \int_zero:N \l_regex_balance_int + \int_set:Nn \l_regex_current_pos_int { \c_two * \l_regex_max_state_int } + \regex_query_set:nnn { } { -1 } { -2 } + \int_set_eq:NN \l_regex_min_pos_int \l_regex_current_pos_int + \tl_analysis_map_inline:nn {#1} + { \regex_query_set:nnn {##1} {"##2} {##3} } + \int_set_eq:NN \l_regex_max_pos_int \l_regex_current_pos_int + \regex_query_set:nnn { } { -1 } { -2 } + \trace:nnx { regex } { 1 } { initializing } + \bool_gset_false:N \g_regex_success_bool + \prg_stepwise_inline:nnnn + \l_regex_min_state_int \c_one { \l_regex_max_state_int - \c_one } + { \tex_dimen:D ##1 \c_one sp \scan_stop: } + \int_set_eq:NN \l_regex_min_active_int \l_regex_max_state_int + \int_set_eq:NN \l_regex_step_int \c_zero + \int_set_eq:NN \l_regex_success_pos_int \l_regex_min_pos_int + \int_set:Nn \l_regex_submatch_int + { \c_two * \l_regex_max_state_int } + \bool_set_false:N \l_regex_empty_success_bool + \regex_match_once: + \trace_pop:nnx { regex } { 1 } { regex_match } + } +\cs_new_protected_nopar:Npn \regex_match_once: + { + \if_meaning:w \c_true_bool \l_regex_empty_success_bool + \cs_set_nopar:Npn \regex_if_two_empty_matches:F + { \int_compare:nNnF \l_regex_start_pos_int = \l_regex_current_pos_int } + \else: + \cs_set_eq:NN \regex_if_two_empty_matches:F \use:n + \fi: + \int_set_eq:NN \l_regex_start_pos_int \l_regex_success_pos_int + \bool_set_false:N \l_regex_match_success_bool + \prop_clear:N \l_regex_current_submatches_prop + \int_set_eq:NN \l_regex_max_active_int \l_regex_min_active_int + \regex_store_state:n { \l_regex_min_state_int } + \int_set:Nn \l_regex_current_pos_int + { \l_regex_start_pos_int - \c_one } + \regex_query_get: + \regex_match_loop: + \l_regex_every_match_tl + } +\cs_new_protected_nopar:Npn \regex_single_match: + { + \tl_set:Nn \l_regex_every_match_tl + { \bool_gset_eq:NN \g_regex_success_bool \l_regex_match_success_bool } + } +\cs_new_protected:Npn \regex_multi_match:n #1 + { + \tl_set:Nn \l_regex_every_match_tl + { + \if_meaning:w \c_true_bool \l_regex_match_success_bool + \bool_gset_true:N \g_regex_success_bool + #1 + \exp_after:wN \regex_match_once: + \fi: + } + } +\cs_new_protected_nopar:Npn \regex_match_loop: + { + \tex_advance:D \l_regex_step_int \c_two + \int_incr:N \l_regex_current_pos_int + \int_set_eq:NN \l_regex_last_char_int \l_regex_current_char_int + \int_set_eq:NN \l_regex_case_changed_char_int \c_max_int + \regex_query_get: + \use:x + { + \int_set_eq:NN \l_regex_max_active_int \l_regex_min_active_int + \exp_after:wN \regex_match_one_active:w + \int_use:N \l_regex_min_active_int ; + } + \prg_break_point:n { \bool_set_false:N \l_regex_fresh_thread_bool } + \if_num:w \l_regex_max_active_int > \l_regex_min_active_int + \if_num:w \l_regex_current_pos_int < \l_regex_max_pos_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_match_loop: + \fi: + \fi: + } +\cs_new:Npn \regex_match_one_active:w #1; + { + \if_num:w #1 < \l_regex_max_active_int + \regex_use_state_and_submatches:nn + { \int_value:w \tex_skip:D #1 } + { \tex_the:D \tex_toks:D #1 } + \exp_after:wN \regex_match_one_active:w + \int_use:N \int_eval:w #1 + \c_one \exp_after:wN ; + \fi: + } +\cs_new_protected:Npn \regex_query_set:nnn #1#2#3 + { + \tex_muskip:D \l_regex_current_pos_int + = \etex_gluetomu:D + #3 sp + plus #2 sp + minus \l_regex_balance_int sp + \scan_stop: + \tex_toks:D \l_regex_current_pos_int {#1} + \int_incr:N \l_regex_current_pos_int + \if_case:w #2 \exp_stop_f: + \or: \int_incr:N \l_regex_balance_int + \or: \int_decr:N \l_regex_balance_int + \fi: + } +\cs_new_protected_nopar:Npn \regex_query_get: + { + \l_regex_current_char_int + = \etex_mutoglue:D \tex_muskip:D \l_regex_current_pos_int + \l_regex_current_catcode_int = \etex_gluestretch:D + \etex_mutoglue:D \tex_muskip:D \l_regex_current_pos_int + } +\cs_new_protected_nopar:Npn \regex_use_state: + { + \trace:nnx { regex } { 2 } { state~\int_use:N \l_regex_current_state_int } + \tex_dimen:D \l_regex_current_state_int + = \l_regex_step_int sp \scan_stop: + \tex_the:D \tex_toks:D \l_regex_current_state_int + \tex_dimen:D \l_regex_current_state_int + = \int_eval:w \l_regex_step_int + \c_one \int_eval_end: sp \scan_stop: + } +\cs_new_protected:Npn \regex_use_state_and_submatches:nn #1 #2 + { + \int_set:Nn \l_regex_current_state_int {#1} + \if_num:w \tex_dimen:D \l_regex_current_state_int < \l_regex_step_int + \tl_set:Nn \l_regex_current_submatches_prop {#2} + \exp_after:wN \regex_use_state: + \fi: + \scan_stop: + } +\cs_new_protected_nopar:Npn \regex_action_start_wildcard: + { + \bool_set_true:N \l_regex_fresh_thread_bool + \regex_action_free:n {1} + \bool_set_false:N \l_regex_fresh_thread_bool + \regex_action_cost:n {0} + } +\cs_new_protected_nopar:Npn \regex_action_free:n + { \regex_action_free_aux:nn { > \l_regex_step_int \else: } } +\cs_new_protected_nopar:Npn \regex_action_free_group:n + { \regex_action_free_aux:nn { < \l_regex_step_int } } +\cs_new_protected:Npn \regex_action_free_aux:nn #1#2 + { + \use:x + { + \int_add:Nn \l_regex_current_state_int {#2} + \exp_not:n + { + \if_num:w \tex_dimen:D \l_regex_current_state_int #1 + \exp_after:wN \regex_use_state: + \fi: + } + \int_set:Nn \l_regex_current_state_int + { \int_use:N \l_regex_current_state_int } + \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop + { \exp_not:o \l_regex_current_submatches_prop } + } + } +\cs_new_protected:Npn \regex_action_cost:n #1 + { + \exp_args:No \regex_store_state:n + { \int_use:N \int_eval:w \l_regex_current_state_int + #1 } + } +\cs_new_protected:Npn \regex_store_state:n #1 + { + \regex_store_submatches: + \tex_skip:D \l_regex_max_active_int = #1 sp \scan_stop: + \int_incr:N \l_regex_max_active_int + } +\cs_new_protected_nopar:Npn \regex_store_submatches: + { + \tex_toks:D \l_regex_max_active_int \exp_after:wN + { \l_regex_current_submatches_prop } + } +\cs_new_protected_nopar:Npn \regex_disable_submatches: + { + \cs_set_protected_nopar:Npn \regex_store_submatches: { } + \cs_set_protected:Npn \regex_action_submatch:n ##1 { } + } +\cs_new_protected:Npn \regex_action_submatch:n #1 + { + \prop_put:Nno \l_regex_current_submatches_prop {#1} + { \int_use:N \l_regex_current_pos_int } + } +\cs_new_protected_nopar:Npn \regex_action_success: + { + \regex_if_two_empty_matches:F + { + \bool_set_true:N \l_regex_match_success_bool + \bool_set_eq:NN \l_regex_empty_success_bool + \l_regex_fresh_thread_bool + \int_set_eq:NN \l_regex_success_pos_int \l_regex_current_pos_int + \prop_set_eq:NN \l_regex_success_submatches_prop + \l_regex_current_submatches_prop + \prg_map_break: + } + } +\int_new:N \l_regex_replacement_csnames_int +\tl_new:N \l_regex_balance_tl +\cs_new:Npn \regex_replacement_balance_one_match:n #1 + { - \regex_submatch_balance:n {#1} } +\cs_new:Npn \regex_replacement_do_one_match:n #1 + { + \regex_query_range:nn + { \etex_glueshrink:D \tex_skip:D #1 } + { \tex_skip:D #1 } + } +\cs_new:Npn \regex_replacement_exp_not:N #1 { \exp_not:n {#1} } +\cs_new:Npn \regex_query_range:nn #1#2 + { + \exp_after:wN \regex_query_range_loop:ww + \int_use:N \int_eval:w #1 \exp_after:wN ; + \int_use:N \int_eval:w #2 ; + \prg_break_point:n { } + } +\cs_new:Npn \regex_query_range_loop:ww #1 ; #2 ; + { + \if_num:w #1 < #2 \exp_stop_f: + \else: + \exp_after:wN \prg_map_break: + \fi: + \tex_the:D \tex_toks:D #1 \exp_stop_f: + \exp_after:wN \regex_query_range_loop:ww + \int_use:N \int_eval:w #1 + \c_one ; #2 ; + } +\cs_new:Npn \regex_query_submatch:n #1 + { + \regex_query_range:nn + { \tex_skip:D \int_eval:w #1 } + { \etex_gluestretch:D \tex_skip:D \int_eval:w #1 } + } +\cs_new_protected:Npn \regex_submatch_balance:n #1 + { + \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D + \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1 + - \tex_muskip:D \tex_skip:D #1 + \scan_stop: + } +\cs_new_protected:Npn \regex_replacement:n #1 + { + \trace_push:nnn { regex } { 1 } { regex_replacement:n } + \tl_set_build:Nw \l_regex_internal_a_tl + \int_zero:N \l_regex_balance_int + \tl_clear:N \l_regex_balance_tl + \regex_escape_use:nnnn + { + \if_charcode:w \c_rbrace_str ##1 + \regex_replacement_rbrace:N \else: \tl_build_one:n \fi: ##1 + } + { \regex_replacement_escaped:N ##1 } + { \tl_build_one:n ##1 } + {#1} + \prg_do_nothing: \prg_do_nothing: + \if_int_compare:w \l_regex_replacement_csnames_int > \c_zero + \msg_kernel_error:nnx { regex } { replacement-missing-rbrace } + { \int_use:N \l_regex_replacement_csnames_int } + \tl_build_one:x + { \prg_replicate:nn \l_regex_replacement_csnames_int \cs_end: } + \fi: + \cs_gset:Npx \regex_replacement_balance_one_match:n ##1 + { + + \int_use:N \l_regex_balance_int + \l_regex_balance_tl + - \regex_submatch_balance:n {##1} + } + \tl_build_end: + \exp_args:No \regex_replacement_aux:n \l_regex_internal_a_tl + \trace_pop:nnn { regex } { 1 } { regex_replacement:n } + } +\cs_new_protected:Npn \regex_replacement_aux:n #1 + { + \cs_set:Npn \regex_replacement_do_one_match:n ##1 + { + \regex_query_range:nn + { \etex_glueshrink:D \tex_skip:D ##1 } + { \tex_skip:D ##1 } + #1 + } + } +\cs_new_protected:Npn \regex_replacement_escaped:N #1 + { + \cs_if_exist_use:cF { regex_replacement_#1:w } + { + \if_num:w \c_one < 1#1 \exp_stop_f: + \regex_replacement_put_submatch:n {#1} + \else: + \tl_build_one:n #1 + \fi: + } + } +\cs_new_protected:Npn \regex_replacement_put_submatch:n #1 + { + \if_num:w #1 < \l_regex_capturing_group_int + \tl_build_one:n { \regex_query_submatch:n { #1 + ##1 } } + \if_num:w \l_regex_replacement_csnames_int = \c_zero + \tl_put_right:Nn \l_regex_balance_tl + { + \regex_submatch_balance:n { \int_eval:w #1+##1 \int_eval_end: } } + \fi: + \fi: + } +\cs_new_protected:Npn \regex_replacement_g:w #1#2 + { + \str_if_eq:xxTF { #1#2 } { \tl_build_one:n \c_lbrace_str } + { + \int_zero:N \l_regex_internal_a_int + \regex_replacement_g_digits:NN + } + { \regex_replacement_error:NNN g #1 #2 } + } +\cs_new_protected:Npn \regex_replacement_g_digits:NN #1#2 + { + \token_if_eq_meaning:NNTF #1 \tl_build_one:n + { + \if_num:w \c_one < 1#2 \exp_stop_f: + \int_set:Nn \l_regex_internal_a_int + { \c_ten * \l_regex_internal_a_int + #2 } + \exp_after:wN \use_i:nnn + \exp_after:wN \regex_replacement_g_digits:NN + \else: + \exp_after:wN \regex_replacement_error:NNN + \exp_after:wN g + \fi: + } + { + \if_meaning:w \regex_replacement_rbrace:N #1 + \exp_args:No \regex_replacement_put_submatch:n + { \int_use:N \l_regex_internal_a_int } + \exp_after:wN \use_none:nn + \else: + \exp_after:wN \regex_replacement_error:NNN + \exp_after:wN g + \fi: + } + #1 #2 + } +\cs_new_protected:Npn \regex_replacement_c:w #1#2 + { + \token_if_eq_meaning:NNTF #1 \tl_build_one:n + { + \cs_if_exist_use:cF { regex_replacement_c_#2:w } + { \regex_replacement_error:NNN c #1#2 } + } + { \regex_replacement_error:NNN c #1#2 } + } +\cs_new_protected_nopar:cpn { regex_replacement_c_ \c_lbrace_str :w } + { + \if_case:w \l_regex_replacement_csnames_int + \tl_build_one:n + { \exp_not:n { \exp_after:wN \regex_replacement_exp_not:N \cs:w } } + \else: + \tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:N \cs:w } } + \fi: + \int_incr:N \l_regex_replacement_csnames_int + } +\cs_new_protected:Npn \regex_replacement_u:w #1#2 + { + \str_if_eq:xxTF { #1#2 } { \tl_build_one:n \c_lbrace_str } + { + \if_case:w \l_regex_replacement_csnames_int + \tl_build_one:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } } + \else: + \tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } } + \fi: + \int_incr:N \l_regex_replacement_csnames_int + } + { \regex_replacement_error:NNN u #1#2 } + } +\cs_new_protected:Npn \regex_replacement_rbrace:N #1 + { + \if_int_compare:w \l_regex_replacement_csnames_int > \c_zero + \tl_build_one:n \cs_end: + \int_decr:N \l_regex_replacement_csnames_int + \else: + \tl_build_one:n #1 + \fi: + } +\group_begin: + \cs_new_protected:Npn \regex_replacement_char:nNN #1#2#3 + { + \if_meaning:w \prg_do_nothing: #3 + \msg_kernel_error:nn { regex } { replacement-catcode-end } + \else: + \tex_lccode:D \c_zero = `#3 \scan_stop: + \tl_to_lowercase:n { \tl_build_one:n {#1} } + \fi: + } + \char_set_catcode_active:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_A:w + { \regex_replacement_char:nNN { \exp_not:n { \exp_not:N ^^@ } } } + \char_set_catcode_group_begin:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_B:w + { + \if_num:w \l_regex_replacement_csnames_int = \c_zero + \int_incr:N \l_regex_balance_int + \fi: + \regex_replacement_char:nNN + { \exp_not:n { \exp_after:wN ^^@ \if_false: } \fi: } } + } + \cs_new_protected:Npn \regex_replacement_c_C:w #1#2 + { \tl_build_one:n { \exp_not:N \exp_not:N \exp_not:c {#2} } } + \char_set_catcode_math_subscript:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_D:w + { \regex_replacement_char:nNN { ^^@ } } + \char_set_catcode_group_end:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_E:w + { + \if_num:w \l_regex_replacement_csnames_int = \c_zero + \int_decr:N \l_regex_balance_int + \fi: + \regex_replacement_char:nNN + { \exp_not:n { \if_false: { \fi: ^^@ } } + } + \char_set_catcode_letter:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_L:w + { \regex_replacement_char:nNN { ^^@ } } + \char_set_catcode_math_toggle:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_M:w + { \regex_replacement_char:nNN { ^^@ } } + \char_set_catcode_other:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_O:w + { \regex_replacement_char:nNN { ^^@ } } + \char_set_catcode_parameter:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_P:w + { + \regex_replacement_char:nNN + { \exp_not:n { \exp_not:n { ^^@^^@^^@^^@ } } } + } + \cs_new_protected:Npn \regex_replacement_c_S:w #1#2 + { + \if_meaning:w \prg_do_nothing: #2 + \msg_kernel_error:nn { regex } { replacement-catcode-end } + \else: + \if_num:w `#2 = \c_zero + \msg_kernel_error:nn { regex } { replacement-null-space } + \fi: + \tex_lccode:D 32 = `#2 \scan_stop: + \tl_to_lowercase:n { \tl_build_one:n {~} } + \fi: + } + \char_set_catcode_alignment:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_T:w + { \regex_replacement_char:nNN { ^^@ } } + \char_set_catcode_math_superscript:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_U:w + { \regex_replacement_char:nNN { ^^@ } } +\group_end: +\cs_new_protected:Npn \regex_replacement_error:NNN #1#2#3 + { + \msg_kernel_error:nnx { regex } { replacement-#1 } {#3} + #2 #3 + } +\cs_new_protected:Npn \regex_new:N #1 + { \cs_new_eq:NN #1 \c_regex_no_match_regex } +\cs_new_protected_nopar:Npn \regex_set:Nn #1#2 + { + \regex_compile:n {#2} + \tl_set_eq:NN #1 \l_regex_internal_regex + } +\cs_new_protected_nopar:Npn \regex_gset:Nn #1#2 + { + \regex_compile:n {#2} + \tl_gset_eq:NN #1 \l_regex_internal_regex + } +\cs_new_protected_nopar:Npn \regex_const:Nn #1#2 + { + \regex_compile:n {#2} + \tl_const:Nx #1 { \exp_not:o \l_regex_internal_regex } + } +\cs_new_protected:Npn \regex_show:n #1 + { + \regex_compile:n {#1} + \regex_show_aux:Nx \l_regex_internal_regex + { { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \regex_show:N #1 + { \regex_show_aux:Nx #1 { variable~\token_to_str:N #1 } } +\prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF } + { + \regex_match_aux:nn { \regex_build:n {#1} } {#2} + \regex_aux_return: + } +\prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF } + { + \regex_match_aux:nn { \regex_build:N #1 } {#2} + \regex_aux_return: + } +\cs_new_protected:Npn \regex_count:nnN #1 + { \regex_count_aux:nnN { \regex_build:n {#1} } } +\cs_new_protected:Npn \regex_count:NnN #1 + { \regex_count_aux:nnN { \regex_build:N #1 } } +\cs_set_protected:Npn \regex_tmp:w #1#2#3 + { + \cs_new_protected:Npn #2 ##1 { #1 { \regex_build:n {##1} } } + \cs_new_protected:Npn #3 ##1 { #1 { \regex_build:N ##1 } } + \prg_new_protected_conditional:Npnn #2 ##1##2##3 { T , F , TF } + { #1 { \regex_build:n {##1} } {##2} ##3 \regex_aux_return: } + \prg_new_protected_conditional:Npnn #3 ##1##2##3 { T , F , TF } + { #1 { \regex_build:N ##1 } {##2} ##3 \regex_aux_return: } + } +\regex_tmp:w \regex_extract_once_aux:nnN + \regex_extract_once:nnN \regex_extract_once:NnN +\regex_tmp:w \regex_extract_all_aux:nnN + \regex_extract_all:nnN \regex_extract_all:NnN +\regex_tmp:w \regex_replace_once_aux:nnN + \regex_replace_once:nnN \regex_replace_once:NnN +\regex_tmp:w \regex_replace_all_aux:nnN + \regex_replace_all:nnN \regex_replace_all:NnN +\regex_tmp:w \regex_split_aux:nnN \regex_split:nnN \regex_split:NnN +\int_new:N \l_regex_match_count_int +\flag_new:n { regex_begin } +\flag_new:n { regex_end } +\int_new:N \l_regex_submatch_int +\int_new:N \l_regex_zeroth_submatch_int +\cs_new_protected_nopar:Npn \regex_aux_return: + { + \if_meaning:w \c_true_bool \g_regex_success_bool + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new_protected:Npn \regex_match_aux:nn #1#2 + { + \group_begin: + \regex_disable_submatches: + \regex_single_match: + #1 + \regex_match:n {#2} + \group_end: + } +\cs_new_protected:Npn \regex_count_aux:nnN #1#2#3 + { + \group_begin: + \regex_disable_submatches: + \int_zero:N \l_regex_match_count_int + \regex_multi_match:n { \int_incr:N \l_regex_match_count_int } + #1 + \regex_match:n {#2} + \exp_args:NNNo + \group_end: + \int_set:Nn #3 { \int_use:N \l_regex_match_count_int } + } +\cs_new_protected:Npn \regex_extract_once_aux:nnN #1#2#3 + { + \group_begin: + \regex_single_match: + #1 + \regex_match:n {#2} + \regex_extract: + \regex_group_end_extract_seq:N #3 + } +\cs_new_protected:Npn \regex_extract_all_aux:nnN #1#2#3 + { + \group_begin: + \regex_multi_match:n { \regex_extract: } + #1 + \regex_match:n {#2} + \regex_group_end_extract_seq:N #3 + } +\cs_new_protected:Npn \regex_split_aux:nnN #1#2#3 + { + \group_begin: + \regex_multi_match:n + { + \if_num:w \l_regex_start_pos_int < \l_regex_success_pos_int + \regex_extract: + \tex_skip:D \l_regex_zeroth_submatch_int + = \l_regex_start_pos_int sp + plus \tex_skip:D \l_regex_zeroth_submatch_int \scan_stop: + \fi: + } + #1 + \regex_match:n {#2} + \tex_skip:D \l_regex_submatch_int + = \l_regex_start_pos_int sp plus \l_regex_max_pos_int sp \scan_stop: + \int_incr:N \l_regex_submatch_int + \if_meaning:w \c_true_bool \l_regex_empty_success_bool + \if_num:w \l_regex_start_pos_int = \l_regex_max_pos_int + \int_decr:N \l_regex_submatch_int + \fi: + \fi: + \regex_group_end_extract_seq:N #3 + } +\cs_new_protected:Npn \regex_group_end_extract_seq:N #1 + { + \cs_set_eq:NN \seq_item:n \scan_stop: + \flag_clear:n { regex_begin } + \flag_clear:n { regex_end } + \tl_set:Nx \l_regex_internal_a_tl + { + \prg_stepwise_function:nnnN + { \c_two * \l_regex_max_state_int } + \c_one + { \l_regex_submatch_int - \c_one } + \regex_extract_seq_aux:n + } + \int_compare:nNnF + { \flag_height:n { regex_begin } + \flag_height:n { regex_end } } + = \c_zero + { + \msg_kernel_error:nnxxx { regex } { result-unbalanced } + { splitting~or~extracting~submatches } + { \flag_height:n { regex_end } } + { \flag_height:n { regex_begin } } + } + \use:x + { + \group_end: + \tl_set:Nn \exp_not:N #1 { \l_regex_internal_a_tl } + } + } +\cs_new:Npn \regex_extract_seq_aux:n #1 + { + \seq_item:n + { + \exp_after:wN \regex_extract_seq_aux:ww + \int_value:w \regex_submatch_balance:n {#1} ; #1; + } + } +\cs_new:Npn \regex_extract_seq_aux:ww #1; #2; + { + \if_num:w #1 < \c_zero + \flag_raise:n { regex_end } + \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } } + \fi: + \regex_query_submatch:n {#2} + \if_num:w #1 > \c_zero + \flag_raise:n { regex_begin } + \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } } + \fi: + } +\cs_new_protected_nopar:Npn \regex_extract: + { + \if_meaning:w \c_true_bool \g_regex_success_bool + \int_set_eq:NN \l_regex_zeroth_submatch_int \l_regex_submatch_int + \prg_replicate:nn \l_regex_capturing_group_int + { + \tex_skip:D \l_regex_submatch_int \c_zero sp \scan_stop: + \int_incr:N \l_regex_submatch_int + } + \prop_map_inline:Nn \l_regex_success_submatches_prop + { + \if_num:w ##1 \c_minus_one + \exp_after:wN \regex_extract_aux_e:wn \int_value:w + \else: + \exp_after:wN \regex_extract_aux_b:wn \int_value:w + \fi: + \int_eval:w \l_regex_zeroth_submatch_int + ##1 {##2} + } + \tex_skip:D \l_regex_zeroth_submatch_int + = \tex_the:D \tex_skip:D \l_regex_zeroth_submatch_int + minus \l_regex_start_pos_int sp \scan_stop: + \fi: + } +\cs_new_protected:Npn \regex_extract_aux_b:wn #1 < #2 + { + \tex_skip:D #1 = #2 sp + plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop: + } +\cs_new_protected:Npn \regex_extract_aux_e:wn #1 > #2 + { + \tex_skip:D #1 + = 1 \tex_skip:D #1 plus #2 sp \scan_stop: + } +\cs_new_protected:Npn \regex_replace_once_aux:nnN #1#2#3 + { + \group_begin: + \regex_single_match: + #1 + \regex_replacement:n {#2} + \exp_args:No \regex_match:n { #3 } + \if_meaning:w \c_false_bool \g_regex_success_bool + \group_end: + \else: + \regex_extract: + \int_set:Nn \l_regex_balance_int + { + \regex_replacement_balance_one_match:n + { \l_regex_zeroth_submatch_int } + } + \tl_set:Nx \l_regex_internal_a_tl + { + \regex_replacement_do_one_match:n { \l_regex_zeroth_submatch_int } + \regex_query_range:nn + { \etex_gluestretch:D \tex_skip:D \l_regex_zeroth_submatch_int } + { \l_regex_max_pos_int } + } + \regex_group_end_replace:N #3 + \fi: + } +\cs_new_protected:Npn \regex_replace_all_aux:nnN #1#2#3 + { + \group_begin: + \regex_multi_match:n { \regex_extract: } + #1 + \regex_replacement:n {#2} + \exp_args:No \regex_match:n {#3} + \int_set:Nn \l_regex_balance_int + { + 0 + \prg_stepwise_function:nnnN + { \c_two * \l_regex_max_state_int } + \l_regex_capturing_group_int + { \l_regex_submatch_int - \c_one } + \regex_replacement_balance_one_match:n + } + \tl_set:Nx \l_regex_internal_a_tl + { + \prg_stepwise_function:nnnN + { \c_two * \l_regex_max_state_int } + \l_regex_capturing_group_int + { \l_regex_submatch_int - \c_one } + \regex_replacement_do_one_match:n + \regex_query_range:nn + \l_regex_start_pos_int \l_regex_max_pos_int + } + \regex_group_end_replace:N #3 + } +\cs_new_protected_nopar:Npn \regex_group_end_replace:N #1 + { + \if_num:w \l_regex_balance_int = \c_zero + \else: + \msg_kernel_error:nnxxx { regex } { result-unbalanced } + { replacing } + { \int_max:nn { - \l_regex_balance_int } { \c_zero } } + { \int_max:nn { \l_regex_balance_int } { \c_zero } } + \fi: + \use:x + { + \group_end: + \tl_set:Nn \exp_not:N #1 + { + \if_int_compare:w \l_regex_balance_int < \c_zero + \prg_replicate:nn { - \l_regex_balance_int } + { { \if_false: } \fi: } + \fi: + \l_regex_internal_a_tl + \if_int_compare:w \l_regex_balance_int > \c_zero + \prg_replicate:nn { \l_regex_balance_int } + { \if_false: { \fi: } } + \fi: + } + } + } +\msg_kernel_new:nnnn { regex } { trailing-backslash } + { Trailing~escape~character~\iow_char:N\\. } + { + A~regular~expression~or~its~replacement~text~ends~with~ + the~escape~character~\iow_char:N\\.~It~will~be~ignored. + } +\msg_kernel_new:nnnn { regex } { x-missing-rbrace } + { Missing~closing~brace~in~\iow_char:N\\x~hexadecimal~sequence. } + { + You~wrote~something~like~ + `\iow_char:N\\x\{\int_to_hexadecimal:n{#1}'.~ + The~closing~brace~is~missing. + } +\msg_kernel_new:nnnn { regex } { x-overflow } + { Character~code~'#1'~too~large~in~\iow_char:N\\x~hexadecimal~sequence. } + { + You~wrote~something~like~ + `\iow_char:N\\x\{\int_to_hexadecimal:n{#1}\}'.~ + The~character~code~'#1'~is~larger~than~\int_use:N \c_max_char_int. + } +\msg_kernel_new:nnnn { regex } { invalid-quantifier } + { Braced~quantifier~'#1'~may~not~be~followed~by~'#2'. } + { + The~character~'#2'~is~invalid~in~the~braced~quantifier~'#1'.~ + The~only~valid~quantifiers~are~'*',~'?',~'+',~'{<int>}',~ + '{<min>,}'~and~'{<min>,<max>}',~followed~or~not~by~'?'. + } +\msg_kernel_new:nnnn { regex } { missing-rbrack } + { Missing~right~bracket~inserted~in~regular~expression. } + { + LaTeX~was~given~a~regular~expression~where~a~character~class~ + was~started~with~'[',~but~the~matching~']'~is~missing. + } +\msg_kernel_new:nnnn { regex } { missing-rparen } + { + Missing~right~parenthes\int_compare:nTF{#1=1}{i}{e}s~ + inserted~in~regular~expression. + } + { + LaTeX~was~given~a~regular~expression~with~\int_eval:n{#1}~ + more~left~parenthes\int_compare:nTF{#1=1}{i}{e}s~than~right~ + parenthes\int_compare:nTF{#1=1}{i}{e}s. + } +\msg_kernel_new:nnnn { regex } { extra-rparen } + { Extra~right~parenthesis~ignored~in~regular~expression. } + { + LaTeX~came~across~a~closing~parenthesis~when~no~submatch~group~ + was~open.~The~parenthesis~will~be~ignored. + } +\msg_kernel_new:nnnn { regex } { bad-escape } + { + Invalid~escape~\c_backslash_str #1~ + \regex_if_in_cs:TF { within~a~control~sequence. } + { + \regex_if_in_class:TF + { in~a~character~class. } + { following~a~category~test. } + } + } + { + The~escape~sequence~\iow_char:N\\#1~may~not~appear~ + \regex_if_in_cs:TF + { + within~a~control~sequence~test~introduced~by~ + \iow_char:N\\c\iow_char:N\{. + } + { + \regex_if_in_class:TF + { within~a~character~class~ } + { following~a~category~test~such~as~\iow_char:N\\cL~ } + because~it~does~not~match~exactly~one~character. + } + } +\msg_kernel_new:nnnn { regex } { range-missing-end } + { Invalid~end-point~for~range~'#1-#2'~in~character~class. } + { + The~end-point~'#2'~of~the~range~'#1-#2'~may~not~serve~as~an~ + end-point~for~a~range:~alphanumeric~characters~should~not~be~ + escaped,~and~non-alphanumeric~characters~should~be~escaped. + } +\msg_kernel_new:nnnn { regex } { range-backwards } + { Range~[#1-#2]~out~of~order~in~character~class. } + { + In~ranges~of~characters~[x-y]~appearing~in~character~classes,~ + the~first~character~code~must~not~be~larger~than~the~second.~ + Here,~#1~has~character~code~\int_eval:n {`#1},~while~#2~has~ + character~code~\int_eval:n {`#2}. + } +\msg_kernel_new:nnnn { regex } { c-bad-mode } + { Invalid~nested~\iow_char:N\\c~escape~in~regular~expression. } + { + The~\iow_char:N\\c~escape~cannot~be~used~within~ + a~control~sequence~test~'\iow_char:N\\c{...}'.~ + To~combine~several~category~tests,~use~'\iow_char:N\\c[...]'. + } +\msg_kernel_new:nnnn { regex } { c-missing-rbrace } + { Missing~right~brace~inserted~for~\iow_char:N\\c~escape. } + { + LaTeX~was~given~a~regular~expression~where~a~ + '\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~ + with~a~closing~brace~'\iow_char:N\}'. + } +\msg_kernel_new:nnnn { regex } { c-missing-rbrack } + { Missing~right~bracket~inserted~for~\iow_char:N\\c~escape. } + { + A~construction~'\iow_char:N\\c[...'~appears~in~a~ + regular~expression,~but~the~closing~']'~is~not~present. + } +\msg_kernel_new:nnnn { regex } { c-missing-category } + { Invalid~character~'#1'~following~\iow_char:N\\c~escape. } + { + In~regular~expressions,~the~\iow_char:N\\c~escape~sequence~ + may~only~be~followed~by~a~left~brace,~a~left~bracket,~or~a~ + capital~letter~representing~a~character~category,~namely~ + one~of~ABCDELMOPSTU. + } +\msg_kernel_new:nnnn { regex } { u-missing-lbrace } + { Missing~left~brace~following~\iow_char:N\\u~escape. } + { + The~\iow_char:N\\u~escape~sequence~must~be~followed~by~ + a~brace~group~with~the~name~of~the~variable~to~use. + } +\msg_kernel_new:nnnn { regex } { u-missing-rbrace } + { Missing~right~brace~inserted~for~\iow_char:N\\u~escape. } + { + LaTeX~ + \tl_if_empty:xTF {#2} + { reached~the~end~of~the~string~ } + { encountered~an~escaped~alphanumeric~character '\iow_char:N\\#2'~ } + when~parsing~the~argument~of~an~'\iow_char:N\\u\iow_char:N\{...\}'~escape. + } +\msg_kernel_new:nnnn { regex } { posix-unsupported } + { POSIX~collating~element~'[#1 ~ #1]'~not~supported. } + { + The~[.foo.]~and~[=bar=]~syntaxes~have~a~special~meaning~in~POSIX~ + regular~expressions.~This~is~not~supported~by~LaTeX.~Maybe~you~ + forgot~to~escape~a~left~bracket~in~a~character~class? + } +\msg_kernel_new:nnnn { regex } { posix-unknown } + { POSIX~class~[:#1:]~unknown. } + { + [:#1:]~is~not~among~the~known~POSIX~classes~ + [:alnum:],~[:alpha:],~[:ascii:],~[:blank:],~ + [:cntrl:],~[:digit:],~[:graph:],~[:lower:],~ + [:print:],~[:punct:],~[:space:],~[:upper:],~ + [:word:],~and~[:xdigit:]. + } +\msg_kernel_new:nnnn { regex } { posix-missing-close } + { Missing~closing~':]'~for~POSIX~class. } + { The~POSIX~syntax~'#1'~must~be~followed~by~':]',~not~'#2'. } +\msg_kernel_new:nnnn { regex } { result-unbalanced } + { Missing~brace~inserted~when~#1. } + { + LaTeX~was~asked~to~do~some~regular~expression~operation,~ + and~the~resulting~token~list~would~not~have~the~same~number~ + of~begin-group~and~end-group~tokens.~Braces~were~inserted:~ + #2~left,~#3~right. + } +\msg_kernel_new:nnnn { regex } { unknown-option } + { Unknown~option~`#1'~for~regular~expressions. } + { + The~only~available~option~is~'case-insensitive',~toggled~by~ + '(?i)'~and~'(?-i)'. + } +\msg_kernel_new:nnnn { regex } { replacement-c } + { Misused~\iow_char:N\\c~command~in~a~replacement~text. } + { + In~a~replacement~text,~the~\iow_char:N\\c~escape~sequence~ + can~be~followed~by~one~of~the~letters~ABCDELMOPSTU~ + or~a~brace~group,~not~by~'#1'. + } +\msg_kernel_new:nnnn { regex } { replacement-u } + { Misused~\iow_char:N\\u~command~in~a~replacement~text. } + { + In~a~replacement~text,~the~\iow_char:N\\u~escape~sequence~ + must~be~~followed~by~a~brace~group~holding~the~name~of~the~ + variable~to~use. + } +\msg_kernel_new:nnnn { regex } { replacement-g } + { Missing~brace~for~the~\iow_char:N\\g~construction~in~a~replacement~text. } + { + In~the~replacement~text~for~a~regular~expression~search,~ + submatches~are~represented~either~as~\iow_char:N \\g{dd..d},~ + or~\\d,~where~`d'~are~single~digits.~Here,~a~brace~is~missing. + } +\msg_kernel_new:nnnn { regex } { replacement-catcode-end } + { + Missing~character~for~the~\iow_char:N\\c<category><character>~ + construction~in~a~replacement~text. + } + { + In~a~replacement~text,~the~\iow_char:N\\c~escape~sequence~ + can~be~followed~by~one~of~the~letters~ABCDELMOPSTU~representing~ + the~character~category.~Then,~a~character~must~follow.~LaTeX~ + reached~the~end~of~the~replacement~when~looking~for~that. + } +\msg_kernel_new:nnnn { regex } { replacement-null-space } + { TeX~cannot~build~a~space~token~with~character~code~0. } + { + You~asked~for~a~character~token~with~category~'space',~ + and~character~code~0,~for~instance~through~ + '\iow_char:N\\cS\iow_char:N\\x00'.~ + This~specific~case~is~impossible~and~will~be~replaced~ + by~a~normal~space. + } +\msg_kernel_new:nnnn { regex } { replacement-missing-rbrace } + { Missing~right~brace~inserted~in~replacement~text. } + { + There~were~\int_use:N \l_regex_replacement_csnames_int \ + missing~right~braces. + } +\cs_new:Npn \regex_msg_repeated:nnN #1#2#3 + { + \str_if_eq:xxF { #1 #2 } { 1 0 } + { + , ~ repeated ~ + \prg_case_int:nnn {#2} + { + { -1 } { #1~or~more~times,~\bool_if:NTF #3 { lazy } { greedy } } + { 0 } { #1~times } + } + { + between~#1~and~\int_eval:n {#1+#2}~times,~ + \bool_if:NTF #3 { lazy } { greedy } + } + } + } +\cs_new_protected:Npn \regex_trace_states:n #1 + { + \prg_stepwise_inline:nnnn + \l_regex_min_state_int + \c_one + { \l_regex_max_state_int - 1 } + { + \trace:nnx { regex } { #1 } + { \iow_char:N \\toks ##1 = { \tex_the:D \tex_toks:D ##1 } } + } + } +%% +%% +%% End of file `l3regex-trace.sty'. diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty index 2b99a8eb661..17480334049 100644 --- a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty +++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty @@ -46,236 +46,35 @@ %% %% ----------------------------------------------------------------------- \RequirePackage{expl3} -\GetIdInfo$Id: l3regex.dtx 3326 2012-02-07 00:39:44Z bruno $ +\GetIdInfo$Id: l3regex.dtx 3463 2012-02-26 15:05:14Z bruno $ {L3 Experimental Regular Expressions} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\RequirePackage{l3str, l3tl-analysis, l3flag} +\RequirePackage{l3tl-build, l3tl-analysis, l3flag, l3str} +\cs_generate_variant:Nn \tl_to_str:n { V } \cs_new:Npn \regex_tmp:w { } \tl_new:N \l_regex_internal_a_tl \tl_new:N \l_regex_internal_b_tl \int_new:N \l_regex_internal_a_int \int_new:N \l_regex_internal_b_int \int_new:N \l_regex_internal_c_int +\bool_new:N \l_regex_internal_bool +\seq_new:N \l_regex_internal_seq \tl_new:N \g_regex_internal_tl -\tl_const:Nn \c_regex_d_tl - { \regex_item_range:nn \c_forty_eight { 57 } } % 0--9 -\tl_const:Nn \c_regex_h_tl - { - \regex_item_equal:n \c_thirty_two % space - \regex_item_equal:n \c_nine % tab - } -\tl_const:Nn \c_regex_s_tl - { - \regex_item_equal:n \c_thirty_two % space - \regex_item_equal:n \c_nine % tab - \regex_item_equal:n \c_ten % lf - \regex_item_equal:n \c_twelve % ff - \regex_item_equal:n \c_thirteen % cr - } -\tl_const:Nn \c_regex_v_tl - { \regex_item_range:nn \c_ten \c_thirteen } % lf, vtab, ff, cr -\tl_const:Nn \c_regex_w_tl - { - \regex_item_range:nn \c_ninety_seven { 122 } % a--z - \regex_item_range:nn \c_sixty_five { 90 } % A--Z - \regex_item_range:nn \c_forty_eight { 57 } % 0--9 - \regex_item_equal:n { 95 } % _ - } -\tl_const:Nn \c_regex_D_tl - { \c_regex_d_tl \regex_break_point:TF { } \regex_break_true:w } -\tl_const:Nn \c_regex_H_tl - { \c_regex_h_tl \regex_break_point:TF { } \regex_break_true:w } -\tl_const:Nn \c_regex_S_tl - { \c_regex_s_tl \regex_break_point:TF { } \regex_break_true:w } -\tl_const:Nn \c_regex_V_tl - { \c_regex_v_tl \regex_break_point:TF { } \regex_break_true:w } -\tl_const:Nn \c_regex_W_tl - { \c_regex_w_tl \regex_break_point:TF { } \regex_break_true:w } -\tl_const:Nn \c_regex_N_tl - { - \regex_item_equal:n \c_ten - \regex_break_point:TF { } { \regex_break_true:w } - } -\tl_const:cn { c_regex_._tl } - { - \if_num:w \l_regex_current_char_int > - \c_two - \exp_after:wN \regex_break_true:w - \fi: - } -\int_new:N \l_regex_build_mode_int -\int_new:N \l_regex_max_state_int -\int_new:N \l_regex_left_state_int -\int_new:N \l_regex_right_state_int -\seq_new:N \l_regex_left_state_seq -\seq_new:N \l_regex_right_state_seq -\seq_new:N \l_regex_end_group_seq -\seq_new:N \l_regex_end_alternation_seq -\int_new:N \l_regex_capturing_group_int -\seq_new:N \l_regex_capturing_group_seq -\int_new:N \l_regex_capturing_group_max_int -\tl_new:N \l_regex_one_or_group_tl -\int_new:N \l_regex_catcodes_int -\int_new:N \l_regex_catcodes_default_int -\int_const:Nn \c_regex_catcode_C_int { "1 } -\int_const:Nn \c_regex_catcode_B_int { "4 } -\int_const:Nn \c_regex_catcode_E_int { "10 } -\int_const:Nn \c_regex_catcode_M_int { "40 } -\int_const:Nn \c_regex_catcode_T_int { "100 } -\int_const:Nn \c_regex_catcode_P_int { "1000 } -\int_const:Nn \c_regex_catcode_U_int { "4000 } -\int_const:Nn \c_regex_catcode_D_int { "10000 } -\int_const:Nn \c_regex_catcode_S_int { "100000 } -\int_const:Nn \c_regex_catcode_L_int { "400000 } -\int_const:Nn \c_regex_catcode_O_int { "1000000 } -\int_const:Nn \c_regex_catcode_A_int { "4000000 } -\int_const:Nn \c_regex_catcodes_all_int { "5515155 } -\bool_new:N \l_regex_catcodes_bool -\bool_new:N \l_regex_tests_bool -\tl_new:N \l_regex_tests_tl -\bool_new:N \l_regex_tests_saved_bool -\tl_new:N \l_regex_tests_saved_tl -\int_new:N \l_regex_catcodes_saved_int -\int_new:N \l_regex_min_index_int -\int_new:N \l_regex_max_index_int -\int_new:N \l_regex_nesting_int -\int_new:N \l_regex_current_index_int -\int_new:N \l_regex_start_index_int -\int_new:N \l_regex_success_index_int -\int_new:N \l_regex_current_char_int -\int_new:N \l_regex_current_catcode_int -\tl_new:N \l_regex_current_token_tl -\int_new:N \l_regex_last_char_int -\int_new:N \l_regex_case_changed_char_int -\bool_new:N \l_regex_caseless_bool -\int_new:N \l_regex_current_state_int -\prop_new:N \l_regex_current_submatches_prop -\prop_new:N \l_regex_success_submatches_prop -\int_new:N \l_regex_step_int -\int_new:N \l_regex_max_active_int -\tl_new:N \l_regex_every_match_tl -\bool_new:N \l_regex_fresh_thread_bool -\bool_new:N \l_regex_success_empty_bool -\cs_new_eq:NN \regex_if_two_empty_matches:F \use:n -\bool_new:N \g_regex_success_bool -\bool_new:N \l_regex_saved_success_bool -\bool_new:N \l_regex_success_match_bool \tl_const:Nn \c_regex_no_match_regex { - \regex_nfa:Nw \c_regex_no_match_regex - \l_regex_max_state_int = \c_one - \l_regex_capturing_group_int = \c_zero - \tex_toks:D \c_zero { \s_stop } - \s_stop - } -\cs_new_protected:Npn \regex_new:N #1 - { - \chk_if_free_cs:N #1 - \cs_gset_eq:NN #1 \c_regex_no_match_regex - } -\regex_new:N \l_regex_internal_regex -\int_new:N \l_regex_replacement_csnames_int -\int_new:N \l_regex_replacement_int -\int_new:N \l_regex_submatch_int -\int_new:N \l_regex_submatch_start_int -\int_new:N \l_regex_match_count_int -\flag_new:n { regex_begin } -\flag_new:n { regex_end } -\cs_new_protected:Npn \regex_toks_put_left:Nx #1#2 - { - \cs_set_nopar:Npx \regex_tmp:w \s_stop { \s_stop #2 } - \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN - { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 } - } -\cs_new_protected:Npn \regex_toks_put_right:Nx #1#2 - { - \cs_set_nopar:Npx \regex_tmp:w {#2} - \tex_toks:D #1 \exp_after:wN - { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w } - } -\cs_new:Npn \regex_toks_range:nn #1#2 - { - \exp_after:wN \regex_toks_range:ww - \int_use:N \int_eval:w #1 \exp_after:wN ; - \int_use:N \int_eval:w #2 ; - \prg_break_point:n { } - } -\cs_new:Npn \regex_toks_range:ww #1 ; #2 ; - { - \if_num:w #1 < #2 \exp_stop_f: - \else: - \exp_after:wN \prg_map_break: - \fi: - \tex_the:D \tex_toks:D #1 \exp_stop_f: - \exp_after:wN \regex_toks_range:ww - \int_use:N \int_eval:w #1 + \c_one ; #2 ; - } -\cs_new:Npn \regex_query_submatch:nn #1#2 - { - \if_num:w #1 < \l_regex_capturing_group_int - \exp_after:wN \regex_query_submatch:w - \int_use:N \int_eval:w #1 + #2 ; - \fi: - } -\cs_new:Npn \regex_query_submatch:w #1 ; - { - \regex_toks_range:nn - { \tex_skip:D #1 } - { \etex_gluestretch:D \tex_skip:D #1 } - } -\cs_new_protected:Npn \regex_seq_pop_int:NN #1#2 - { - \seq_pop:NN #1 \l_regex_internal_a_tl - \int_set:Nn #2 \l_regex_internal_a_tl - } -\cs_new_protected:Npn \regex_seq_get_int:NN #1#2 - { - \seq_get:NN #1 \l_regex_internal_a_tl - \int_set:Nn #2 \l_regex_internal_a_tl - } -\cs_new_protected:Npn \regex_seq_push_int:NN #1#2 - { \seq_push:No #1 { \int_use:N #2 } } -\cs_new_protected:Npn \regex_seq_pop_use:N #1 - { - \seq_pop:NN #1 \l_regex_internal_a_tl - \l_regex_internal_a_tl - } -\cs_new_protected:Npn \regex_seq_get_use:N #1 - { - \seq_get:NN #1 \l_regex_internal_a_tl - \l_regex_internal_a_tl - } -\cs_new_protected:Npn \regex_get_digits:nw #1 - { - \tex_afterassignment:D \regex_tmp:w - \cs_set_nopar:Npx \regex_tmp:w - { - \exp_not:n {#1} - { \if_false: } } \fi: - \regex_get_digits_aux:NN - } -\cs_new:Npn \regex_get_digits_aux:NN #1#2 - { - \if_meaning:w \regex_build_raw:N #1 - \if_num:w 9 < 1 \exp_not:N #2 \exp_stop_f: - #2 - \else: - \regex_get_digits_end:w #1 #2 - \fi: - \else: - \regex_get_digits_end:w #1 #2 - \fi: - \regex_get_digits_aux:NN - } -\cs_new:Npn \regex_get_digits_end:w #1 \fi: #2 \regex_get_digits_aux:NN - { - \fi: #2 - \if_false: { { \fi: } } - #1 + \regex_branch:n + { \regex_class:NnnnN \c_true_bool { } { 1 } { 0 } \c_true_bool } } +\int_new:N \l_regex_balance_int \cs_new_protected:Npn \regex_break_true:w #1 \regex_break_point:TF #2 #3 {#2} \cs_new_protected:Npn \regex_break_point:TF #1 #2 { #2 } +\cs_new_protected:Npn \regex_item_reverse:n #1 + { + #1 + \regex_break_point:TF { } \regex_break_true:w + } \cs_new_protected:Npn \regex_item_caseful_equal:n #1 { \if_num:w #1 = \l_regex_current_char_int @@ -290,17 +89,14 @@ \fi: \fi: } -\cs_new_protected:Npn \regex_item_caseful_geq:n #1 - { - \reverse_if:N \if_num:w #1 > \l_regex_current_char_int - \exp_after:wN \regex_break_true:w - \fi: - } \cs_new_protected:Npn \regex_item_caseless_equal:n #1 { \if_num:w #1 = \l_regex_current_char_int \exp_after:wN \regex_break_true:w \fi: + \if_num:w \l_regex_case_changed_char_int = \c_max_int + \regex_compute_case_changed_char: + \fi: \if_num:w #1 = \l_regex_case_changed_char_int \exp_after:wN \regex_break_true:w \fi: @@ -312,38 +108,34 @@ \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w \fi: \fi: + \if_num:w \l_regex_case_changed_char_int = \c_max_int + \regex_compute_case_changed_char: + \fi: \reverse_if:N \if_num:w #1 > \l_regex_case_changed_char_int \reverse_if:N \if_num:w #2 < \l_regex_case_changed_char_int \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w \fi: \fi: } -\cs_new_protected:Npn \regex_item_caseless_geq:n #1 +\cs_new_protected_nopar:Npn \regex_compute_case_changed_char: { - \reverse_if:N \if_num:w #1 > \l_regex_current_char_int - \exp_after:wN \regex_break_true:w - \fi: - \reverse_if:N \if_num:w #1 > \l_regex_case_changed_char_int - \exp_after:wN \regex_break_true:w + \int_set_eq:NN \l_regex_case_changed_char_int \l_regex_current_char_int + \if_num:w \l_regex_current_char_int < \c_ninety_one + \if_num:w \l_regex_current_char_int < \c_sixty_five + \else: + \int_add:Nn \l_regex_case_changed_char_int { \c_thirty_two } + \fi: + \else: + \if_num:w \l_regex_current_char_int < \c_one_hundred_twenty_three + \if_num:w \l_regex_current_char_int < \c_ninety_seven + \else: + \int_sub:Nn \l_regex_case_changed_char_int { \c_thirty_two } + \fi: + \fi: \fi: } -\cs_new:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } -\cs_new:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } -\cs_new:Npn \regex_item_geq:n { \regex_item_caseful_geq:n } -\cs_new_protected_nopar:Npn \regex_build_caseless: - { - \bool_set_true:N \l_regex_caseless_bool - \cs_set:Npn \regex_item_equal:n { \regex_item_caseless_equal:n } - \cs_set:Npn \regex_item_range:nn { \regex_item_caseless_range:nn } - \cs_set:Npn \regex_item_geq:n { \regex_item_caseless_geq:n } - } -\cs_new_protected_nopar:Npn \regex_build_caseful: - { - \bool_set_false:N \l_regex_caseless_bool - \cs_set:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } - \cs_set:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } - \cs_set:Npn \regex_item_geq:n { \regex_item_caseful_geq:n } - } +\cs_new_eq:NN \regex_item_equal:n ? +\cs_new_eq:NN \regex_item_range:nn ? \cs_new_protected:Npn \regex_item_catcode_aux: { " @@ -362,44 +154,134 @@ \exp_after:wN \use_none:n \fi: } -\cs_new_protected:Npn \regex_item_cs:n #1 +\cs_new_protected:Npn \regex_item_catcode_reverse:nT #1#2 + { \regex_item_catcode:nT {#1} { \regex_item_reverse:n {#2} } } +\cs_new_protected:Npn \regex_item_exact:nn #1#2 { - \int_compare:nNnT \l_regex_current_catcode_int = \c_zero + \if_num:w #1 = \l_regex_current_catcode_int + \if_num:w #2 = \l_regex_current_char_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w + \fi: + \fi: + } +\cs_new_protected:Npn \regex_item_exact_cs:c #1 + { + \int_compare:nNnTF \l_regex_current_catcode_int = \c_zero { - \tl_set:Nn \l_regex_internal_regex {#1} - \bool_set_eq:NN \l_regex_saved_success_bool \g_regex_success_bool - \exp_args:NNx \regex_match:NnTF \l_regex_internal_regex + \str_if_eq:xxTF { - \exp_after:wN \exp_after:wN - \exp_after:wN \cs_to_str:N \l_regex_current_token_tl + \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N + \tex_the:D \tex_toks:D \l_regex_current_pos_int } - { - \bool_gset_eq:NN \g_regex_success_bool \l_regex_saved_success_bool - \regex_break_true:w - } - { \bool_gset_eq:NN \g_regex_success_bool \l_regex_saved_success_bool } + { #1 } + { \regex_break_true:w } { } } + { } + } +\cs_new_protected:Npn \regex_item_cs:n #1 + { + \int_compare:nNnT \l_regex_current_catcode_int = \c_zero + { + \group_begin: + \regex_single_match: + \regex_disable_submatches: + \regex_build_for_cs:n {#1} + \bool_set_eq:NN \l_regex_saved_success_bool \g_regex_success_bool + \exp_args:Nx \regex_match:n + { + \exp_after:wN \exp_after:wN + \exp_after:wN \cs_to_str:N + \tex_the:D \tex_toks:D \l_regex_current_pos_int + } + \if_meaning:w \c_true_bool \g_regex_success_bool + \group_insert_after:N \regex_break_true:w + \fi: + \bool_gset_eq:NN \g_regex_success_bool \l_regex_saved_success_bool + \group_end: + } + } +\cs_new_protected_nopar:Npn \regex_prop_d: + { \regex_item_caseful_range:nn \c_forty_eight { 57 } } % 0--9 +\cs_new_protected_nopar:Npn \regex_prop_h: + { + \regex_item_caseful_equal:n \c_thirty_two % space + \regex_item_caseful_equal:n \c_nine % tab + } +\cs_new_protected_nopar:Npn \regex_prop_s: + { + \regex_item_caseful_equal:n \c_thirty_two % space + \regex_item_caseful_equal:n \c_nine % tab + \regex_item_caseful_equal:n \c_ten % lf + \regex_item_caseful_equal:n \c_twelve % ff + \regex_item_caseful_equal:n \c_thirteen % cr + } +\cs_new_protected_nopar:Npn \regex_prop_v: + { \regex_item_caseful_range:nn \c_ten \c_thirteen } % lf, vtab, ff, cr +\cs_new_protected_nopar:Npn \regex_prop_w: + { + \regex_item_caseful_range:nn \c_ninety_seven { 122 } % a--z + \regex_item_caseful_range:nn \c_sixty_five { 90 } % A--Z + \regex_item_caseful_range:nn \c_forty_eight { 57 } % 0--9 + \regex_item_caseful_equal:n { 95 } % _ + } +\cs_new_protected_nopar:Npn \regex_prop_N: + { \regex_item_reverse:n { \regex_item_caseful_equal:n \c_ten } } +\cs_new_protected_nopar:Npn \regex_posix_alnum: + { \regex_posix_alpha: \regex_posix_digit: } +\cs_new_protected_nopar:Npn \regex_posix_alpha: + { \regex_posix_lower: \regex_posix_upper: } +\cs_new_protected_nopar:Npn \regex_posix_ascii: + { \regex_item_caseful_range:nn \c_zero \c_one_hundred_twenty_seven } +\cs_new_eq:NN \regex_posix_blank: \regex_prop_h: +\cs_new_protected_nopar:Npn \regex_posix_cntrl: + { + \regex_item_caseful_range:nn \c_zero { 31 } + \regex_item_caseful_equal:n \c_one_hundred_twenty_seven + } +\cs_new_eq:NN \regex_posix_digit: \regex_prop_d: +\cs_new_protected_nopar:Npn \regex_posix_graph: + { \regex_item_caseful_range:nn { 33 } { 126 } } +\cs_new_protected_nopar:Npn \regex_posix_lower: + { \regex_item_caseful_range:nn \c_ninety_seven { 122 } } +\cs_new_protected_nopar:Npn \regex_posix_print: + { \regex_item_caseful_range:nn \c_thirty_two { 126 } } +\cs_new_protected_nopar:Npn \regex_posix_punct: + { + \regex_item_caseful_range:nn { 33 } { 47 } + \regex_item_caseful_range:nn { 58 } { 64 } + \regex_item_caseful_range:nn { 91 } { 96 } + \regex_item_caseful_range:nn { 123 } { 126 } + } +\cs_new_protected_nopar:Npn \regex_posix_space: + { + \regex_item_caseful_equal:n \c_thirty_two + \regex_item_caseful_range:nn \c_nine \c_thirteen + } +\cs_new_protected_nopar:Npn \regex_posix_upper: + { \regex_item_caseful_range:nn \c_sixty_five { 90 } } +\cs_new_eq:NN \regex_posix_word: \regex_prop_w: +\cs_new_protected_nopar:Npn \regex_posix_xdigit: + { + \regex_posix_digit: + \regex_item_caseful_range:nn \c_sixty_five { 70 } + \regex_item_caseful_range:nn \c_ninety_seven { 102 } } \cs_new_protected:Npn \regex_escape_use:nnnn #1#2#3#4 { - \group_begin: + \tl_set_build:Nw \l_regex_internal_a_tl \cs_set_nopar:Npn \regex_escape_unescaped:N ##1 { #1 } \cs_set_nopar:Npn \regex_escape_escaped:N ##1 { #2 } \cs_set_nopar:Npn \regex_escape_raw:N ##1 { #3 } \int_set:Nn \tex_escapechar:D { 92 } - \str_gset_other:Nn \g_regex_internal_tl {#4} - \int_zero:N \l_regex_internal_a_int - \tl_set:Nx \l_regex_internal_a_tl + \str_gset_other:Nn \g_regex_internal_tl { #4 } + \tl_set:Nx \l_regex_internal_b_tl { \exp_after:wN \regex_escape_loop:N \g_regex_internal_tl { break } \prg_break_point:n { } } - \use:x - { - \group_end: - \regex_toks_range:nn \c_zero \l_regex_internal_a_int - \exp_not:o \l_regex_internal_a_tl - } + \tl_build_one:o \l_regex_internal_b_tl + \tl_build_end: + \l_regex_internal_a_tl } \cs_new:Npn \regex_escape_loop:N #1 { @@ -437,82 +319,96 @@ { \exp_not:N \regex_escape_raw:N \iow_char:N \^^M } \cs_new_nopar:cpx { regex_escape_/e:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^[ } -\cs_new_nopar:cpn { regex_escape_/x:w } \regex_escape_loop:N +\cs_new:cpn { regex_escape_/x:w } \regex_escape_loop:N { - \if_false: { \fi: } - \tex_toks:D \l_regex_internal_a_int - \exp_after:wN { \l_regex_internal_a_tl } - \int_incr:N \l_regex_internal_a_int - \int_zero:N \l_regex_current_char_int - \regex_escape_x_test:N + \exp_after:wN \regex_escape_x_end:w + \int_value:w "0 \regex_escape_x_test:N } -\cs_new_protected:Npx \regex_escape_x_test:N #1 +\cs_new:Npn \regex_escape_x_end:w #1 ; { - \exp_not:N \token_if_eq_charcode:NNTF \c_space_token #1 - { \exp_not:N \regex_escape_x_test:N } + \int_compare:nNnTF {#1} < \c_two_hundred_fifty_six { - \l_regex_current_char_int = "0 - \exp_not:N \token_if_eq_charcode:NNTF \c_lbrace_str #1 - { \exp_not:N \regex_escape_x_braced_loop:N } - { \exp_not:N \regex_escape_x_unbraced_i:N #1 } + \exp_last_unbraced:Nf \regex_escape_raw:N + { \str_output_byte:n {#1} } } + { \regex_escape_x_large:n {#1} } } -\cs_new:Npn \regex_escape_x_unbraced_i:N #1 - { - \str_aux_hexadecimal_use:NTF #1 - { \regex_escape_x_unbraced_ii:N } - { \exp_stop_f: \regex_escape_x_end: #1 } - } -\cs_new:Npn \regex_escape_x_unbraced_ii:N #1 +\group_begin: + \char_set_catcode_other:n { 0 } + \cs_new:Npn \regex_escape_x_large:n #1 + { + \if_false: { \fi: } + \tl_build_one:o \l_regex_internal_b_tl + \int_compare:nNnTF {#1} > \c_max_char_int + { + \msg_kernel_error:nnx { regex } { x-overflow } {#1} + \tl_set:Nx \l_regex_internal_b_tl + { \if_false: } \fi: \regex_escape_loop:N + } + { + \char_set_lccode:nn { \c_zero } {#1} + \tl_to_lowercase:n + { + \tl_set:Nx \l_regex_internal_b_tl + { \if_false: } \fi: + \regex_escape_raw:N ^^@ + \regex_escape_loop:N + } + } + } +\group_end: +\cs_new:Npn \regex_escape_x_test:N #1 { - \token_if_eq_charcode:NNTF \c_space_token #1 - { \regex_escape_x_unbraced_ii:N } + \str_if_eq:xxTF {#1} { break } { ; } { - \str_aux_hexadecimal_use:NTF #1 - { \exp_stop_f: \regex_escape_x_end: } - { \exp_stop_f: \regex_escape_x_end: #1 } + \if_charcode:w \c_space_token #1 + \exp_after:wN \regex_escape_x_test:N + \else: + \exp_after:wN \regex_escape_x_test_ii:N + \exp_after:wN #1 + \fi: } } -\cs_new:Npn \regex_escape_x_braced_loop:N #1 +\cs_new:Npn \regex_escape_x_test_ii:N #1 { - \token_if_eq_charcode:NNTF \c_space_token #1 - { \regex_escape_x_braced_loop:N } + \if_charcode:w \c_lbrace_str #1 + \exp_after:wN \regex_escape_x_loop:N + \else: + \str_aux_hexadecimal_use:NTF #1 + { \exp_after:wN \regex_escape_x_ii:N } + { ; \exp_after:wN \regex_escape_loop:N \exp_after:wN #1 } + \fi: + } +\cs_new:Npn \regex_escape_x_ii:N #1 + { + \str_if_eq:xxTF {#1} { break } { ; } { \str_aux_hexadecimal_use:NTF #1 - { \regex_escape_x_braced_loop:N } - { \exp_stop_f: \regex_escape_x_braced_end:N #1 } + { ; \regex_escape_loop:N } + { ; \regex_escape_loop:N #1 } } } -\cs_new_protected:Npx \regex_escape_x_braced_end:N #1 +\cs_new:Npn \regex_escape_x_loop:N #1 { - \exp_not:N \token_if_eq_charcode:NNTF \c_rbrace_str #1 - { \exp_not:N \regex_escape_x_end: } + \str_aux_hexadecimal_use:NTF #1 + { \regex_escape_x_loop:N } { - \msg_kernel_error:nnx { regex } { x-missing-rbrace } - { \int_use:N \l_regex_current_char_int } - \exp_not:N \regex_escape_x_end: #1 + \token_if_eq_charcode:NNTF \c_space_token #1 + { \regex_escape_x_loop:N } + { + ; + \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #1 + { \regex_escape_loop:N } + { + \if_false: { \fi: } + \tl_build_one:o \l_regex_internal_b_tl + \msg_kernel_error:nn { regex } { x-missing-rbrace } {#1} + \tl_set:Nx \l_regex_internal_b_tl + { \if_false: } \fi: \regex_escape_loop:N #1 + } + } } } -\group_begin: - \char_set_catcode_other:N \^^@ - \cs_new_protected_nopar:Npn \regex_escape_x_end: - { - \if_num:w \l_regex_current_char_int > \c_max_char_int - \msg_kernel_error:nnx { regex } { x-overflow } - { \int_use:N \l_regex_current_char_int } - \exp_after:wN \use:n - \else: - \tex_lccode:D \c_zero \l_regex_current_char_int - \exp_after:wN \tl_to_lowercase:n - \fi: - { - \tl_set:Nx \l_regex_internal_a_tl - { \if_false: } \fi: - \regex_escape_raw:N ^^@ - \regex_escape_loop:N - } - } -\group_end: \prg_new_conditional:Npnn \regex_char_if_special:N #1 { TF } { \if_num:w `#1 < \c_ninety_one @@ -554,198 +450,368 @@ \fi: \fi: } -\cs_new_nopar:Npn \regex_build_if_in_class:TF +\int_new:N \l_regex_group_level_int +\int_new:N \l_regex_mode_int +\int_new:N \l_regex_catcodes_int +\int_new:N \l_regex_default_catcodes_int +\bool_new:N \l_regex_catcodes_bool +\int_const:Nn \c_regex_catcode_C_int { "1 } +\int_const:Nn \c_regex_catcode_B_int { "4 } +\int_const:Nn \c_regex_catcode_E_int { "10 } +\int_const:Nn \c_regex_catcode_M_int { "40 } +\int_const:Nn \c_regex_catcode_T_int { "100 } +\int_const:Nn \c_regex_catcode_P_int { "1000 } +\int_const:Nn \c_regex_catcode_U_int { "4000 } +\int_const:Nn \c_regex_catcode_D_int { "10000 } +\int_const:Nn \c_regex_catcode_S_int { "100000 } +\int_const:Nn \c_regex_catcode_L_int { "400000 } +\int_const:Nn \c_regex_catcode_O_int { "1000000 } +\int_const:Nn \c_regex_catcode_A_int { "4000000 } +\int_const:Nn \c_regex_all_catcodes_int { "5515155 } +\cs_new_eq:NN \l_regex_internal_regex \c_regex_no_match_regex +\seq_new:N \l_regex_show_prefix_seq +\int_new:N \l_regex_show_lines_int +\cs_new_protected:Npn \regex_get_digits:NTFw #1#2#3#4#5 + { + \regex_if_raw_digit:NNTF #4 #5 + { #1 = #5 \regex_get_digits_loop:nw {#2} } + { #3 #4 #5 } + } +\cs_new:Npn \regex_get_digits_loop:nw #1#2#3 + { + \regex_if_raw_digit:NNTF #2 #3 + { #3 \regex_get_digits_loop:nw {#1} } + { \scan_stop: #1 #2 #3 } + } +\prg_new_conditional:Npnn \regex_if_raw_digit:NN #1#2 { TF } + { + \if_meaning:w \regex_compile_raw:N #1 + \if_int_compare:w \c_one < 1 #2 \exp_stop_f: + \prg_return_true: + \else: + \prg_return_false: + \fi: + \else: + \prg_return_false: + \fi: + } +\cs_new_nopar:Npn \regex_if_in_class:TF { - \if_int_odd:w \l_regex_build_mode_int + \if_int_odd:w \l_regex_mode_int \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: } -\cs_new_nopar:Npn \regex_build_if_assertions_forbidden:TF +\cs_new_nopar:Npn \regex_if_in_cs:TF { - \if_int_odd:w \l_regex_build_mode_int - \exp_after:wN \use_i:nn + \if_int_odd:w \l_regex_mode_int + \exp_after:wN \use_ii:nn \else: - \if_int_compare:w \l_regex_build_mode_int > \c_zero + \if_int_compare:w \l_regex_mode_int < \c_zero \exp_after:wN \exp_after:wN \exp_after:wN \use_i:nn \else: \exp_after:wN \exp_after:wN \exp_after:wN \use_ii:nn \fi: \fi: } -\cs_new_protected_nopar:Npn \regex_build_new_state: +\cs_new_nopar:Npn \regex_if_in_class_or_catcode:TF { - \tex_toks:D \l_regex_max_state_int { \s_stop } - \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int - \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int - \int_incr:N \l_regex_max_state_int + \if_int_odd:w \l_regex_mode_int + \exp_after:wN \use_i:nn + \else: + \if_int_compare:w \l_regex_mode_int > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN \use_i:nn + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \use_ii:nn + \fi: + \fi: } -\cs_new_protected:Npn \regex_build_transition:NN #1#2 +\cs_new_nopar:Npn \regex_if_within_catcode:TF { - \regex_build_new_state: - \regex_toks_put_right:Nx \l_regex_left_state_int - { #1 { \int_eval:n { #2 - \l_regex_left_state_int } } } + \if_int_compare:w \l_regex_mode_int > \c_zero + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: } -\cs_new_protected:Npn \regex_build_transitions:NNNN #1#2#3#4 +\cs_new_protected:Npn \regex_chk_c_allowed:T { - \regex_build_new_state: - \regex_toks_put_right:Nx \l_regex_left_state_int - { - #1 { \int_eval:n { #2 - \l_regex_left_state_int } } - #3 { \int_eval:n { #4 - \l_regex_left_state_int } } - } + \if_num:w \l_regex_mode_int = \c_zero + \exp_after:wN \use:n + \else: + \if_num:w \l_regex_mode_int = \c_three + \exp_after:wN \exp_after:wN \exp_after:wN \use:n + \else: + \msg_kernel_error:nn { regex } { c-bad-mode } + \exp_after:wN \exp_after:wN \exp_after:wN \use_none:n + \fi: + \fi: } -\cs_new_protected_nopar:Npn \regex_build:w +\cs_new_protected:Npn \regex_mode_quit_c: { - \int_set_eq:NN \l_regex_catcodes_default_int \c_regex_catcodes_all_int - \int_set_eq:NN \l_regex_catcodes_int \l_regex_catcodes_default_int - \int_set_eq:NN \l_regex_capturing_group_int \c_zero - \seq_clear:N \l_regex_capturing_group_seq - \tl_clear:N \l_regex_tests_tl - \bool_set_true:N \l_regex_tests_bool - \int_zero:N \l_regex_max_state_int - \regex_build_new_state: + \if_num:w \l_regex_mode_int = \c_two + \l_regex_mode_int = \c_zero + \else: + \if_num:w \l_regex_mode_int = \c_six + \l_regex_mode_int = \c_three + \fi: + \fi: } -\cs_new_protected_nopar:Npn \regex_build_end: +\cs_new_protected_nopar:Npn \regex_compile:w { - \regex_build_exit_class: - \regex_build_exit_groups: - \regex_toks_put_right:Nx \l_regex_right_state_int - { \regex_action_success: } - \int_incr:N \l_regex_capturing_group_int + \tl_set_build_x:Nw \l_regex_internal_regex + \int_zero:N \l_regex_group_level_int + \int_set_eq:NN \l_regex_default_catcodes_int \c_regex_all_catcodes_int + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \cs_set_nopar:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } + \cs_set_nopar:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } + \tl_build_one:n { \regex_branch:n { \if_false: } \fi: } } -\cs_new_protected_nopar:Npn \regex_build_exit_class: +\cs_new_protected_nopar:Npn \regex_compile_end: { - \regex_build_if_in_class:TF - { - \msg_kernel_error:nn { regex } { missing-rbrack } - \use:c { regex_build_]: } - } - { } - } -\cs_new_protected_nopar:Npn \regex_build_exit_groups: - { - \seq_if_empty:NF \l_regex_capturing_group_seq - { + \regex_if_in_class:TF + { + \msg_kernel_error:nn { regex } { missing-rbrack } + \use:c { regex_compile_]: } + \prg_do_nothing: \prg_do_nothing: + } + { } + \if_num:w \l_regex_group_level_int > \c_zero \msg_kernel_error:nnx { regex } { missing-rparen } - { \seq_length:N \l_regex_capturing_group_seq } + { \int_use:N \l_regex_group_level_int } \prg_replicate:nn - { \seq_length:N \l_regex_capturing_group_seq } - { \regex_build_close_aux: \regex_build_group_: } - } - } -\cs_new_protected:Npn \regex_build:n #1 - { - \regex_build:w - \int_set_eq:NN \l_regex_build_mode_int \c_zero - \regex_build_new_state: - \regex_toks_put_right:Nx \l_regex_left_state_int - { \regex_action_start_wildcard: } - \regex_build_open_aux: - \regex_escape_use:nnnn + { \l_regex_group_level_int } { - \regex_char_if_special:NTF ##1 - \regex_build_special:N \regex_build_raw:N ##1 - } - { - \regex_char_if_alphanumeric:NTF ##1 - \regex_build_escaped:N \regex_build_raw:N ##1 + \tl_build_one:n + { + \if_false: { \fi: } + \if_false: { \fi: } { 1 } { 0 } \c_true_bool + } + \tl_build_end: + \tl_build_one:o \l_regex_internal_regex } - { \regex_build_raw:N ##1 } - { #1 } - \prg_do_nothing: \prg_do_nothing: - \prg_do_nothing: \prg_do_nothing: - \int_compare:nNnT \l_regex_build_mode_int < \c_zero + \fi: + \tl_build_one:n { \if_false: { \fi: } } + \tl_build_end: + } +\cs_new_protected:Npn \regex_compile:n #1 + { + \regex_compile:w + \int_set:Nn \tex_escapechar:D { 92 } + \int_set_eq:NN \l_regex_mode_int \c_zero + \regex_escape_use:nnnn + { + \regex_char_if_special:NTF ##1 + \regex_compile_special:N \regex_compile_raw:N ##1 + } + { + \regex_char_if_alphanumeric:NTF ##1 + \regex_compile_escaped:N \regex_compile_raw:N ##1 + } + { \regex_compile_raw:N ##1 } + { #1 } + \prg_do_nothing: \prg_do_nothing: + \prg_do_nothing: \prg_do_nothing: + \int_compare:nNnT \l_regex_mode_int < \c_zero { \msg_kernel_error:nn { regex } { c-missing-rbrace } - \exp_after:wN \regex_build_special:N \c_rbrace_str + \regex_compile_end: + \regex_compile_one:x + { \regex_item_cs:n { \exp_not:o \l_regex_internal_regex } } + \prg_do_nothing: \prg_do_nothing: + \prg_do_nothing: \prg_do_nothing: } - \seq_put_right:Nn \l_regex_capturing_group_seq {0} - \regex_build_close_aux: \regex_build_group_: - \regex_build_end: + \regex_compile_end: } -\cs_new_protected:Npn \regex_build_special:N #1 +\cs_new_protected:Npn \regex_compile_special:N #1 { - \cs_if_exist_use:cF { regex_build_#1: } - { \regex_build_raw:N #1 } + \cs_if_exist_use:cF { regex_compile_#1: } + { \regex_compile_raw:N #1 } } -\cs_new_protected:Npn \regex_build_escaped:N #1 +\cs_new_protected:Npn \regex_compile_escaped:N #1 { - \cs_if_exist_use:cF { regex_build_/#1: } - { \regex_build_raw:N #1 } + \cs_if_exist_use:cF { regex_compile_/#1: } + { \regex_compile_raw:N #1 } } -\cs_new_protected:Npn \regex_build_one:n #1 - { \regex_build_one:x { \exp_not:n {#1} } } -\cs_new_protected:Npn \regex_build_one:x #1 +\cs_new_protected:Npn \regex_compile_one:x #1 { - \tl_put_right:Nx \l_regex_tests_tl + \regex_mode_quit_c: + \regex_if_in_class:TF { } { - \if_num:w \l_regex_catcodes_int < \c_regex_catcodes_all_int + \tl_build_one:n + { \regex_class:NnnnN \c_true_bool { \if_false: } \fi: } + } + \tl_build_one:x + { + \if_num:w \l_regex_catcodes_int < \c_regex_all_catcodes_int \regex_item_catcode:nT { \int_use:N \l_regex_catcodes_int } + { \exp_not:N \exp_not:n {#1} } \else: - \exp_after:wN \use:n + \exp_not:N \exp_not:n {#1} \fi: - {#1} } - \int_set_eq:NN \l_regex_catcodes_int \l_regex_catcodes_default_int - \if_num:w \l_regex_build_mode_int = \c_two - \l_regex_build_mode_int = \c_zero - \else: - \if_num:w \l_regex_build_mode_int = \c_six - \l_regex_build_mode_int = \c_three - \fi: - \fi: - \if_int_odd:w \l_regex_build_mode_int \else: - \exp_after:wN \regex_build_one_quantifier: - \fi: + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \regex_if_in_class:TF { } { \regex_compile_quantifier:w } } -\cs_new:Npn \regex_tests_action_cost:n #1 +\cs_new_protected:Npn \regex_compile_abort_tokens:n #1 { - \exp_not:o \l_regex_tests_tl - \bool_if:NTF \l_regex_tests_bool - { \regex_break_point:TF { \regex_action_cost:n {#1} } { } } - { \regex_break_point:TF { } { \regex_action_cost:n {#1} } } + \use:x + { + \exp_args:No \tl_map_function:nN { \tl_to_str:n {#1} } + \regex_compile_raw:N + } } -\cs_new_protected:Npn \regex_build_raw_error:N #1 +\cs_generate_variant:Nn \regex_compile_abort_tokens:n { x } +\cs_new_protected:Npn \regex_compile_quantifier:w #1#2 { - \if_int_odd:w \l_regex_build_mode_int - \msg_kernel_error:nnx { regex } { class-bad-escape } {#1} - \else: - \msg_kernel_error:nnx { regex } { catcode-bad-escape } {#1} - \fi: - \regex_build_raw:N #1 + \token_if_eq_meaning:NNTF #1 \regex_compile_special:N + { + \cs_if_exist_use:cF { regex_compile_quantifier_#2:w } + { \regex_compile_quantifier_none: #1 #2 } + } + { \regex_compile_quantifier_none: #1 #2 } } -\cs_new_protected:Npn \regex_build_raw:N #1#2#3 +\cs_new_protected:Npn \regex_compile_quantifier_none: + { \tl_build_one:n { \if_false: { \fi: } { 1 } { 0 } \c_false_bool } } +\cs_new_protected:Npn \regex_compile_quantifier_abort:xNN #1#2#3 { - \regex_build_if_in_class:TF - { \str_if_eq:nnTF {#2#3} { \regex_build_special:N - } } - { \use_ii:nn } - { \regex_class_range:Nw #1 } + \regex_compile_quantifier_none: + \msg_kernel_warning:nnxx { regex } { invalid-quantifier } {#1} {#3} + \regex_compile_abort_tokens:x {#1} + #2 #3 + } +\cs_new_protected:Npn \regex_compile_quantifier_lazyness:nnNN #1#2#3#4 + { + \str_if_eq:nnTF { #3 #4 } { \regex_compile_special:N ? } + { \tl_build_one:n { \if_false: { \fi: } { #1 } { #2 } \c_true_bool } } { - \regex_build_one:x { \regex_item_equal:n { \int_value:w `#1 ~ } } - #2 #3 + \tl_build_one:n { \if_false: { \fi: } { #1 } { #2 } \c_false_bool } + #3 #4 } } -\cs_new_protected:Npn \regex_class_range:Nw #1#2#3 +\cs_new_protected_nopar:cpn { regex_compile_quantifier_?:w } + { \regex_compile_quantifier_lazyness:nnNN { 0 } { 1 } } +\cs_new_protected_nopar:cpn { regex_compile_quantifier_*:w } + { \regex_compile_quantifier_lazyness:nnNN { 0 } { -1 } } +\cs_new_protected_nopar:cpn { regex_compile_quantifier_+:w } + { \regex_compile_quantifier_lazyness:nnNN { 1 } { -1 } } +\cs_new_protected:cpn { regex_compile_quantifier_ \c_lbrace_str :w } { - \token_if_eq_meaning:NNTF #2 \regex_build_escaped:N % [ - { \use_i:nn } { \str_if_eq:nnTF { #2#3 } { \regex_build_special:N ] } } + \regex_get_digits:NTFw \l_regex_internal_a_int + { \regex_compile_quantifier_braced_i:w } + { \regex_compile_quantifier_abort:xNN { \c_lbrace_str } } + } +\cs_new_protected:Npn \regex_compile_quantifier_braced_i:w #1#2 + { + \prg_case_str:xxn { #1 #2 } { - \msg_kernel_warning:nnxx { regex } { range-missing-end } % [ - {#1} { \token_if_eq_charcode:NNF #3 ] { \c_backslash_str } #3 } - \tl_put_right:Nx \l_regex_tests_tl + { \regex_compile_special:N \c_rbrace_str } { - \regex_item_equal:n { \int_value:w `#1 ~ } - \regex_item_equal:n { \int_value:w `- ~ } + \exp_args:No \regex_compile_quantifier_lazyness:nnNN + { \int_use:N \l_regex_internal_a_int } { 0 } + } + { \regex_compile_special:N , } + { + \regex_get_digits:NTFw \l_regex_internal_b_int + { \regex_compile_quantifier_braced_iii:w } + { \regex_compile_quantifier_braced_ii:w } + } + } + { + \regex_compile_quantifier_abort:xNN + { \c_lbrace_str \int_use:N \l_regex_internal_a_int } + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_quantifier_braced_ii:w #1#2 + { + \str_if_eq:xxTF + { #1 #2 } { \regex_compile_special:N \c_rbrace_str } + { + \exp_args:No \regex_compile_quantifier_lazyness:nnNN + { \int_use:N \l_regex_internal_a_int } { -1 } + } + { + \regex_compile_quantifier_abort:xNN + { \c_lbrace_str \int_use:N \l_regex_internal_a_int , } + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_quantifier_braced_iii:w #1#2 + { + \str_if_eq:xxTF + { #1 #2 } { \regex_compile_special:N \c_rbrace_str } + { + \if_num:w \l_regex_internal_a_int > \l_regex_internal_b_int + \msg_kernel_error:nnxx { regex } { backwards-quantifier } + { \int_use:N \l_regex_internal_a_int } + { \int_use:N \l_regex_internal_b_int } + \int_zero:N \l_regex_internal_b_int + \else: + \int_sub:Nn \l_regex_internal_b_int \l_regex_internal_a_int + \fi: + \exp_args:Noo \regex_compile_quantifier_lazyness:nnNN + { \int_use:N \l_regex_internal_a_int } + { \int_use:N \l_regex_internal_b_int } + } + { + \regex_compile_quantifier_abort:xNN + { + \c_lbrace_str + \int_use:N \l_regex_internal_a_int , + \int_use:N \l_regex_internal_b_int + } + #1 #2 + } + } +\cs_new_protected:Npn \regex_compile_raw_error:N #1 + { + \msg_kernel_error:nnx { regex } { bad-escape } {#1} + \regex_compile_raw:N #1 + } +\cs_new_protected:Npn \regex_compile_raw:N #1#2#3 + { + \regex_if_in_class:TF + { + \str_if_eq:nnTF {#2#3} { \regex_compile_special:N - } + { \regex_compile_range:Nw #1 } + { + \regex_compile_one:x + { \regex_item_equal:n { \int_value:w `#1 ~ } } + #2 #3 } - #2#3 } { + \regex_compile_one:x + { \regex_item_equal:n { \int_value:w `#1 ~ } } + #2 #3 + } + } +\prg_new_protected_conditional:Npnn \regex_if_end_range:NN #1#2 { TF } + { + \if_meaning:w \regex_compile_raw:N #1 + \prg_return_true: + \else: + \if_meaning:w \regex_compile_special:N #1 + \if_charcode:w ] #2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + \else: + \prg_return_false: + \fi: + \fi: + } +\cs_new_protected:Npn \regex_compile_range:Nw #1#2#3 + { + \regex_if_end_range:NNTF #2 #3 + { \if_num:w `#1 > `#3 \exp_stop_f: \msg_kernel_error:nnxx { regex } { range-backwards } {#1} {#3} \else: - \tl_put_right:Nx \l_regex_tests_tl + \tl_build_one:x { \if_num:w `#1 = `#3 \exp_stop_f: \regex_item_equal:n @@ -756,1088 +822,1125 @@ } \fi: } - } -\cs_new_protected_nopar:cpx { regex_build_.: } - { - \exp_not:N \regex_build_if_in_class:TF - { \regex_build_raw:N . } - { \regex_build_one:n \exp_not:c { c_regex_._tl } } - } -\tl_map_inline:nn { dDhHsSvVwWN } - { - \cs_new_protected_nopar:cpx { regex_build_/#1: } - { \regex_build_one:n \exp_not:c { c_regex_#1_tl } } - } -\cs_new_protected:Npn \regex_build_simple_assertion:nn #1#2 - { - \regex_build_if_assertions_forbidden:TF {#1} { - \regex_build_new_state: - \regex_toks_put_right:Nx \l_regex_left_state_int + \msg_kernel_warning:nnxx { regex } { range-missing-end } + {#1} { \c_backslash_str #3 } + \tl_build_one:x { - \exp_not:n {#2} - { - \regex_action_free:n - { - \int_eval:n - { \l_regex_right_state_int - \l_regex_left_state_int } - } - } + \regex_item_equal:n { \int_value:w `#1 ~ } + \regex_item_equal:n { \int_value:w `- ~ } } - %^^A todo: add \regex_assertion_quantifier: + #2#3 } } -\cs_new_protected_nopar:cpn { regex_build_^: } - { - \regex_build_simple_assertion:nn { \regex_build_raw:N ^ } - { \int_compare:nNnT \l_regex_min_index_int = \l_regex_current_index_int } - } -\cs_new_protected_nopar:cpn { regex_build_/A: } +\cs_new_protected_nopar:cpx { regex_compile_.: } { - \regex_build_simple_assertion:nn { \regex_build_raw_error:N A } - { \int_compare:nNnT \l_regex_min_index_int = \l_regex_current_index_int } + \exp_not:N \regex_if_in_class:TF + { \regex_compile_raw:N . } + { \regex_compile_one:x \exp_not:c { regex_prop_.: } } } -\cs_new_protected_nopar:cpn { regex_build_/G: } +\cs_new_protected_nopar:cpn { regex_prop_.: } { - \regex_build_simple_assertion:nn { \regex_build_raw_error:N G } - { \int_compare:nNnT \l_regex_start_index_int = \l_regex_current_index_int } + \if_num:w \l_regex_current_char_int > - \c_two + \exp_after:wN \regex_break_true:w + \fi: } -\group_begin: - \char_set_catcode_other:N \$ - \cs_new_protected_nopar:cpn { regex_build_$: } % $ - { - \regex_build_simple_assertion:nn { \regex_build_raw:N $ } % $ - { \int_compare:nNnT \l_regex_current_char_int < \c_minus_one } - } -\group_end: -\cs_new_protected_nopar:cpn { regex_build_/Z: } +\cs_set_protected:Npn \regex_tmp:w #1#2 { - \regex_build_simple_assertion:nn { \regex_build_raw_error:N Z } - { \int_compare:nNnT \l_regex_current_char_int < \c_minus_one } + \cs_new_protected_nopar:cpx { regex_compile_/#1: } + { \regex_compile_one:x \exp_not:c { regex_prop_#1: } } + \cs_new_protected_nopar:cpx { regex_compile_/#2: } + { + \regex_compile_one:x + { \regex_item_reverse:n \exp_not:c { regex_prop_#1: } } + } } -\cs_new_protected_nopar:cpn { regex_build_/z: } +\regex_tmp:w d D +\regex_tmp:w h H +\regex_tmp:w s S +\regex_tmp:w v V +\regex_tmp:w w W +\cs_new_protected_nopar:cpn { regex_compile_/N: } + { \regex_compile_one:x \regex_prop_N: } +\cs_new_protected:Npn \regex_compile_anchor:NF #1#2 { - \regex_build_simple_assertion:nn { \regex_build_raw_error:N z } - { \int_compare:nNnT \l_regex_current_char_int < \c_minus_one } + \regex_if_in_class_or_catcode:TF {#2} + { + \tl_build_one:n + { \regex_assertion:Nn \c_true_bool { \regex_anchor:N #1 } } + } } -\cs_new_protected_nopar:cpn { regex_build_/b: } +\cs_set_protected:Npn \regex_tmp:w #1#2 { - \regex_build_simple_assertion:nn { \regex_build_raw_error:N b } - { \regex_if_word_boundary:T } + \cs_new_protected_nopar:cpn { regex_compile_/#1: } + { \regex_compile_anchor:NF #2 { \regex_compile_raw_error:N #1 } } } -\cs_new_protected_nopar:cpn { regex_build_/B: } +\regex_tmp:w A \l_regex_min_pos_int +\regex_tmp:w G \l_regex_start_pos_int +\regex_tmp:w Z \l_regex_max_pos_int +\regex_tmp:w z \l_regex_max_pos_int +\cs_set_protected:Npn \regex_tmp:w #1#2 { - \regex_build_simple_assertion:nn { \regex_build_raw_error:N B } - { \regex_if_word_boundary:TF { } } + \cs_new_protected_nopar:cpn { regex_compile_#1: } + { \regex_compile_anchor:NF #2 { \regex_compile_raw:N #1 } } } -\cs_new_protected_nopar:Npn \regex_if_word_boundary:TF +\exp_args:Nx \regex_tmp:w { \iow_char:N \^ } \l_regex_min_pos_int +\exp_args:Nx \regex_tmp:w { \iow_char:N \$ } \l_regex_max_pos_int +\cs_new_protected_nopar:cpn { regex_compile_/b: } { - \group_begin: - \int_set_eq:NN \l_regex_current_char_int \l_regex_last_char_int - \c_regex_w_tl - \regex_break_point:TF - { \group_end: \c_regex_W_tl \regex_item_equal:n { -2 } } - { \group_end: \c_regex_w_tl } - \regex_break_point:TF + \regex_if_in_class_or_catcode:TF + { \regex_compile_raw_error:N b } + { + \tl_build_one:n + { \regex_assertion:Nn \c_true_bool { \regex_b_test: } } + } } -\cs_new_protected_nopar:Npn \regex_if_word_boundary:T - { \regex_if_word_boundary:TF \use:n \use_none:n } -\cs_new_protected_nopar:cpn { regex_build_[: } +\cs_new_protected_nopar:cpn { regex_compile_/B: } { - \regex_build_if_in_class:TF - { \regex_build_raw:N [ } - { \regex_class_first:NNNN } + \regex_if_in_class_or_catcode:TF + { \regex_compile_raw_error:N B } + { + \tl_build_one:n + { \regex_assertion:Nn \c_false_bool { \regex_b_test: } } + } } -\cs_new_protected:cpn { regex_build_]: } +\cs_new_protected:cpn { regex_compile_]: } { - \regex_build_if_in_class:TF + \regex_if_in_class:TF { - \if_num:w \l_regex_build_mode_int > \c_sixteen - \tl_set:Nx \l_regex_tests_tl - { - \exp_not:o \l_regex_tests_saved_tl - \if_num:w \l_regex_catcodes_saved_int < \c_regex_catcodes_all_int - \regex_item_catcode:nT - { \int_use:N \l_regex_catcodes_saved_int } - \else: - \exp_after:wN \use:n - \fi: - { - \exp_not:o \l_regex_tests_tl - \bool_if:NF \l_regex_tests_bool - { \regex_break_point:TF { } \regex_break_true:w } - } - } - \bool_set_eq:NN \l_regex_tests_bool \l_regex_tests_saved_bool + \if_num:w \l_regex_mode_int > \c_sixteen + \tl_build_one:n { \if_false: { \fi: } } \fi: - \tex_advance:D \l_regex_build_mode_int - \c_fifteen - \tex_divide:D \l_regex_build_mode_int \c_thirteen - \if_int_odd:w \l_regex_build_mode_int \else: - \exp_after:wN \regex_build_one_quantifier: + \tex_advance:D \l_regex_mode_int - \c_fifteen + \tex_divide:D \l_regex_mode_int \c_thirteen + \if_int_odd:w \l_regex_mode_int \else: + \exp_after:wN \regex_compile_quantifier:w \fi: } - { \regex_build_raw:N ] } + { \regex_compile_raw:N ] } } -\cs_new_protected:Npn \regex_class_first:NNNN #1#2#3#4 +\cs_new_protected_nopar:cpn { regex_compile_[: } { - \l_regex_build_mode_int = \int_value:w \l_regex_build_mode_int 3 ~ % - \if_num:w \l_regex_build_mode_int > \c_sixteen - \tl_set_eq:NN \l_regex_tests_saved_tl \l_regex_tests_tl - \bool_set_eq:NN \l_regex_tests_saved_bool \l_regex_tests_bool - \int_set_eq:NN \l_regex_catcodes_saved_int \l_regex_catcodes_int - \int_set_eq:NN \l_regex_catcodes_int \c_regex_catcodes_all_int - \fi: - \token_if_eq_meaning:NNTF #1 \regex_build_special:N + \regex_if_in_class:TF + { \regex_compile_class_posix_test:w } { - \token_if_eq_charcode:NNTF #2 ^ + \regex_if_within_catcode:TF { - \bool_set_false:N \l_regex_tests_bool % [ - \str_if_eq:nnTF {#3#4} { \regex_build_special:N ] } - { \regex_build_raw:N } - } - { % [ - \token_if_eq_charcode:NNTF #2 ] - { \regex_build_raw:N #2 } - { #1 #2 } + \exp_after:wN \regex_compile_class_catcode:w + \int_use:N \l_regex_catcodes_int ; } + { \regex_compile_class_normal:w } } - { #1 #2 } - #3 #4 - } -\cs_new_protected:cpn { regex_build_/c: } - { - \if_case:w \l_regex_build_mode_int - \exp_after:wN \regex_build_c_aux:wNN - \or: \or: \or: \exp_after:wN \regex_build_c_aux:wNN - \fi: - \msg_kernel_error:nn { regex } { c-bad-mode } - \s_stop } -\cs_new_protected:Npn \regex_build_c_aux:wNN #1 \s_stop #2#3 +\cs_new_protected_nopar:Npn \regex_compile_class_normal:w { - \token_if_eq_meaning:NNTF #2 \regex_build_raw:N - { - \cs_if_exist:cTF { c_regex_catcode_#3_int } - { - \int_set_eq:Nc \l_regex_catcodes_int { c_regex_catcode_#3_int } - \l_regex_build_mode_int - = \if_case:w \l_regex_build_mode_int \c_two \else: \c_six \fi: - } - } - { \cs_if_exist_use:cF { regex_build_c_#3: } } - { - \msg_kernel_error:nnx { regex } { c-missing-category } {#3} - #2 #3 - } + \regex_compile_class:TFNN + { \regex_class:NnnnN \c_true_bool } + { \regex_class:NnnnN \c_false_bool } } -\cs_new_protected:cpn { regex_build_c_ \c_lbrace_str : } +\cs_new_protected:Npn \regex_compile_class_catcode:w #1; { - \group_begin: - \l_regex_build_mode_int - = - \if_case:w \l_regex_build_mode_int \c_two \else: \c_six \fi: - \regex_build:w + \if_int_compare:w \l_regex_mode_int = \c_two + \tl_build_one:n + { \regex_class:NnnnN \c_true_bool { \if_false: } \fi: } + \fi: + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \regex_compile_class:TFNN + { \regex_item_catcode:nT {#1} } + { \regex_item_catcode_reverse:nT {#1} } } -\cs_new_protected:cpn { regex_build_c_[: } #1#2 +\cs_new_protected:Npn \regex_compile_class:TFNN #1#2#3#4 { - \int_zero:N \l_regex_catcodes_int - \str_if_eq:nnTF { #1 #2 } { \regex_build_special:N ^ } + \l_regex_mode_int = \int_value:w \l_regex_mode_int 3 \exp_stop_f: + \str_if_eq:nnTF { #3 #4 } { \regex_compile_special:N ^ } { - \bool_set_false:N \l_regex_catcodes_bool - \regex_build_c_lbrack_loop:NN + \tl_build_one:n { #2 { \if_false: } \fi: } + \regex_compile_class_ii:NN } { - \bool_set_true:N \l_regex_catcodes_bool - \regex_build_c_lbrack_loop:NN - #1#2 + \tl_build_one:n { #1 { \if_false: } \fi: } + \regex_compile_class_ii:NN #3 #4 } } -\cs_new_protected:Npn \regex_build_c_lbrack_loop:NN #1#2 +\cs_new_protected:Npn \regex_compile_class_ii:NN #1#2 { - \token_if_eq_meaning:NNTF #1 \regex_build_raw:N + \token_if_eq_charcode:NNTF #2 ] + { \regex_compile_raw:N #2 } + { #1 #2 } + } +\cs_new_protected:Npn \regex_compile_class_posix_test:w #1#2 + { + \token_if_eq_meaning:NNT \regex_compile_special:N #1 { - \cs_if_exist:cTF { c_regex_catcode_#2_int } + \prg_case_str:nnn { #2 } { - \exp_args:Nc \regex_build_c_lbrack_add:N - { c_regex_catcode_#2_int } - \regex_build_c_lbrack_loop:NN + : { \regex_compile_class_posix:NNNNw } + = { \msg_kernel_warning:nnx { regex } { posix-unsupported } { = } } + . { \msg_kernel_warning:nnx { regex } { posix-unsupported } { . } } } + { } } - { % [ - \token_if_eq_charcode:NNTF #2 ] - { \regex_build_c_lbrack_end: } - } - { - \msg_kernel_error:nnx { regex } { c-missing-rbrack } {#2} - \regex_build_c_lbrack_end: - } + \regex_compile_raw:N [ #1 #2 } -\cs_new_protected_nopar:Npn \regex_build_c_lbrack_end: +\cs_new_protected:Npn \regex_compile_class_posix:NNNNw #1#2#3#4#5#6 { - \l_regex_build_mode_int - = \if_case:w \l_regex_build_mode_int \c_two \else: \c_six \fi: - \if_meaning:w \c_false_bool \l_regex_catcodes_bool - \int_set:Nn \l_regex_catcodes_int - { \c_regex_catcodes_all_int - \l_regex_catcodes_int } - \fi: + \str_if_eq:nnTF { #5 #6 } { \regex_compile_special:N ^ } + { + \bool_set_false:N \l_regex_internal_bool + \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: + \regex_compile_class_posix_loop:w + } + { + \bool_set_true:N \l_regex_internal_bool + \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: + \regex_compile_class_posix_loop:w #5 #6 + } } -\cs_new_protected:Npn \regex_build_c_lbrack_add:N #1 +\cs_new:Npn \regex_compile_class_posix_loop:w #1#2 { - \if_int_odd:w \int_eval:w \l_regex_catcodes_int / #1 \int_eval_end: - \else: - \tex_advance:D \l_regex_catcodes_int #1 - \fi: + \token_if_eq_meaning:NNTF \regex_compile_raw:N #1 + { #2 \regex_compile_class_posix_loop:w } + { \if_false: { \fi: } \regex_compile_class_posix_end:w #1 #2 } } -\cs_new_protected:cpn { regex_build_ \c_rbrace_str : } +\cs_new_protected:Npn \regex_compile_class_posix_end:w #1#2#3#4 { - \int_compare:nNnTF \l_regex_build_mode_int < \c_zero + \str_if_eq:nnTF { #1 #2 #3 #4 } + { \regex_compile_special:N : \regex_compile_special:N ] } { - \regex_build_exit_class: - \regex_build_exit_groups: - \regex_build_escaped:N Z - \regex_build_end: - \use:x + \cs_if_exist:cTF { regex_posix_ \l_regex_internal_a_tl : } { - \group_end: - \regex_build_one:n - { - \regex_item_cs:n - { \regex_set_aux:N \l_regex_internal_regex } - } + \regex_compile_one:x + { + \bool_if:NF \l_regex_internal_bool \regex_item_reverse:n + \exp_not:c { regex_posix_ \l_regex_internal_a_tl : } + } } - } - { \exp_after:wN \regex_build_raw:N \c_rbrace_str } - } -\cs_new_protected:Npn \regex_build_quantifier:w #1#2 - { - \token_if_eq_meaning:NNTF #1 \regex_build_special:N - { - \cs_if_exist_use:cF { regex_build_quantifier_#2:w } { - \regex_build_quantifier_end:nn { } { } - #1 #2 + \msg_kernel_warning:nnx { regex } { posix-unknown } + { \l_regex_internal_a_tl } + \regex_compile_abort_tokens:x + { + [: \bool_if:NF \l_regex_internal_bool { ^ } + \l_regex_internal_a_tl :] + } } } { - \regex_build_quantifier_end:nn { } { } - #1 #2 + \msg_kernel_error:nnxx { regex } { posix-missing-close } + { [: \l_regex_internal_a_tl } { #2 #4 } + \regex_compile_abort_tokens:x { [: \l_regex_internal_a_tl } + #1 #2 #3 #4 } } -\cs_new_protected_nopar:cpn { regex_build_quantifier_?:w } - { \regex_build_quantifier_aux:nnNN { } { ? } } -\cs_new_protected_nopar:cpn { regex_build_quantifier_*:w } - { \regex_build_quantifier_aux:nnNN { } { * } } -\cs_new_protected_nopar:cpn { regex_build_quantifier_+:w } - { \regex_build_quantifier_aux:nnNN { } { + } } -\cs_new_protected:Npn \regex_build_quantifier_aux:nnNN #1#2#3#4 +\cs_new_protected:Npn \regex_compile_group_begin:N #1 { - \str_if_eq:nnTF { #3 #4 } { \regex_build_special:N ? } - { \regex_build_quantifier_end:nn { #2 #4 } {#1} } - { - \regex_build_quantifier_end:nn { #2 } {#1} - #3 #4 - } + \tl_build_one:n { #1 { \if_false: } \fi: } + \regex_mode_quit_c: + \tl_set_build:Nw \l_regex_internal_regex + \int_set_eq:NN \l_regex_default_catcodes_int \l_regex_catcodes_int + \int_incr:N \l_regex_group_level_int + \tl_build_one:n { \regex_branch:n { \if_false: } \fi: } } -\cs_new_protected_nopar:cpn { regex_build_quantifier_ \c_lbrace_str :w } - { \regex_get_digits:nw { \regex_build_quantifier_lbrace:n } } -\cs_new_protected:Npn \regex_build_quantifier_lbrace:n #1 +\cs_new_protected:Npn \regex_compile_group_end: { - \tl_if_empty:nTF {#1} - { - \regex_build_quantifier_end:nn { } { } - \exp_after:wN \regex_build_raw:N \c_lbrace_str - } - { \regex_build_quantifier_lbrace:nw {#1} } + \if_num:w \l_regex_group_level_int > \c_zero + \tl_build_one:n { \if_false: { \fi: } } + \tl_build_end: + \int_set_eq:NN \l_regex_catcodes_int \l_regex_default_catcodes_int + \tl_build_one:o \l_regex_internal_regex + \exp_after:wN \regex_compile_quantifier:w + \else: + \msg_kernel_warning:nn { regex } { extra-rparen } + \exp_after:wN \regex_compile_raw:N \exp_after:wN ) + \fi: + } +\cs_new_protected_nopar:cpn { regex_compile_(: } + { + \regex_if_in_class:TF { \regex_compile_raw:N ( } + { \regex_compile_lparen:w } } -\cs_new_protected:Npx \regex_build_quantifier_lbrace:nw #1#2#3 +\cs_new_protected:Npn \regex_compile_lparen:w #1#2#3#4 { - \exp_not:N \prg_case_str:nnn { #2 #3 } + \str_if_eq:nnTF { #1 #2 } { \regex_compile_special:N ? } { - { \exp_not:N \regex_build_special:N , } + \cs_if_exist_use:cF + { regex_compile_special_group_\token_to_str:N #4 :w } { - \exp_not:N \regex_get_digits:nw - { \exp_not:N \regex_build_quantifier_lbrace:nnw {#1} } + \msg_kernel_warning:nnx { regex } { special-group-unknown } + { (? \token_to_str:N #4 } + \regex_compile_group_begin:N \regex_group:nnnN + \regex_compile_raw:N ? #3 #4 } - { \exp_not:N \regex_build_special:N \c_rbrace_str } - { \exp_not:N \regex_build_quantifier_end:nn {n} { {#1} } } } { - \exp_not:N \regex_build_quantifier_end:nn { } { } - \exp_not:N \regex_build_raw:N \c_lbrace_str #1#2 + \regex_compile_group_begin:N \regex_group:nnnN + #1 #2 #3 #4 } } -\cs_new_protected:Npn \regex_build_quantifier_lbrace:nnw #1#2#3#4 +\cs_new_protected_nopar:cpn { regex_compile_|: } { - \str_if_eq:xxTF - { \exp_not:n {#3#4} } - { \exp_not:N \regex_build_special:N \c_rbrace_str } + \regex_if_in_class:TF { \regex_compile_raw:N | } { - \tl_if_empty:nTF {#2} - { \regex_build_quantifier_aux:nnNN { {#1} } { n* } } - { \regex_build_quantifier_aux:nnNN { {#1} {#2} } { nn } } + \tl_build_one:n + { \if_false: { \fi: } \regex_branch:n { \if_false: } \fi: } } - { - \regex_build_quantifier_end:nn { } { } - \use:x - { - \exp_args:No \tl_map_function:nN - { \c_lbrace_str #1 , #2 } - \regex_build_raw:N - } - #3 #4 - } - } -\cs_new_protected:Npn \regex_build_quantifier_end:nn #1#2 - { - \use:c { regex_build_ \l_regex_one_or_group_tl _ #1 : } #2 - \tl_clear:N \l_regex_tests_tl - \bool_set_true:N \l_regex_tests_bool } -\cs_new_protected_nopar:Npn \regex_build_one_quantifier: +\cs_new_protected_nopar:cpn { regex_compile_): } { - \tl_set:Nx \l_regex_one_or_group_tl { one } - \regex_build_quantifier:w + \regex_if_in_class:TF { \regex_compile_raw:N ) } + { \regex_compile_group_end: } } -\cs_new_protected:Npn \regex_build_one_n: #1 +\cs_new_protected_nopar:cpn { regex_compile_special_group_::w } + { \regex_compile_group_begin:N \regex_group_no_capture:nnnN } +\cs_new_protected_nopar:cpn { regex_compile_special_group_|:w } + { \regex_compile_group_begin:N \regex_group_resetting:nnnN } +\cs_new_protected:Npn \regex_compile_special_group_i:w #1#2 { - \prg_replicate:nn {#1} + \str_if_eq:nnTF { #1 #2 } { \regex_compile_special:N ) } { - \regex_build_transition:NN - \regex_tests_action_cost:n \l_regex_right_state_int - } - } -\cs_new_eq:cN { regex_build_one_n?: } \regex_build_one_n: -\cs_new_protected_nopar:Npn \regex_build_one_: - { \regex_build_one_n: \c_one } -\cs_new_protected:cpn { regex_build_one_n*: } #1 - { - \int_compare:nNnTF {#1} = \c_zero - { - \regex_build_transitions:NNNN - \regex_tests_action_cost:n \l_regex_left_state_int - \regex_action_free:n \l_regex_right_state_int + \cs_set_nopar:Npn \regex_item_equal:n { \regex_item_caseless_equal:n } + \cs_set_nopar:Npn \regex_item_range:nn { \regex_item_caseless_range:nn } } { - \regex_build_one_n: {#1} - \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int - \regex_build_transitions:NNNN - \regex_action_free:n \l_regex_internal_a_int - \regex_action_free:n \l_regex_right_state_int + \msg_kernel_warning:nnx { regex } { unknown-option } { (?i #2 } + \regex_compile_raw:N ( + \regex_compile_raw:N ? + \regex_compile_raw:N i + #1 #2 } } -\cs_new_protected:cpn { regex_build_one_n*?: } #1 +\cs_new_protected_nopar:cpn { regex_compile_special_group_-:w } #1#2#3#4 { - \int_compare:nNnTF {#1} = \c_zero - { - \regex_build_transitions:NNNN - \regex_action_free:n \l_regex_right_state_int - \regex_tests_action_cost:n \l_regex_left_state_int - } + \str_if_eq:nnTF { #1 #2 #3 #4 } + { \regex_compile_raw:N i \regex_compile_special:N ) } { - \regex_build_one_n: {#1} - \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int - \regex_build_transitions:NNNN - \regex_action_free:n \l_regex_right_state_int - \regex_action_free:n \l_regex_internal_a_int + \cs_set_nopar:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } + \cs_set_nopar:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } } - } -\cs_new_protected_nopar:cpx { regex_build_one_*: } - { \exp_not:c { regex_build_one_n*: } \c_zero } -\cs_new_protected_nopar:cpx { regex_build_one_*?: } - { \exp_not:c { regex_build_one_n*?: } \c_zero } -\cs_new_protected_nopar:cpx { regex_build_one_+: } - { \exp_not:c { regex_build_one_n*: } \c_one } -\cs_new_protected_nopar:cpx { regex_build_one_+?: } - { \exp_not:c { regex_build_one_n*?: } \c_one } -\cs_new_protected_nopar:Npn \regex_build_one_nn: - { - \regex_build_one_nn_aux:nnnn { } { - \regex_build_transitions:NNNN - \regex_tests_action_cost:n \l_regex_right_state_int - \regex_action_free:n \l_regex_internal_a_int + \msg_kernel_warning:nnx { regex } { unknown-option } { (?-#2#4 } + \regex_compile_raw:N ( + \regex_compile_raw:N ? + \regex_compile_raw:N - + #1 #2 #3 #4 } } -\cs_new_protected_nopar:cpn { regex_build_one_nn?: } +\cs_new_protected:cpn { regex_compile_/c: } + { \regex_chk_c_allowed:T { \regex_compile_c_test:NN } } +\cs_new_protected:Npn \regex_compile_c_test:NN #1#2 { - \regex_build_one_nn_aux:nnnn {?} + \token_if_eq_meaning:NNTF #1 \regex_compile_raw:N { - \regex_build_transitions:NNNN - \regex_action_free:n \l_regex_internal_a_int - \regex_tests_action_cost:n \l_regex_right_state_int + \cs_if_exist:cTF { c_regex_catcode_#2_int } + { + \int_set_eq:Nc \l_regex_catcodes_int { c_regex_catcode_#2_int } + \l_regex_mode_int + = \if_case:w \l_regex_mode_int \c_two \else: \c_six \fi: + } } + { \cs_if_exist_use:cF { regex_compile_c_#2:w } } + { + \msg_kernel_error:nnx { regex } { c-missing-category } {#2} + #1 #2 + } } -\cs_new_protected:Npn \regex_build_one_nn_aux:nnnn #1#2#3#4 +\cs_new_protected:cpn { regex_compile_c_[:w } #1#2 { - \regex_build_one_n: {#3} - \int_compare:nNnTF {#3} > {#4} + \l_regex_mode_int + = \if_case:w \l_regex_mode_int \c_two \else: \c_six \fi: + \int_zero:N \l_regex_catcodes_int + \str_if_eq:nnTF { #1 #2 } { \regex_compile_special:N ^ } { - \msg_kernel_error:nnxxx - { regex } { quantifier-backwards } {#3} {#4} {#1} + \bool_set_false:N \l_regex_catcodes_bool + \regex_compile_c_lbrack_loop:NN } { - \int_set:Nn \l_regex_internal_a_int - { \l_regex_right_state_int + #4 - #3 } - \prg_replicate:nn { #4 - #3 } { #2 } + \bool_set_true:N \l_regex_catcodes_bool + \regex_compile_c_lbrack_loop:NN + #1 #2 } } -\cs_new_protected_nopar:cpn { regex_build_one_?: } - { \regex_build_one_nn: \c_zero \c_one } -\cs_new_protected_nopar:cpx { regex_build_one_??: } - { \exp_not:c { regex_build_one_nn?: } \c_zero \c_one } -\cs_new_protected:cpn { regex_build_(: } #1#2 +\cs_new_protected:Npn \regex_compile_c_lbrack_loop:NN #1#2 { - \regex_build_if_in_class:TF + \token_if_eq_meaning:NNTF #1 \regex_compile_raw:N { - \regex_build_raw:N ( - #1 #2 + \cs_if_exist:cTF { c_regex_catcode_#2_int } + { + \exp_args:Nc \regex_compile_c_lbrack_add:N + { c_regex_catcode_#2_int } + \regex_compile_c_lbrack_loop:NN + } } { - \str_if_eq:nnTF { #1 #2 } { \regex_build_special:N ? } - { \regex_build_special_group:NN } + \token_if_eq_charcode:NNTF #2 ] + { \regex_compile_c_lbrack_end: } + } { - \int_incr:N \l_regex_capturing_group_int - \regex_seq_push_int:NN - \l_regex_capturing_group_seq \l_regex_capturing_group_int - \regex_build_open_aux: + \msg_kernel_error:nnx { regex } { c-missing-rbrack } {#2} + \regex_compile_c_lbrack_end: #1 #2 } - } } -\cs_new_protected_nopar:Npn \regex_build_open_aux: +\cs_new_protected:Npn \regex_compile_c_lbrack_add:N #1 { - \regex_build_new_state: - \regex_seq_push_int:NN \l_regex_left_state_seq \l_regex_left_state_int - \regex_seq_push_int:NN \l_regex_right_state_seq \l_regex_right_state_int - \bool_if:NTF \l_regex_caseless_bool - { \seq_push:Nn \l_regex_end_group_seq \regex_build_caseless: } - { \seq_push:Nn \l_regex_end_group_seq \regex_build_caseful: } - \seq_push:Nn \l_regex_end_alternation_seq { } - \regex_build_begin_alternation: + \if_int_odd:w \int_eval:w \l_regex_catcodes_int / #1 \int_eval_end: + \else: + \tex_advance:D \l_regex_catcodes_int #1 + \fi: } -\cs_new_protected_nopar:cpn { regex_build_|: } +\cs_new_protected_nopar:Npn \regex_compile_c_lbrack_end: { - \regex_build_if_in_class:TF { \regex_build_raw:N | } - { - \regex_build_end_alternation: - \regex_build_begin_alternation: - } + \if_meaning:w \c_false_bool \l_regex_catcodes_bool + \int_set:Nn \l_regex_catcodes_int + { \c_regex_all_catcodes_int - \l_regex_catcodes_int } + \fi: } -\cs_new_protected_nopar:cpn { regex_build_): } +\cs_new_protected_nopar:cpn { regex_compile_c_ \c_lbrace_str :w } { - \regex_build_if_in_class:TF { \regex_build_raw:N ) } - { - \seq_if_empty:NTF \l_regex_capturing_group_seq - { \msg_kernel_error:nn { regex } { extra-rparen } } - { - \regex_build_close_aux: - \regex_build_group_quantifier: - } - } + \regex_compile:w + \regex_disable_submatches: + \l_regex_mode_int + = - \if_case:w \l_regex_mode_int \c_two \else: \c_six \fi: } -\cs_new_protected_nopar:Npn \regex_build_close_aux: +\cs_new_protected:cpn { regex_compile_ \c_rbrace_str : } { - \regex_build_end_alternation: - \regex_seq_pop_int:NN \l_regex_left_state_seq \l_regex_left_state_int - \regex_seq_pop_int:NN \l_regex_right_state_seq \l_regex_right_state_int - \regex_seq_pop_use:N \l_regex_end_group_seq - \seq_pop:NN \l_regex_end_alternation_seq \l_regex_internal_a_tl + \regex_if_in_cs:TF + { + \regex_compile_end: + \regex_compile_one:x + { \regex_item_cs:n { \exp_not:o \l_regex_internal_regex } } + } + { \exp_after:wN \regex_compile_raw:N \c_rbrace_str } } -\cs_new_protected_nopar:Npn \regex_build_begin_alternation: +\cs_new_protected:cpn { regex_compile_/u: } #1#2 { - \regex_build_new_state: - \regex_seq_get_int:NN \l_regex_left_state_seq \l_regex_left_state_int - \regex_toks_put_right:Nx \l_regex_left_state_int + \regex_if_in_class_or_catcode:TF + { \regex_compile_raw_error:N u #1 #2 } { - \regex_action_free:n + \str_if_eq:xxTF {#1#2} { \regex_compile_special:N \c_lbrace_str } { - \int_eval:n - { \l_regex_right_state_int - \l_regex_left_state_int } + \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: + \regex_compile_u_loop:NN + } + { + \msg_kernel_error:nn { regex } { u-missing-lbrace } + \regex_compile_raw:N u #1 #2 } } } -\cs_new_protected_nopar:Npn \regex_build_end_alternation: +\cs_new:Npn \regex_compile_u_loop:NN #1#2 { - \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int - \regex_seq_get_int:NN \l_regex_right_state_seq \l_regex_right_state_int - \regex_toks_put_right:Nx \l_regex_left_state_int + \token_if_eq_meaning:NNTF #1 \regex_compile_raw:N + { #2 \regex_compile_u_loop:NN } { - \regex_action_free:n + \token_if_eq_meaning:NNTF #1 \regex_compile_special:N { - \int_eval:n - { \l_regex_right_state_int - \l_regex_left_state_int } + \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #2 + { \if_false: { \fi: } \regex_compile_u_end: } + { #2 \regex_compile_u_loop:NN } + } + { + \if_false: { \fi: } + \msg_kernel_error:nnx { regex } { u-missing-rbrace } {#2} + \regex_compile_u_end: + #1 #2 } } - \regex_seq_get_use:N \l_regex_end_alternation_seq } -\cs_new_protected:Npn \regex_build_special_group:NN #1#2 +\cs_new_protected:Npn \regex_compile_u_end: + { + \tl_set:Nv \l_regex_internal_a_tl { \l_regex_internal_a_tl } + \if_num:w \l_regex_mode_int = \c_zero + \regex_compile_u_not_cs: + \else: + \regex_compile_u_in_cs: + \fi: + } +\cs_new_protected:Npn \regex_compile_u_in_cs: { - \cs_if_exist_use:cF { regex_build_special_group_\token_to_str:N #2 : } + \exp_args:NNo \str_gset_other:Nn \g_regex_internal_tl + { \l_regex_internal_a_tl } + \tl_build_one:x { - \msg_kernel_error:nnx { regex } { special-group-unknown } - { (? \token_to_str:N #2 } %) - \regex_build_special:N ( % ) - \regex_build_raw:N ? - #1 #2 + \tl_map_function:NN \g_regex_internal_tl + \regex_compile_u_in_cs_aux:n } } -\cs_new_protected_nopar:cpn { regex_build_special_group_:: } +\cs_new:Npn \regex_compile_u_in_cs_aux:n #1 { - \regex_seq_push_int:NN \l_regex_capturing_group_seq \c_minus_one - \regex_build_open_aux: + \regex_class:NnnnN \c_true_bool + { \regex_item_caseful_equal:n { \int_value:w `#1 } } + { 1 } { 0 } \c_false_bool } -\cs_new_protected_nopar:cpn { regex_build_special_group_|: } +\cs_new_protected:Npn \regex_compile_u_not_cs: { - \regex_seq_push_int:NN \l_regex_capturing_group_seq \c_minus_one - \regex_build_new_state: - \regex_seq_push_int:NN \l_regex_left_state_seq \l_regex_left_state_int - \regex_seq_push_int:NN \l_regex_right_state_seq \l_regex_right_state_int - \seq_push:Nx \l_regex_end_alternation_seq + \exp_args:No \tl_analysis_map_inline:nn { \l_regex_internal_a_tl } { - \exp_not:N \int_compare:nNnT - \l_regex_capturing_group_int - > \l_regex_capturing_group_max_int + \tl_build_one:n { - \int_set_eq:NN - \l_regex_capturing_group_max_int - \l_regex_capturing_group_int + \regex_class:NnnnN \c_true_bool + { + \if_num:w "##2 = \c_zero + \regex_item_exact_cs:c { \exp_after:wN \cs_to_str:N ##1 } + \else: + \regex_item_exact:nn { \int_value:w "##2 } { ##3 } + \fi: + } + { 1 } { 0 } \c_false_bool } - \int_set:Nn \l_regex_capturing_group_int - { \int_use:N \l_regex_capturing_group_int } } - \seq_push:Nx \l_regex_end_group_seq - { - \bool_if:NTF \l_regex_caseless_bool - \regex_build_caseless: - \regex_build_caseful: - \int_set_eq:NN - \l_regex_capturing_group_int - \l_regex_capturing_group_max_int - } - \regex_build_begin_alternation: } -\cs_new_protected_nopar:Npn \regex_build_special_group_i: +\cs_new_protected_nopar:cpn { regex_compile_/K: } { - \regex_build_options:NNN + - \regex_build_raw:N i + \int_compare:nNnTF \l_regex_mode_int = \c_zero + { \tl_build_one:n { \regex_command_K: } } + { \regex_compile_raw_error:N K } } -\cs_new_protected_nopar:cpn { regex_build_special_group_-: } +\cs_new_protected:Npn \regex_show_aux:Nx #1#2 { - \regex_build_options:NNN - + \tl_set_build:Nw \l_regex_internal_a_tl + \cs_set_protected_nopar:Npn \regex_branch:n + { + \seq_pop_right:NN \l_regex_show_prefix_seq \l_regex_internal_a_tl + \regex_show_one:n { +-branch } + \seq_put_right:No \l_regex_show_prefix_seq \l_regex_internal_a_tl + \use:n + } + \cs_set_protected_nopar:Npn \regex_group:nnnN + { \regex_show_group_aux:nnnnN { } } + \cs_set_protected_nopar:Npn \regex_group_no_capture:nnnN + { \regex_show_group_aux:nnnnN { ~(no~capture) } } + \cs_set_protected_nopar:Npn \regex_group_resetting:nnnN + { \regex_show_group_aux:nnnnN { ~(resetting) } } + \cs_set_eq:NN \regex_class:NnnnN \regex_show_class:NnnnN + \cs_set_protected_nopar:Npn \regex_command_K: + { \regex_show_one:n { reset~match~start~(\iow_char:N\\K) } } + \cs_set_protected:Npn \regex_assertion:Nn ##1##2 + { \regex_show_one:n { \bool_if:NF ##1 { negative~ } assertion:~##2 } } + \cs_set_nopar:Npn \regex_b_test: { word~boundary } + \cs_set_eq:NN \regex_anchor:N \regex_show_anchor_to_str:N + \cs_set_protected:Npn \regex_item_caseful_equal:n ##1 + { \regex_show_one:n { char~code~\int_eval:n{##1} } } + \cs_set_protected:Npn \regex_item_caseful_range:nn ##1##2 + { \regex_show_one:n { range~[\int_eval:n{##1}, \int_eval:n{##2}] } } + \cs_set_protected:Npn \regex_item_caseless_equal:n ##1 + { \regex_show_one:n { char~code~\int_eval:n{##1}~(caseless) } } + \cs_set_protected:Npn \regex_item_caseless_range:nn ##1##2 + { + \regex_show_one:n + { Range~[\int_eval:n{##1}, \int_eval:n{##2}]~(caseless) } + } + \cs_set_protected:Npn \regex_item_catcode:nT + { \regex_show_item_catcode:NnT \c_true_bool } + \cs_set_protected:Npn \regex_item_catcode_reverse:nT + { \regex_show_item_catcode:NnT \c_false_bool } + \cs_set_protected:Npn \regex_item_reverse:n + { \regex_show_scope:nn { Reversed~match } } + \cs_set_protected:Npn \regex_item_exact:nn ##1##2 + { \regex_show_one:n { char~##2,~catcode~##1 } } + \cs_set_protected:Npn \regex_item_exact_cs:c ##1 + { \regex_show_one:n { control~sequence~\iow_char:N\\##1 } } + \cs_set_protected:Npn \regex_item_cs:n + { \regex_show_scope:nn { control~sequence } } + \cs_set:cpn { regex_prop_.: } { \regex_show_one:n { any~token } } + \seq_clear:N \l_regex_show_prefix_seq + \regex_show_push:n { ~ } + #1 + \tl_build_end: + \msg_aux_show:x { > Compiled~regex~#2: \l_regex_internal_a_tl } } -\cs_new_protected:Npn \regex_build_options:NNN #1#2#3 +\cs_new_protected:Npn \regex_show_one:n #1 { - \token_if_eq_meaning:NNTF \regex_build_raw:N #2 - { - \cs_if_exist_use:cF { regex_build_option_#1#3: } - { \msg_kernel_error:nnx { regex } { unknown-option } { #3 } } - \regex_build_options:NNN #1 - } - { - \prg_case_str:nnn { #3 } - { % ( - { ) } { } - { - } { \regex_build_options:NNN - } - } - { \msg_kernel_error:nnx { regex } { invalid-in-option } { #3 } } - } + \int_incr:N \l_regex_show_lines_int + \tl_build_one:x + { \iow_newline: \seq_use:N \l_regex_show_prefix_seq #1 } } -\cs_new_protected_nopar:cpn { regex_build_option_+i: } +\cs_new_protected:Npn \regex_show_push:n #1 + { \seq_put_right:Nx \l_regex_show_prefix_seq { #1 ~ } } +\cs_new_protected:Npn \regex_show_pop: + { \seq_pop_right:NN \l_regex_show_prefix_seq \l_regex_internal_a_tl } +\cs_new_protected:Npn \regex_show_scope:nn #1#2 { - \regex_build_caseless: - \cs_set_eq:NN \regex_match_loop_case_hook: - \regex_match_loop_caseless_hook: + \regex_show_one:n {#1} + \regex_show_push:n { ~ } + #2 + \regex_show_pop: } -\cs_new_protected_nopar:cpn { regex_build_option_-i: } - { \regex_build_caseful: } -\cs_new_protected_nopar:Npn \regex_build_group_quantifier: +\cs_new_protected:Npn \regex_show_group_aux:nnnnN #1#2#3#4#5 { - \tl_set:Nn \l_regex_one_or_group_tl { group } - \regex_build_quantifier:w + \regex_show_one:n { ,-group~begin #1 } + \regex_show_push:n { | } + \use_ii:nn #2 + \regex_show_pop: + \regex_show_one:n + { `-group~end \regex_msg_repeated:nnN {#3} {#4} #5 } } -\cs_new_protected:Npn \regex_build_group_submatches:NN #1#2 +\cs_set:Npn \regex_show_class:NnnnN #1#2#3#4#5 { - \seq_pop:NN \l_regex_capturing_group_seq \l_regex_internal_a_tl - \int_compare:nNnF { \l_regex_internal_a_tl } < \c_zero + \tl_set_build:Nw \l_regex_internal_a_tl + \int_zero:N \l_regex_show_lines_int + \regex_show_push:n {~} + #2 + \exp_last_unbraced:Nf + \prg_case_int:nnn { \l_regex_show_lines_int } { - \regex_toks_put_left:Nx #1 - { \regex_action_submatch:n { \l_regex_internal_a_tl < } } - \regex_toks_put_left:Nx #2 - { \regex_action_submatch:n { \l_regex_internal_a_tl > } } - } - } -\cs_new_protected_nopar:Npn \regex_build_group_qs_aux: - { - \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int - \regex_build_new_state: - \tex_toks:D \l_regex_right_state_int = \tex_toks:D \l_regex_internal_a_int - \regex_toks_put_left:Nx \l_regex_right_state_int - { - \int_sub:Nn \l_regex_current_state_int + {0} { - \int_eval:n % ^^A here we lie! - { \l_regex_right_state_int - \l_regex_internal_a_int } + \tl_build_end: + \regex_show_one:n { \bool_if:NTF #1 { Fail } { Pass } } } - } - \use:x - { - \tex_toks:D \l_regex_internal_a_int + {1} { - \s_stop - \regex_action_free:n + \tl_build_end: + \bool_if:NTF #1 { - \int_eval:n - { \l_regex_right_state_int - \l_regex_internal_a_int } + #2 + \tl_build_one:n { \regex_msg_repeated:nnN {#3} {#4} #5 } + } + { + \regex_show_one:n + { Don't~match~\regex_msg_repeated:nnN {#3} {#4} #5 } + \tl_build_one:o \l_regex_internal_a_tl } } } - \regex_build_group_submatches:NN - \l_regex_right_state_int \l_regex_left_state_int + { + \tl_build_end: + \regex_show_one:n + { + \bool_if:NTF #1 { M } { Don't~m } atch + \regex_msg_repeated:nnN {#3} {#4} #5 + } + \tl_build_one:o \l_regex_internal_a_tl + } } -\cs_new_protected:Npn \regex_build_group_qs_aux:NN #1#2 +\cs_new:Npn \regex_show_anchor_to_str:N #1 { - \regex_build_group_qs_aux: - \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int - \regex_build_transition:NN \regex_action_free:n #1 - #2 \l_regex_internal_a_int + anchor~at~ + \prg_case_str:nnn { #1 } { - \regex_action_free:n - { \int_eval:n { \l_regex_right_state_int - \l_regex_internal_a_int } } + { \l_regex_min_pos_int } { start~(\iow_char:N\\A) } + { \l_regex_start_pos_int } { start~of~match~(\iow_char:N\\G) } + { \l_regex_max_pos_int } { end~(\iow_char:N\\Z) } } + { <error:~'#1'~not~recognized> } } -\cs_new_protected_nopar:cpn { regex_build_group_?: } +\cs_new_protected:Npn \regex_show_item_catcode:NnT #1#2 { - \regex_build_group_qs_aux:NN - \l_regex_right_state_int \regex_toks_put_right:Nx + \seq_set_split:Nnn \l_regex_internal_seq { } { CBEMTPUDSLOA } + \seq_set_filter:NNn \l_regex_internal_seq \l_regex_internal_seq + { \int_if_odd_p:n { #2 / \int_use:c { c_regex_catcode_##1_int } } } + \regex_show_scope:nn + { + categories~\seq_use:N \l_regex_internal_seq, ~ + \bool_if:NF #1 { negative~ } class + } } -\cs_new_protected_nopar:cpn { regex_build_group_??: } +\int_new:N \l_regex_min_state_int +\int_new:N \l_regex_max_state_int +\int_new:N \l_regex_left_state_int +\int_new:N \l_regex_right_state_int +\seq_new:N \l_regex_left_state_seq +\seq_new:N \l_regex_right_state_seq +\int_new:N \l_regex_capturing_group_int +\cs_new_protected:Npn \regex_build:n #1 { - \regex_build_group_qs_aux:NN - \l_regex_right_state_int \regex_toks_put_left:Nx + \regex_compile:n {#1} + \regex_build:N \l_regex_internal_regex } -\cs_new_protected:Npn \regex_build_group_transition_right_max: +\cs_new_protected:Npn \regex_build:N #1 { - \regex_toks_put_right:Nx \l_regex_right_state_int - { - \regex_action_free:n - { \int_eval:n { \l_regex_max_state_int - \l_regex_right_state_int } } - } + \int_set:Nn \tex_escapechar:D { 92 } + \int_zero:N \l_regex_capturing_group_int + \int_set_eq:NN \l_regex_max_state_int \l_regex_min_state_int + \regex_build_new_state: + \regex_build_new_state: + \regex_toks_put_right:Nn \l_regex_left_state_int + { \regex_action_start_wildcard: } + \regex_group:nnnN {#1} { 1 } { 0 } \c_false_bool + \regex_toks_put_right:Nn \l_regex_right_state_int + { \regex_action_success: } } -\cs_new_protected:Npn \regex_build_group_n_aux:n #1 +\cs_new_protected:Npn \regex_build_for_cs:n #1 { - \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int - \int_set_eq:NN \l_regex_internal_b_int \l_regex_max_state_int - \int_add:Nn \l_regex_right_state_int - { ( #1 - 1 ) * ( \l_regex_max_state_int - \l_regex_left_state_int ) } - \int_set:Nn \l_regex_max_state_int - { - \l_regex_left_state_int - + (#1) * ( \l_regex_max_state_int - \l_regex_left_state_int ) - } - \int_while_do:nNnn \l_regex_internal_b_int < \l_regex_max_state_int + \int_set_eq:NN \l_regex_max_state_int \l_regex_min_state_int + \regex_build_new_state: + \regex_build_new_state: + \regex_push_lr_states: + #1 + \regex_pop_lr_states: + \regex_toks_put_right:Nn \l_regex_right_state_int { - \tex_toks:D \l_regex_internal_b_int - = \tex_toks:D \l_regex_internal_a_int - \int_incr:N \l_regex_internal_a_int - \int_incr:N \l_regex_internal_b_int + \if_num:w \l_regex_current_pos_int = \l_regex_max_pos_int + \exp_after:wN \regex_action_success: + \fi: } } -\cs_new_protected:Npn \regex_build_group_n: #1 +\cs_new_protected_nopar:Npn \regex_push_lr_states: { - \regex_build_group_transition_right_max: - \regex_build_group_n_aux:n {#1} - \regex_build_new_state: - \int_compare:nNnF {#1} = \c_zero - { - \regex_build_group_submatches:NN - \l_regex_internal_a_int \l_regex_left_state_int - } + \seq_push:No \l_regex_left_state_seq + { \int_use:N \l_regex_left_state_int } + \seq_push:No \l_regex_right_state_seq + { \int_use:N \l_regex_right_state_int } } -\cs_new_eq:cN { regex_build_group_n?: } \regex_build_group_n: -\cs_new_protected_nopar:Npn \regex_build_group_: - { \regex_build_group_n: \c_one } -\cs_new_protected_nopar:cpn { regex_build_group_n*: } +\cs_new_protected_nopar:Npn \regex_pop_lr_states: { - \regex_build_group_n_star_aux:NNn - \regex_toks_put_right:Nx \regex_toks_put_left:Nx + \seq_pop:NN \l_regex_left_state_seq \l_regex_internal_a_tl + \int_set:Nn \l_regex_left_state_int \l_regex_internal_a_tl + \seq_pop:NN \l_regex_right_state_seq \l_regex_internal_a_tl + \int_set:Nn \l_regex_right_state_int \l_regex_internal_a_tl } -\cs_new_protected_nopar:cpn { regex_build_group_n*?: } +\cs_new_protected:Npn \regex_toks_put_left:Nx #1#2 { - \regex_build_group_n_star_aux:NNn - \regex_toks_put_left:Nx \regex_toks_put_right:Nx + \cs_set_nopar:Npx \regex_tmp:w { #2 } + \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 } } -\cs_new_protected:Npn \regex_build_group_n_star_aux:NNn #1#2#3 +\cs_new_protected:Npn \regex_toks_put_right:Nx #1#2 { - \int_compare:nNnTF {#3} = \c_zero - { \regex_build_group_qs_aux:NN \l_regex_internal_a_int #1 } - { - \regex_build_group_transition_right_max: - \regex_build_group_n_aux:n {#3} - \regex_build_new_state: - #2 \l_regex_left_state_int - { - \regex_action_free:n - { - \int_eval:n - { \l_regex_internal_a_int - \l_regex_left_state_int } - } - } - \regex_build_group_submatches:NN - \l_regex_internal_a_int \l_regex_left_state_int - } + \cs_set_nopar:Npx \regex_tmp:w {#2} + \tex_toks:D #1 \exp_after:wN + { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w } } -\cs_new_protected_nopar:cpx { regex_build_group_*: } - { \exp_not:c { regex_build_group_n*: } \c_zero } -\cs_new_protected_nopar:cpx { regex_build_group_*?: } - { \exp_not:c { regex_build_group_n*?: } \c_zero } -\cs_new_protected_nopar:cpx { regex_build_group_+: } - { \exp_not:c { regex_build_group_n*: } \c_one } -\cs_new_protected_nopar:cpx { regex_build_group_+?: } - { \exp_not:c { regex_build_group_n*?: } \c_one } -\cs_new_protected_nopar:Npn \regex_build_group_nn: +\cs_new_protected:Npn \regex_toks_put_right:Nn #1#2 + { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } } +\cs_new_protected:Npn \regex_build_transition_left:NNN #1#2#3 + { \regex_toks_put_left:Nx #2 { #1 { \int_eval:n { #3 - #2 } } } } +\cs_new_protected:Npn \regex_build_transition_right:nNn #1#2#3 + { \regex_toks_put_right:Nx #2 { #1 { \int_eval:n { #3 - #2 } } } } +\cs_new_protected_nopar:Npn \regex_build_new_state: { - \regex_build_group_nn_aux:nnnn { } - \regex_build_group_transition_right_max: + \tex_toks:D \l_regex_max_state_int { } + \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int + \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int + \int_incr:N \l_regex_max_state_int } -\cs_new_protected_nopar:cpn { regex_build_group_nn?: } +\cs_new_protected:Npn \regex_build_transitions_lazyness:NNNNN #1#2#3#4#5 { - \regex_build_group_nn_aux:nnnn { } + \regex_build_new_state: + \regex_toks_put_right:Nx \l_regex_left_state_int { - \use:x - { - \tex_toks:D \l_regex_right_state_int - { - \exp_after:wN \regex_build_group_nn_aux_ii:w - \tex_the:D \tex_toks:D \l_regex_right_state_int - } - } + \if_meaning:w \c_true_bool #1 + #2 { \int_eval:n { #3 - \l_regex_left_state_int } } + #4 { \int_eval:n { #5 - \l_regex_left_state_int } } + \else: + #4 { \int_eval:n { #5 - \l_regex_left_state_int } } + #2 { \int_eval:n { #3 - \l_regex_left_state_int } } + \fi: } } -\cs_new_protected:Npn \regex_build_group_nn_aux:nnnn #1#2#3#4 +\cs_new_protected:Npn \regex_class:NnnnN #1#2#3#4#5 { - \int_compare:nNnTF {#3} > {#4} - { - \msg_kernel_error:nnxxx - { regex } { quantifier-backwards } {#3} {#4} {#1} - } + \cs_set_nopar:Npx \regex_tests_action_cost:n ##1 { - \int_compare:nNnTF {#3} = \c_zero - { - \regex_build_group_qs_aux: - \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int - \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int - \regex_build_group_transition_right_max: - \regex_build_group_n_aux:n { #4 - #3 } - \int_set_eq:NN \l_regex_internal_c_int \l_regex_right_state_int - \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int - \prg_replicate:nn { #4 - #3 } - { - #2 - \int_add:Nn \l_regex_right_state_int - { \l_regex_internal_b_int - \l_regex_internal_a_int } - } - \int_set_eq:NN \l_regex_right_state_int \l_regex_internal_c_int - \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int - \regex_build_new_state: - } - { - \regex_build_group_transition_right_max: - \regex_build_group_n_aux:n {#3} - \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int - \regex_build_group_submatches:NN - \l_regex_left_state_int \l_regex_right_state_int - \regex_build_group_n_aux:n { #4 - #3 + \c_one } - \int_sub:Nn \l_regex_right_state_int - { \l_regex_internal_a_int - \l_regex_left_state_int } - \prg_replicate:nn { #4 - #3 } - { - #2 - \int_add:Nn \l_regex_right_state_int - { \l_regex_internal_b_int - \l_regex_internal_a_int } - } - \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int - \regex_build_new_state: - } + \exp_not:n { \exp_not:n {#2} } + \bool_if:NTF #1 + { \regex_break_point:TF { \regex_action_cost:n {##1} } { } } + { \regex_break_point:TF { } { \regex_action_cost:n {##1} } } } + \if_case:w - #4 \exp_stop_f: + \regex_class_repeat:n {#3} + \or: \regex_class_repeat:nN {#3} #5 + \else: \regex_class_repeat:nnN {#3} {#4} #5 + \fi: } -\cs_new_protected:Npn \regex_build_group_nn_aux_ii:w #1 \regex_action_free:n +\cs_new:Npn \regex_tests_action_cost:n { \regex_action_cost:n } +\cs_new_protected:Npn \regex_class_repeat:n #1 { - #1 - \regex_action_free:n + \prg_replicate:nn {#1} { - \int_eval:n - { \l_regex_max_state_int - \l_regex_right_state_int } + \regex_build_new_state: + \regex_build_transition_right:nNn \regex_tests_action_cost:n + \l_regex_left_state_int \l_regex_right_state_int } - \regex_action_free:n } -\cs_new_protected:cpn { regex_build_/u: } #1#2 +\cs_new_protected:Npn \regex_class_repeat:nN #1#2 { - \regex_build_if_assertions_forbidden:TF - { \regex_build_raw_error:N u #1#2 } - { - \str_if_eq:xxTF {#1#2} { \regex_build_special:N \c_lbrace_str } - { - \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: - \regex_build_u_loop:NN - } - { - \msg_kernel_error:nn { regex } { u-missing-lbrace } - #1#2 - } - } + \if_num:w #1 = \c_zero + \regex_build_transitions_lazyness:NNNNN #2 + \regex_action_free:n \l_regex_right_state_int + \regex_tests_action_cost:n \l_regex_left_state_int + \else: + \regex_class_repeat:n {#1} + \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int + \regex_build_transitions_lazyness:NNNNN #2 + \regex_action_free:n \l_regex_right_state_int + \regex_action_free:n \l_regex_internal_a_int + \fi: } -\cs_new:Npn \regex_build_u_loop:NN #1#2 +\cs_new_protected:Npn \regex_class_repeat:nnN #1#2#3 { - \token_if_eq_meaning:NNTF #1 \regex_build_raw:N - { #2 \regex_build_u_loop:NN } + \regex_class_repeat:n {#1} + \int_set:Nn \l_regex_internal_a_int + { \l_regex_max_state_int + #2 - \c_one } + \prg_replicate:nn { #2 } { - \token_if_eq_meaning:NNTF #1 \regex_build_special:N - { - \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #2 - { \if_false: { \fi: } \regex_build_u_end: } - { #2 \regex_build_u_loop:NN } - } - { - \if_false: { \fi: } - \msg_kernel_error:nnx { regex } { u-missing-rbrace } {#2} - \regex_build_u_end: - #1#2 - } + \regex_build_transitions_lazyness:NNNNN #3 + \regex_action_free:n \l_regex_internal_a_int + \regex_tests_action_cost:n \l_regex_right_state_int } } -\cs_new_protected:Npn \regex_build_u_end: +\cs_new_protected:Npn \regex_group_aux:nnnnN #1#2#3#4#5 { - \tl_set:Nv \l_regex_internal_a_tl \l_regex_internal_a_tl - \if_num:w \l_regex_build_mode_int = \c_zero - \regex_build_u_not_cs: - \else: - \regex_build_u_in_cs: - \fi: - \tl_clear:N \l_regex_tests_tl + \if_num:w #3 = \c_zero + \regex_build_new_state: + \regex_build_transition_right:nNn \regex_action_free_group:n + \l_regex_left_state_int \l_regex_right_state_int + \fi: + \regex_build_new_state: + \regex_push_lr_states: + #2 + \regex_pop_lr_states: + \if_case:w - #4 \exp_stop_f: + \regex_group_repeat:nn {#1} {#3} + \or: \regex_group_repeat:nnN {#1} {#3} #5 + \else: \regex_group_repeat:nnnN {#1} {#3} {#4} #5 + \fi: } -\cs_new_protected:Npn \regex_build_u_in_cs: +\cs_new_protected:Npn \regex_group:nnnN #1 { - \exp_args:NNo \str_gset_other:Nn \g_regex_internal_tl - { \l_regex_internal_a_tl } - \tl_map_inline:Nn \g_regex_internal_tl + \exp_args:No \regex_group_aux:nnnnN + { \int_use:N \l_regex_capturing_group_int } { - \tl_set:Nx \l_regex_tests_tl { \regex_item_equal:n { `##1 } } - \regex_build_one_: + \int_incr:N \l_regex_capturing_group_int + #1 } } -\cs_new_protected:Npn \regex_build_u_not_cs: +\cs_new_protected_nopar:Npn \regex_group_no_capture:nnnN + { \regex_group_aux:nnnnN { -1 } } +\cs_new_protected:Npn \regex_group_resetting:nnnN #1 { - \exp_args:No \tl_analysis_map_inline:nn { \l_regex_internal_a_tl } + \regex_group_aux:nnnnN { -1 } { - \tl_set:Nx \l_regex_tests_tl - { - \exp_not:N \int_compare:nNnT - \l_regex_current_catcode_int = { \int_value:w "##2 } - { - \int_compare:nNnTF { "##2 } = \c_zero - { - \exp_not:n - { \str_if_eq:xxT { \l_regex_current_token_tl } {##1} } - { \regex_break_true:w } - } - { \regex_item_equal:n {##3} } - } - } - \regex_build_one_: + \exp_args:Noo \regex_group_resetting_loop:nnNn + { \int_use:N \l_regex_capturing_group_int } + { \int_use:N \l_regex_capturing_group_int } + #1 + { ?? \prg_map_break:n } { } + \prg_break_point:n { } } } -\cs_new_protected:Npn \regex_store_state:n #1 +\cs_new_protected:Npn \regex_group_resetting_loop:nnNn #1#2#3#4 { - \int_incr:N \l_regex_max_active_int - \tex_skip:D \l_regex_max_active_int #1 sp \scan_stop: - \regex_store_submatches:n {#1} + \use_none:nn #3 { \int_set:Nn \l_regex_capturing_group_int {#1} } + \int_set:Nn \l_regex_capturing_group_int {#2} + #3 {#4} + \exp_args:Nf \regex_group_resetting_loop:nnNn + { \int_max:nn {#1} { \l_regex_capturing_group_int } } + {#2} } -\cs_new_protected_nopar:Npn \regex_state_use_with_submatches: - { \regex_state_use_aux:n { } } -\cs_new_protected_nopar:Npn \regex_state_use: - { \regex_state_use_aux:n { \exp_after:wN \use_none_delimit_by_s_stop:w } } -\cs_new_protected:Npn \regex_state_use_aux:n #1 +\cs_new_protected:Npn \regex_branch:n #1 { - \if_num:w \tex_dimen:D \l_regex_current_state_int < \l_regex_step_int - \tex_dimen:D \l_regex_current_state_int - = \l_regex_step_int sp \scan_stop: - #1 \tex_the:D \tex_toks:D \exp_after:wN \l_regex_current_state_int - \fi: - \scan_stop: + \regex_build_new_state: + \seq_get:NN \l_regex_left_state_seq \l_regex_internal_a_tl + \int_set:Nn \l_regex_left_state_int \l_regex_internal_a_tl + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_left_state_int \l_regex_right_state_int + #1 + \seq_get:NN \l_regex_right_state_seq \l_regex_internal_a_tl + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_internal_a_tl } -\cs_new_protected_nopar:Npn \regex_disable_submatches: +\cs_new_protected:Npn \regex_group_repeat:nn #1#2 { - \cs_set_eq:NN \regex_state_use_with_submatches: \regex_state_use: - \cs_set_eq:NN \regex_store_submatches:n - \regex_protected_use_none:n - \cs_set_eq:NN \regex_action_submatches:n - \regex_protected_use_none:n + \if_num:w #2 = \c_zero + \int_set:Nn \l_regex_max_state_int + { \l_regex_left_state_int - \c_one } + \regex_build_new_state: + \else: + \regex_group_repeat_aux:n {#2} + \regex_group_submatches:nNN {#1} + \l_regex_internal_a_int \l_regex_right_state_int + \regex_build_new_state: + \fi: } -\cs_new_protected:Npn \regex_protected_use_none:n #1 { } -\cs_new_protected:Npn \regex_store_submatches:n #1 +\cs_new_protected:Npn \regex_group_submatches:nNN #1#2#3 { - \tex_toks:D #1 \exp_after:wN - { - \tex_romannumeral:D - \exp_after:wN \regex_store_submatches_aux:w - \tex_the:D \tex_toks:D #1 - } + \if_num:w #1 > \c_minus_one + \regex_toks_put_left:Nx #2 { \regex_action_submatch:n { #1 < } } + \regex_toks_put_left:Nx #3 { \regex_action_submatch:n { #1 > } } + \fi: } -\cs_new_protected:Npn \regex_store_submatches_aux:w #1 \s_stop +\cs_new_protected:Npn \regex_group_repeat_aux:n #1 { - \regex_store_submatches_aux_ii:Nnnw - #1 - \regex_state_submatches:nn \c_minus_one \q_prop - \s_stop + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_max_state_int + \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int + \int_set_eq:NN \l_regex_internal_b_int \l_regex_max_state_int + \if_num:w \int_eval:w #1 > \c_one + \int_set:Nn \l_regex_internal_c_int + { + ( #1 - \c_one ) + * ( \l_regex_internal_b_int - \l_regex_internal_a_int ) + } + \tex_advance:D \l_regex_right_state_int \l_regex_internal_c_int + \tex_advance:D \l_regex_max_state_int \l_regex_internal_c_int + \prg_replicate:nn \l_regex_internal_c_int + { + \tex_toks:D \l_regex_internal_b_int + = \tex_toks:D \l_regex_internal_a_int + \tex_advance:D \l_regex_internal_a_int \c_one + \tex_advance:D \l_regex_internal_b_int \c_one + } + \fi: } -\cs_new_protected:Npn \regex_store_submatches_aux_ii:Nnnw - \regex_state_submatches:nn #1 #2 #3 \s_stop +\cs_new_protected:Npn \regex_group_repeat:nnN #1#2#3 { - \exp_after:wN \c_zero - \exp_after:wN \regex_state_submatches:nn \exp_after:wN - { \int_value:w \int_eval:w \l_regex_step_int + \c_one \exp_after:wN } - \exp_after:wN { \l_regex_current_submatches_prop } - \regex_state_submatches:nn {#1} {#2} - \s_stop + \if_num:w #2 = \c_zero + \regex_group_submatches:nNN {#1} + \l_regex_left_state_int \l_regex_right_state_int + \int_set:Nn \l_regex_internal_a_int + { \l_regex_left_state_int - \c_one } + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_internal_a_int + \regex_build_new_state: + \if_meaning:w \c_true_bool #3 + \regex_build_transition_left:NNN \regex_action_free:n + \l_regex_internal_a_int \l_regex_right_state_int + \else: + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_internal_a_int \l_regex_right_state_int + \fi: + \else: + \regex_group_repeat_aux:n {#2} + \regex_group_submatches:nNN {#1} + \l_regex_internal_a_int \l_regex_right_state_int + \if_meaning:w \c_true_bool #3 + \regex_build_transition_right:nNn \regex_action_free_group:n + \l_regex_right_state_int \l_regex_internal_a_int + \else: + \regex_build_transition_left:NNN \regex_action_free_group:n + \l_regex_right_state_int \l_regex_internal_a_int + \fi: + \regex_build_new_state: + \fi: } -\cs_new_protected:Npn \regex_state_submatches:nn #1#2 +\cs_new_protected:Npn \regex_group_repeat:nnnN #1#2#3#4 { - \if_num:w #1 = \l_regex_step_int - \tl_set:Nn \l_regex_current_submatches_prop { #2 } + \regex_group_submatches:nNN {#1} + \l_regex_left_state_int \l_regex_right_state_int + \regex_group_repeat_aux:n { #2 + #3 } + \if_meaning:w \c_true_bool #4 + \int_set_eq:NN \l_regex_left_state_int \l_regex_max_state_int + \prg_replicate:nn { #3 } + { + \int_sub:Nn \l_regex_left_state_int + { \l_regex_internal_b_int - \l_regex_internal_a_int } + \regex_build_transition_left:NNN \regex_action_free:n + \l_regex_left_state_int \l_regex_max_state_int + } + \else: + \prg_replicate:nn { #3 - \c_one } + { + \int_sub:Nn \l_regex_right_state_int + { \l_regex_internal_b_int - \l_regex_internal_a_int } + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_max_state_int + } + \if_num:w #2 = \c_zero + \int_set:Nn \l_regex_right_state_int + { \l_regex_left_state_int - \c_one } + \else: + \int_sub:Nn \l_regex_right_state_int + { \l_regex_internal_b_int - \l_regex_internal_a_int } + \fi: + \regex_build_transition_right:nNn \regex_action_free:n + \l_regex_right_state_int \l_regex_max_state_int \fi: + \regex_build_new_state: } -\cs_new_protected:Npn \regex_match:n #1 +\cs_new_protected:Npn \regex_assertion:Nn #1#2 { - \int_zero:N \l_regex_nesting_int - \int_set_eq:NN \l_regex_current_index_int \l_regex_max_state_int - \regex_query_set:nnn { } { -1 } { -2 } - \int_set_eq:NN \l_regex_min_index_int \l_regex_current_index_int - \tl_analysis_map_inline:nn {#1} + \regex_build_new_state: + \regex_toks_put_right:Nx \l_regex_left_state_int { - \regex_query_set:nnn {##1} {"##2} {##3} - \if_case:w "##2 \exp_stop_f: - \or: \int_incr:N \l_regex_nesting_int - \or: \int_decr:N \l_regex_nesting_int - \fi: + \exp_not:n {#2} + \regex_break_point:TF + \bool_if:NF #1 { { } } + { + \regex_action_free:n + { + \int_eval:n + { \l_regex_right_state_int - \l_regex_left_state_int } + } + } + \bool_if:NT #1 { { } } } - \int_set_eq:NN \l_regex_max_index_int \l_regex_current_index_int - \regex_query_set:nnn { } { -1 } { -2 } - \regex_match_initial_setup: - \regex_match_once: } -\cs_new_protected:Npn \regex_query_set:nnn #1#2#3 +\cs_new_protected:Npn \regex_anchor:N #1 { - \tex_muskip:D \l_regex_current_index_int - = \etex_gluetomu:D - #3 sp - plus #2 sp - minus \l_regex_nesting_int sp - \scan_stop: - \tex_toks:D \l_regex_current_index_int {#1} - \int_incr:N \l_regex_current_index_int + \if_num:w #1 = \l_regex_current_pos_int + \exp_after:wN \regex_break_true:w + \fi: } -\cs_new_protected_nopar:Npn \regex_query_get: +\cs_new_protected_nopar:Npn \regex_b_test: { - \tl_set:Nx \l_regex_current_token_tl - { \tex_the:D \tex_toks:D \l_regex_current_index_int } - \l_regex_current_char_int - = \etex_mutoglue:D \tex_muskip:D \l_regex_current_index_int - \l_regex_current_catcode_int = \etex_gluestretch:D - \etex_mutoglue:D \tex_muskip:D \l_regex_current_index_int + \group_begin: + \int_set_eq:NN \l_regex_current_char_int \l_regex_last_char_int + \regex_prop_w: + \regex_break_point:TF + { \group_end: \regex_item_reverse:n \regex_prop_w: } + { \group_end: \regex_prop_w: } } -\cs_new_protected_nopar:Npn \regex_match_once: +\cs_new_protected_nopar:Npn \regex_command_K: { - \regex_match_setup: - \regex_query_get: - \regex_match_loop: - \prg_break_point:n { } - \bool_if:NT \l_regex_success_match_bool + \regex_build_new_state: + \regex_toks_put_right:Nx \l_regex_left_state_int { - \bool_gset_true:N \g_regex_success_bool - \l_regex_every_match_tl + \regex_action_submatch:n { 0< } + \bool_set_true:N \l_regex_fresh_thread_bool + \regex_action_free:n + { \int_eval:n { \l_regex_right_state_int - \l_regex_left_state_int } } + \bool_set_false:N \l_regex_fresh_thread_bool } } -\cs_new_protected_nopar:Npn \regex_match_initial_setup: +\int_new:N \l_regex_min_pos_int +\int_new:N \l_regex_max_pos_int +\int_new:N \l_regex_current_pos_int +\int_new:N \l_regex_start_pos_int +\int_new:N \l_regex_success_pos_int +\int_new:N \l_regex_current_char_int +\int_new:N \l_regex_current_catcode_int +\int_new:N \l_regex_last_char_int +\int_new:N \l_regex_case_changed_char_int +\int_new:N \l_regex_current_state_int +\prop_new:N \l_regex_current_submatches_prop +\prop_new:N \l_regex_success_submatches_prop +\int_new:N \l_regex_step_int +\int_new:N \l_regex_min_active_int +\int_new:N \l_regex_max_active_int +\tl_new:N \l_regex_every_match_tl +\bool_new:N \l_regex_fresh_thread_bool +\bool_new:N \l_regex_empty_success_bool +\cs_new_eq:NN \regex_if_two_empty_matches:F \use:n +\bool_new:N \g_regex_success_bool +\bool_new:N \l_regex_saved_success_bool +\bool_new:N \l_regex_match_success_bool +\cs_new_protected:Npn \regex_match:n #1 { - \int_set_eq:NN \l_regex_step_int \c_minus_one - \prg_stepwise_inline:nnnn - \c_zero \c_one { \l_regex_max_state_int - \c_one } - { \tex_dimen:D ##1 \l_regex_step_int sp } - \int_set:Nn \l_regex_start_index_int - { \l_regex_min_index_int - \c_one } - \int_set_eq:NN \l_regex_current_index_int \l_regex_min_index_int - \int_set_eq:NN \l_regex_success_index_int \l_regex_min_index_int - \int_set_eq:NN \l_regex_submatch_int \l_regex_max_state_int - \bool_set_false:N \l_regex_success_empty_bool + \int_zero:N \l_regex_balance_int + \int_set:Nn \l_regex_current_pos_int { \c_two * \l_regex_max_state_int } + \regex_query_set:nnn { } { -1 } { -2 } + \int_set_eq:NN \l_regex_min_pos_int \l_regex_current_pos_int + \tl_analysis_map_inline:nn {#1} + { \regex_query_set:nnn {##1} {"##2} {##3} } + \int_set_eq:NN \l_regex_max_pos_int \l_regex_current_pos_int + \regex_query_set:nnn { } { -1 } { -2 } \bool_gset_false:N \g_regex_success_bool + \prg_stepwise_inline:nnnn + \l_regex_min_state_int \c_one { \l_regex_max_state_int - \c_one } + { \tex_dimen:D ##1 \c_one sp \scan_stop: } + \int_set_eq:NN \l_regex_min_active_int \l_regex_max_state_int + \int_set_eq:NN \l_regex_step_int \c_zero + \int_set_eq:NN \l_regex_success_pos_int \l_regex_min_pos_int + \int_set:Nn \l_regex_submatch_int + { \c_two * \l_regex_max_state_int } + \bool_set_false:N \l_regex_empty_success_bool + \regex_match_once: } -\cs_new_protected_nopar:Npn \regex_match_setup: +\cs_new_protected_nopar:Npn \regex_match_once: { + \if_meaning:w \c_true_bool \l_regex_empty_success_bool + \cs_set_nopar:Npn \regex_if_two_empty_matches:F + { \int_compare:nNnF \l_regex_start_pos_int = \l_regex_current_pos_int } + \else: + \cs_set_eq:NN \regex_if_two_empty_matches:F \use:n + \fi: + \int_set_eq:NN \l_regex_start_pos_int \l_regex_success_pos_int + \bool_set_false:N \l_regex_match_success_bool \prop_clear:N \l_regex_current_submatches_prop - \bool_if:NTF \l_regex_success_empty_bool - { \cs_set_eq:NN \regex_if_two_empty_matches:F \regex_if_match_empty:F } - { \cs_set_eq:NN \regex_if_two_empty_matches:F \use:n } - \int_set_eq:NN \l_regex_start_index_int \l_regex_success_index_int - \int_set:Nn \l_regex_current_index_int - { \l_regex_start_index_int - \c_one } - \bool_set_false:N \l_regex_success_match_bool - \int_zero:N \l_regex_max_active_int - \regex_store_state:n {0} %^^A _state_int! + \int_set_eq:NN \l_regex_max_active_int \l_regex_min_active_int + \regex_store_state:n { \l_regex_min_state_int } + \int_set:Nn \l_regex_current_pos_int + { \l_regex_start_pos_int - \c_one } + \regex_query_get: + \regex_match_loop: + \l_regex_every_match_tl + } +\cs_new_protected_nopar:Npn \regex_single_match: + { + \tl_set:Nn \l_regex_every_match_tl + { \bool_gset_eq:NN \g_regex_success_bool \l_regex_match_success_bool } + } +\cs_new_protected:Npn \regex_multi_match:n #1 + { + \tl_set:Nn \l_regex_every_match_tl + { + \if_meaning:w \c_true_bool \l_regex_match_success_bool + \bool_gset_true:N \g_regex_success_bool + #1 + \exp_after:wN \regex_match_once: + \fi: + } } \cs_new_protected_nopar:Npn \regex_match_loop: { - \int_incr:N \l_regex_current_index_int - \int_incr:N \l_regex_step_int - \bool_set_false:N \l_regex_fresh_thread_bool + \tex_advance:D \l_regex_step_int \c_two + \int_incr:N \l_regex_current_pos_int \int_set_eq:NN \l_regex_last_char_int \l_regex_current_char_int + \int_set_eq:NN \l_regex_case_changed_char_int \c_max_int \regex_query_get: - \regex_match_loop_case_hook: \use:x { - \int_zero:N \l_regex_max_active_int - \regex_match_one_active:w 1 ; \prg_break_point:n { } - \exp_not:N \prg_break_point:n { } + \int_set_eq:NN \l_regex_max_active_int \l_regex_min_active_int + \exp_after:wN \regex_match_one_active:w + \int_use:N \l_regex_min_active_int ; } - \if_num:w \l_regex_current_char_int < \c_minus_one - \exp_after:wN \prg_map_break: - \fi: - \if_num:w \l_regex_max_active_int = \c_zero - \exp_after:wN \prg_map_break: + \prg_break_point:n { \bool_set_false:N \l_regex_fresh_thread_bool } + \if_num:w \l_regex_max_active_int > \l_regex_min_active_int + \if_num:w \l_regex_current_pos_int < \l_regex_max_pos_int + \exp_after:wN \exp_after:wN \exp_after:wN \regex_match_loop: + \fi: \fi: - \regex_match_loop: } \cs_new:Npn \regex_match_one_active:w #1; { - \if_num:w #1 > \l_regex_max_active_int - \exp_after:wN \prg_map_break: + \if_num:w #1 < \l_regex_max_active_int + \regex_use_state_and_submatches:nn + { \int_value:w \tex_skip:D #1 } + { \tex_the:D \tex_toks:D #1 } + \exp_after:wN \regex_match_one_active:w + \int_use:N \int_eval:w #1 + \c_one \exp_after:wN ; \fi: - \regex_match_one_active_aux:n - { \int_value:w \tex_skip:D #1 } - \exp_after:wN \regex_match_one_active:w - \int_use:N \int_eval:w #1 + \c_one ; } -\cs_new_protected:Npn \regex_match_one_active_aux:n #1 +\cs_new_protected:Npn \regex_query_set:nnn #1#2#3 { - \int_set:Nn \l_regex_current_state_int {#1} - \prop_clear:N \l_regex_current_submatches_prop - \regex_state_use_with_submatches: + \tex_muskip:D \l_regex_current_pos_int + = \etex_gluetomu:D + #3 sp + plus #2 sp + minus \l_regex_balance_int sp + \scan_stop: + \tex_toks:D \l_regex_current_pos_int {#1} + \int_incr:N \l_regex_current_pos_int + \if_case:w #2 \exp_stop_f: + \or: \int_incr:N \l_regex_balance_int + \or: \int_decr:N \l_regex_balance_int + \fi: } -\cs_new_protected_nopar:Npn \regex_match_loop_case_hook: { } -\cs_new_protected_nopar:Npn \regex_match_loop_caseless_hook: +\cs_new_protected_nopar:Npn \regex_query_get: { - \int_set_eq:NN \l_regex_case_changed_char_int \l_regex_current_char_int - \if_num:w \l_regex_current_char_int < \c_ninety_one - \if_num:w \l_regex_current_char_int < \c_sixty_five - \else: - \int_add:Nn \l_regex_case_changed_char_int { \c_thirty_two } - \fi: - \else: - \if_num:w \l_regex_current_char_int < \c_one_hundred_twenty_three - \if_num:w \l_regex_current_char_int < \c_ninety_seven - \else: - \int_sub:Nn \l_regex_case_changed_char_int { \c_thirty_two } - \fi: - \fi: + \l_regex_current_char_int + = \etex_mutoglue:D \tex_muskip:D \l_regex_current_pos_int + \l_regex_current_catcode_int = \etex_gluestretch:D + \etex_mutoglue:D \tex_muskip:D \l_regex_current_pos_int + } +\cs_new_protected_nopar:Npn \regex_use_state: + { + \tex_dimen:D \l_regex_current_state_int + = \l_regex_step_int sp \scan_stop: + \tex_the:D \tex_toks:D \l_regex_current_state_int + \tex_dimen:D \l_regex_current_state_int + = \int_eval:w \l_regex_step_int + \c_one \int_eval_end: sp \scan_stop: + } +\cs_new_protected:Npn \regex_use_state_and_submatches:nn #1 #2 + { + \int_set:Nn \l_regex_current_state_int {#1} + \if_num:w \tex_dimen:D \l_regex_current_state_int < \l_regex_step_int + \tl_set:Nn \l_regex_current_submatches_prop {#2} + \exp_after:wN \regex_use_state: \fi: + \scan_stop: } \cs_new_protected_nopar:Npn \regex_action_start_wildcard: { @@ -1846,96 +1949,145 @@ \bool_set_false:N \l_regex_fresh_thread_bool \regex_action_cost:n {0} } +\cs_new_protected_nopar:Npn \regex_action_free:n + { \regex_action_free_aux:nn { > \l_regex_step_int \else: } } +\cs_new_protected_nopar:Npn \regex_action_free_group:n + { \regex_action_free_aux:nn { < \l_regex_step_int } } +\cs_new_protected:Npn \regex_action_free_aux:nn #1#2 + { + \use:x + { + \int_add:Nn \l_regex_current_state_int {#2} + \exp_not:n + { + \if_num:w \tex_dimen:D \l_regex_current_state_int #1 + \exp_after:wN \regex_use_state: + \fi: + } + \int_set:Nn \l_regex_current_state_int + { \int_use:N \l_regex_current_state_int } + \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop + { \exp_not:o \l_regex_current_submatches_prop } + } + } \cs_new_protected:Npn \regex_action_cost:n #1 { - \exp_args:Nf \regex_store_state:n - { \int_eval:n { \l_regex_current_state_int + #1 } } + \exp_args:No \regex_store_state:n + { \int_use:N \int_eval:w \l_regex_current_state_int + #1 } + } +\cs_new_protected:Npn \regex_store_state:n #1 + { + \regex_store_submatches: + \tex_skip:D \l_regex_max_active_int = #1 sp \scan_stop: + \int_incr:N \l_regex_max_active_int + } +\cs_new_protected_nopar:Npn \regex_store_submatches: + { + \tex_toks:D \l_regex_max_active_int \exp_after:wN + { \l_regex_current_submatches_prop } + } +\cs_new_protected_nopar:Npn \regex_disable_submatches: + { + \cs_set_protected_nopar:Npn \regex_store_submatches: { } + \cs_set_protected:Npn \regex_action_submatch:n ##1 { } + } +\cs_new_protected:Npn \regex_action_submatch:n #1 + { + \prop_put:Nno \l_regex_current_submatches_prop {#1} + { \int_use:N \l_regex_current_pos_int } } \cs_new_protected_nopar:Npn \regex_action_success: { \regex_if_two_empty_matches:F { - \bool_set_true:N \l_regex_success_match_bool - \bool_set_eq:NN \l_regex_success_empty_bool + \bool_set_true:N \l_regex_match_success_bool + \bool_set_eq:NN \l_regex_empty_success_bool \l_regex_fresh_thread_bool - \int_set_eq:NN \l_regex_success_index_int \l_regex_current_index_int + \int_set_eq:NN \l_regex_success_pos_int \l_regex_current_pos_int \prop_set_eq:NN \l_regex_success_submatches_prop \l_regex_current_submatches_prop \prg_map_break: } } -\cs_new_protected:Npn \regex_action_free:n #1 +\int_new:N \l_regex_replacement_csnames_int +\tl_new:N \l_regex_balance_tl +\cs_new:Npn \regex_replacement_balance_one_match:n #1 + { - \regex_submatch_balance:n {#1} } +\cs_new:Npn \regex_replacement_do_one_match:n #1 { - \use:x - { - \int_add:Nn \l_regex_current_state_int {#1} - \regex_state_use: - \int_set:Nn \l_regex_current_state_int - { \int_use:N \l_regex_current_state_int } - \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop - { \exp_not:o \l_regex_current_submatches_prop } - } + \regex_query_range:nn + { \etex_glueshrink:D \tex_skip:D #1 } + { \tex_skip:D #1 } } -\cs_new_protected:Npn \regex_action_submatch:n #1 +\cs_new:Npn \regex_replacement_exp_not:N #1 { \exp_not:n {#1} } +\cs_new:Npn \regex_query_range:nn #1#2 { - \prop_put:Nno \l_regex_current_submatches_prop {#1} - { \int_use:N \l_regex_current_index_int } + \exp_after:wN \regex_query_range_loop:ww + \int_use:N \int_eval:w #1 \exp_after:wN ; + \int_use:N \int_eval:w #2 ; + \prg_break_point:n { } } -\cs_new:Npn \regex_if_match_empty:T - { \int_compare:nNnT \l_regex_start_index_int = \l_regex_current_index_int } -\cs_new:Npn \regex_if_match_empty:F - { \int_compare:nNnF \l_regex_start_index_int = \l_regex_current_index_int } -\cs_new_protected:Npn \regex_submatch_nesting_aux:n #1 +\cs_new:Npn \regex_query_range_loop:ww #1 ; #2 ; { - + \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D - \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1 - - \tex_muskip:D \tex_skip:D #1 - \scan_stop: + \if_num:w #1 < #2 \exp_stop_f: + \else: + \exp_after:wN \prg_map_break: + \fi: + \tex_the:D \tex_toks:D #1 \exp_stop_f: + \exp_after:wN \regex_query_range_loop:ww + \int_use:N \int_eval:w #1 + \c_one ; #2 ; } -\cs_new:Npn \regex_nesting:n #1 { } %^^A move. Rename? -\tl_new:N \l_regex_nesting_tl -\cs_new_protected:Npn \regex_replacement:n #1 +\cs_new:Npn \regex_query_submatch:n #1 { - \int_zero:N \l_regex_replacement_int - \int_zero:N \l_regex_nesting_int - \tl_clear:N \l_regex_nesting_tl - \regex_escape_use:nnnn - { \regex_replacement_unescaped:N ##1 } - { \regex_replacement_escaped:N ##1 } - { \regex_replacement_raw:N ##1 } - {#1} - \prg_do_nothing: \prg_do_nothing: - \cs_set:Npx \regex_nesting:n ##1 - { - + \int_use:N \l_regex_nesting_int - \l_regex_nesting_tl - - \regex_submatch_nesting_aux:n {##1} - } - \use:x - { - \exp_not:n { \cs_set:Npn \regex_replacement_tl:n ##1 } - { \regex_toks_range:nn \c_zero \l_regex_replacement_int } - } - % ^^A rename! + \regex_query_range:nn + { \tex_skip:D \int_eval:w #1 } + { \etex_gluestretch:D \tex_skip:D \int_eval:w #1 } } -\cs_new_protected:Npn \regex_replacement_raw:N #1 - { \regex_replacement_put:n {#1} } -\cs_new_protected:Npn \regex_replacement_put:n #1 +\cs_new_protected:Npn \regex_submatch_balance:n #1 { - \tex_toks:D \l_regex_replacement_int {#1} - \int_incr:N \l_regex_replacement_int + \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D + \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1 + - \tex_muskip:D \tex_skip:D #1 + \scan_stop: } -\cs_new_protected:Npn \regex_replacement_unescaped:N #1 +\cs_new_protected:Npn \regex_replacement:n #1 { - \if_charcode:w \c_rbrace_str #1 - \if_num:w \l_regex_replacement_csnames_int > \c_zero - \regex_replacement_put:n \cs_end: - \else: - \regex_replacement_put:n #1 + \tl_set_build:Nw \l_regex_internal_a_tl + \int_zero:N \l_regex_balance_int + \tl_clear:N \l_regex_balance_tl + \regex_escape_use:nnnn + { + \if_charcode:w \c_rbrace_str ##1 + \regex_replacement_rbrace:N \else: \tl_build_one:n \fi: ##1 + } + { \regex_replacement_escaped:N ##1 } + { \tl_build_one:n ##1 } + {#1} + \prg_do_nothing: \prg_do_nothing: + \if_int_compare:w \l_regex_replacement_csnames_int > \c_zero + \msg_kernel_error:nnx { regex } { replacement-missing-rbrace } + { \int_use:N \l_regex_replacement_csnames_int } + \tl_build_one:x + { \prg_replicate:nn \l_regex_replacement_csnames_int \cs_end: } \fi: - \else: - \regex_replacement_put:n #1 - \fi: + \cs_gset:Npx \regex_replacement_balance_one_match:n ##1 + { + + \int_use:N \l_regex_balance_int + \l_regex_balance_tl + - \regex_submatch_balance:n {##1} + } + \tl_build_end: + \exp_args:No \regex_replacement_aux:n \l_regex_internal_a_tl + } +\cs_new_protected:Npn \regex_replacement_aux:n #1 + { + \cs_set:Npn \regex_replacement_do_one_match:n ##1 + { + \regex_query_range:nn + { \etex_glueshrink:D \tex_skip:D ##1 } + { \tex_skip:D ##1 } + #1 + } } \cs_new_protected:Npn \regex_replacement_escaped:N #1 { @@ -1944,34 +2096,23 @@ \if_num:w \c_one < 1#1 \exp_stop_f: \regex_replacement_put_submatch:n {#1} \else: - \regex_replacement_put:n #1 + \tl_build_one:n #1 \fi: } } \cs_new_protected:Npn \regex_replacement_put_submatch:n #1 { - \regex_replacement_put:n - { \regex_query_submatch:nn {#1} {##1} } - \if_num:w \l_regex_replacement_csnames_int = \c_zero - \tl_put_right:Nn \l_regex_nesting_tl - { - \exp_not:N \if_num:w #1 < \l_regex_capturing_group_int - \regex_submatch_nesting_aux:n { \int_eval:w #1+##1 \int_eval_end: } - \exp_not:N \fi: - } + \if_num:w #1 < \l_regex_capturing_group_int + \tl_build_one:n { \regex_query_submatch:n { #1 + ##1 } } + \if_num:w \l_regex_replacement_csnames_int = \c_zero + \tl_put_right:Nn \l_regex_balance_tl + { + \regex_submatch_balance:n { \int_eval:w #1+##1 \int_eval_end: } } + \fi: \fi: } -\cs_new_protected:Npn \regex_replacement_error:NNN #1#2#3 - { - \msg_kernel_error:nnxx { regex } { #1-command } - { replacement~text } {#3} - #2 #3 - } \cs_new_protected:Npn \regex_replacement_g:w #1#2 { - \str_if_eq:xxTF - { \exp_not:n { #1#2 } } - { \regex_replacement_unescaped:N \c_lbrace_str } + \str_if_eq:xxTF { #1#2 } { \tl_build_one:n \c_lbrace_str } { \int_zero:N \l_regex_internal_a_int \regex_replacement_g_digits:NN @@ -1980,40 +2121,33 @@ } \cs_new_protected:Npn \regex_replacement_g_digits:NN #1#2 { - \token_if_eq_meaning:NNTF #1 \regex_replacement_unescaped:N + \token_if_eq_meaning:NNTF #1 \tl_build_one:n { \if_num:w \c_one < 1#2 \exp_stop_f: - \int_set:Nn \l_regex_internal_a_int { \c_ten * \l_regex_internal_a_int + #2 } + \int_set:Nn \l_regex_internal_a_int + { \c_ten * \l_regex_internal_a_int + #2 } \exp_after:wN \use_i:nnn \exp_after:wN \regex_replacement_g_digits:NN \else: - \if_charcode:w \c_rbrace_str #2 - \exp_args:No \regex_replacement_put_submatch:n - { \int_use:N \l_regex_internal_a_int } - \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn - \else: - \exp_after:wN \exp_after:wN - \exp_after:wN \regex_replacement_error:NNN - \exp_after:wN \exp_after:wN \exp_after:wN g - \fi: + \exp_after:wN \regex_replacement_error:NNN + \exp_after:wN g \fi: } - { \regex_replacement_error:NNN g } - #1 #2 - } -\cs_new_protected:Npn \regex_replacement_u:w #1#2 - { - \str_if_eq:xxTF { #1#2 } { \regex_replacement_unescaped:N \c_lbrace_str } { - \int_incr:N \l_regex_replacement_csnames_int - \regex_replacement_put:n - { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } } + \if_meaning:w \regex_replacement_rbrace:N #1 + \exp_args:No \regex_replacement_put_submatch:n + { \int_use:N \l_regex_internal_a_int } + \exp_after:wN \use_none:nn + \else: + \exp_after:wN \regex_replacement_error:NNN + \exp_after:wN g + \fi: } - { \regex_replacement_error:NNN u #1#2 } + #1 #2 } \cs_new_protected:Npn \regex_replacement_c:w #1#2 { - \token_if_eq_meaning:NNTF #1 \regex_replacement_unescaped:N + \token_if_eq_meaning:NNTF #1 \tl_build_one:n { \cs_if_exist_use:cF { regex_replacement_c_#2:w } { \regex_replacement_error:NNN c #1#2 } @@ -2022,121 +2156,173 @@ } \cs_new_protected_nopar:cpn { regex_replacement_c_ \c_lbrace_str :w } { + \if_case:w \l_regex_replacement_csnames_int + \tl_build_one:n + { \exp_not:n { \exp_after:wN \regex_replacement_exp_not:N \cs:w } } + \else: + \tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:N \cs:w } } + \fi: \int_incr:N \l_regex_replacement_csnames_int - \regex_replacement_put:n - { \exp_not:n { \exp_after:wN \regex_replacement_exp_not:N \cs:w } } } -\cs_new:Npn \regex_replacement_exp_not:N #1 { \exp_not:n {#1} } +\cs_new_protected:Npn \regex_replacement_u:w #1#2 + { + \str_if_eq:xxTF { #1#2 } { \tl_build_one:n \c_lbrace_str } + { + \if_case:w \l_regex_replacement_csnames_int + \tl_build_one:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } } + \else: + \tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } } + \fi: + \int_incr:N \l_regex_replacement_csnames_int + } + { \regex_replacement_error:NNN u #1#2 } + } +\cs_new_protected:Npn \regex_replacement_rbrace:N #1 + { + \if_int_compare:w \l_regex_replacement_csnames_int > \c_zero + \tl_build_one:n \cs_end: + \int_decr:N \l_regex_replacement_csnames_int + \else: + \tl_build_one:n #1 + \fi: + } \group_begin: - - \char_set_catcode_math_superscript:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_U:w - { \regex_replacement_char:nNN { ^^@ } } - - \char_set_catcode_alignment:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_T:w + \cs_new_protected:Npn \regex_replacement_char:nNN #1#2#3 + { + \if_meaning:w \prg_do_nothing: #3 + \msg_kernel_error:nn { regex } { replacement-catcode-end } + \else: + \tex_lccode:D \c_zero = `#3 \scan_stop: + \tl_to_lowercase:n { \tl_build_one:n {#1} } + \fi: + } + \char_set_catcode_active:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_A:w + { \regex_replacement_char:nNN { \exp_not:n { \exp_not:N ^^@ } } } + \char_set_catcode_group_begin:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_B:w + { + \if_num:w \l_regex_replacement_csnames_int = \c_zero + \int_incr:N \l_regex_balance_int + \fi: + \regex_replacement_char:nNN + { \exp_not:n { \exp_after:wN ^^@ \if_false: } \fi: } } + } + \cs_new_protected:Npn \regex_replacement_c_C:w #1#2 + { \tl_build_one:n { \exp_not:N \exp_not:N \exp_not:c {#2} } } + \char_set_catcode_math_subscript:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_D:w { \regex_replacement_char:nNN { ^^@ } } - - \cs_new_protected:Npn \regex_replacement_c_S:w #1#2 + \char_set_catcode_group_end:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_E:w { - \int_compare:nNnTF { `#2 } = \c_zero - { \regex_replacement_error:NNN c #1#2 } - { - \char_set_lccode:nn {32} { `#2 } - \tl_to_lowercase:n { \regex_replacement_put:n {~} } - } + \if_num:w \l_regex_replacement_csnames_int = \c_zero + \int_decr:N \l_regex_balance_int + \fi: + \regex_replacement_char:nNN + { \exp_not:n { \if_false: { \fi: ^^@ } } } - - \char_set_catcode_parameter:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_P:w - { \regex_replacement_char:nNN { ^^@^^@^^@^^@^^@^^@^^@^^@ } } - - \char_set_catcode_other:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_O:w + \char_set_catcode_letter:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_L:w { \regex_replacement_char:nNN { ^^@ } } - \char_set_catcode_math_toggle:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_M:w { \regex_replacement_char:nNN { ^^@ } } - - \char_set_catcode_letter:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_L:w + \char_set_catcode_other:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_O:w { \regex_replacement_char:nNN { ^^@ } } - - \char_set_catcode_group_end:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_E:w + \char_set_catcode_parameter:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_P:w { - \int_decr:N \l_regex_nesting_int - \regex_replacement_char:nNN { \if_false: { \fi: ^^@ } + \regex_replacement_char:nNN + { \exp_not:n { \exp_not:n { ^^@^^@^^@^^@ } } } } - - \char_set_catcode_math_subscript:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_D:w - { \regex_replacement_char:nNN { ^^@ } } - - \char_set_catcode_group_begin:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_B:w + \cs_new_protected:Npn \regex_replacement_c_S:w #1#2 { - \int_incr:N \l_regex_nesting_int - \regex_replacement_char:nNN { \exp_after:wN ^^@ \if_false: } \fi: } + \if_meaning:w \prg_do_nothing: #2 + \msg_kernel_error:nn { regex } { replacement-catcode-end } + \else: + \if_num:w `#2 = \c_zero + \msg_kernel_error:nn { regex } { replacement-null-space } + \fi: + \tex_lccode:D 32 = `#2 \scan_stop: + \tl_to_lowercase:n { \tl_build_one:n {~} } + \fi: } - - \char_set_catcode_active:N \^^@ - \cs_new_protected_nopar:Npn \regex_replacement_c_A:w - { \regex_replacement_char:nNN { \exp_not:N ^^@ } } - + \char_set_catcode_alignment:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_T:w + { \regex_replacement_char:nNN { ^^@ } } + \char_set_catcode_math_superscript:N \^^@ + \cs_new_protected_nopar:Npn \regex_replacement_c_U:w + { \regex_replacement_char:nNN { ^^@ } } \group_end: - -\cs_new_protected:Npn \regex_replacement_char:nNN #1#2#3 +\cs_new_protected:Npn \regex_replacement_error:NNN #1#2#3 { - \char_set_lccode:nn \c_zero { `#3 } - \tl_to_lowercase:n - { \regex_replacement_put:n { \exp_not:n {#1} } } + \msg_kernel_error:nnx { regex } { replacement-#1 } {#3} + #2 #3 } -\cs_new_protected_nopar:Npn \regex_set:Nn - { \regex_set_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \regex_gset:Nn - { \regex_set_aux:NNn \tl_gset:Nn } -\cs_new_protected_nopar:Npn \regex_const:Nn - { \regex_set_aux:NNn \tl_const:Nn } -\cs_new_protected:Npn \regex_set_aux:NNn #1#2#3 +\cs_new_protected:Npn \regex_new:N #1 + { \cs_new_eq:NN #1 \c_regex_no_match_regex } +\cs_new_protected_nopar:Npn \regex_set:Nn #1#2 { - \group_begin: - \regex_build:n {#3} - \use:x - { - \group_end: - #1 \exp_not:N #2 { \regex_set_aux:N #2 } - } + \regex_compile:n {#2} + \tl_set_eq:NN #1 \l_regex_internal_regex } -\cs_new:Npn \regex_set_aux:N #1 +\cs_new_protected_nopar:Npn \regex_gset:Nn #1#2 { - \exp_not:n { \regex_nfa:Nw #1 } - \l_regex_max_state_int - = \int_use:N \l_regex_max_state_int - \l_regex_capturing_group_int - = \int_use:N \l_regex_capturing_group_int - \token_if_eq_meaning:NNT - \regex_match_loop_case_hook: - \regex_match_loop_caseless_hook: - { - \cs_set_eq:NN \regex_match_loop_case_hook: - \regex_match_loop_caseless_hook: - } - \prg_stepwise_function:nnnN - \c_zero \c_one {\l_regex_max_state_int - \c_one } - \regex_set_aux:n - \s_stop + \regex_compile:n {#2} + \tl_gset_eq:NN #1 \l_regex_internal_regex + } +\cs_new_protected_nopar:Npn \regex_const:Nn #1#2 + { + \regex_compile:n {#2} + \tl_const:Nx #1 { \exp_not:o \l_regex_internal_regex } } -\cs_new:Npn \regex_set_aux:n #1 - { \tex_toks:D #1 { \tex_the:D \tex_toks:D #1 } } -\cs_new:Npn \regex_nfa:Nw #1 +\cs_new_protected:Npn \regex_show:n #1 { - \msg_expandable_kernel_error:nnn { regex } { nfa-misused } {#1} - \use_none_delimit_by_s_stop:w + \regex_compile:n {#1} + \regex_show_aux:Nx \l_regex_internal_regex + { { \tl_to_str:n {#1} } } } -\cs_new_protected_nopar:Npn \regex_use:N - { \exp_last_unbraced:No \use_none:nn } +\cs_new_protected:Npn \regex_show:N #1 + { \regex_show_aux:Nx #1 { variable~\token_to_str:N #1 } } +\prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF } + { + \regex_match_aux:nn { \regex_build:n {#1} } {#2} + \regex_aux_return: + } +\prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF } + { + \regex_match_aux:nn { \regex_build:N #1 } {#2} + \regex_aux_return: + } +\cs_new_protected:Npn \regex_count:nnN #1 + { \regex_count_aux:nnN { \regex_build:n {#1} } } +\cs_new_protected:Npn \regex_count:NnN #1 + { \regex_count_aux:nnN { \regex_build:N #1 } } +\cs_set_protected:Npn \regex_tmp:w #1#2#3 + { + \cs_new_protected:Npn #2 ##1 { #1 { \regex_build:n {##1} } } + \cs_new_protected:Npn #3 ##1 { #1 { \regex_build:N ##1 } } + \prg_new_protected_conditional:Npnn #2 ##1##2##3 { T , F , TF } + { #1 { \regex_build:n {##1} } {##2} ##3 \regex_aux_return: } + \prg_new_protected_conditional:Npnn #3 ##1##2##3 { T , F , TF } + { #1 { \regex_build:N ##1 } {##2} ##3 \regex_aux_return: } + } +\regex_tmp:w \regex_extract_once_aux:nnN + \regex_extract_once:nnN \regex_extract_once:NnN +\regex_tmp:w \regex_extract_all_aux:nnN + \regex_extract_all:nnN \regex_extract_all:NnN +\regex_tmp:w \regex_replace_once_aux:nnN + \regex_replace_once:nnN \regex_replace_once:NnN +\regex_tmp:w \regex_replace_all_aux:nnN + \regex_replace_all:nnN \regex_replace_all:NnN +\regex_tmp:w \regex_split_aux:nnN \regex_split:nnN \regex_split:NnN +\int_new:N \l_regex_match_count_int +\flag_new:n { regex_begin } +\flag_new:n { regex_end } +\int_new:N \l_regex_submatch_int +\int_new:N \l_regex_zeroth_submatch_int \cs_new_protected_nopar:Npn \regex_aux_return: { \if_meaning:w \c_true_bool \g_regex_success_bool @@ -2145,79 +2331,67 @@ \prg_return_false: \fi: } -\cs_new_protected:Npn \regex_aux_build_match:nn #1#2 +\cs_new_protected:Npn \regex_match_aux:nn #1#2 { - \regex_build:n {#1} - \regex_match:n {#2} - } -\cs_new_protected:Npn \regex_aux_use_match:Nn #1#2 - { - \exp_args:No \tl_if_head_eq_meaning:nNTF {#1} \regex_nfa:Nw - { - \regex_use:N #1 - \regex_match:n {#2} - } - { - \msg_kernel_error:nnx { regex } { not-nfa } { \token_to_str:N #1 } - \bool_gset_false:N \g_regex_success_bool - } + \group_begin: + \regex_disable_submatches: + \regex_single_match: + #1 + \regex_match:n {#2} + \group_end: } -\cs_set_protected:Npn \regex_tmp:w #1#2#3 +\cs_new_protected:Npn \regex_count_aux:nnN #1#2#3 { - \cs_new_protected_nopar:Npn #1 - { #3 \regex_aux_build_match:nn } - \cs_new_protected_nopar:Npn #2 - { #3 \regex_aux_use_match:Nn } - \prg_new_protected_conditional:Npnn #1 ##1##2##3 { T , F , TF } - { - #3 \regex_aux_build_match:nn {##1} {##2} ##3 - \regex_aux_return: - } - \prg_new_protected_conditional:Npnn #2 ##1##2##3 { T , F , TF } - { - #3 \regex_aux_use_match:Nn {##1} {##2} ##3 - \regex_aux_return: - } + \group_begin: + \regex_disable_submatches: + \int_zero:N \l_regex_match_count_int + \regex_multi_match:n { \int_incr:N \l_regex_match_count_int } + #1 + \regex_match:n {#2} + \exp_args:NNNo + \group_end: + \int_set:Nn #3 { \int_use:N \l_regex_match_count_int } } -\tl_map_inline:nn +\cs_new_protected:Npn \regex_extract_once_aux:nnN #1#2#3 { - { extract_once } { extract_all } - { replace_once } { replace_all } - { split } + \group_begin: + \regex_single_match: + #1 + \regex_match:n {#2} + \regex_extract: + \regex_group_end_extract_seq:N #3 } +\cs_new_protected:Npn \regex_extract_all_aux:nnN #1#2#3 { - \exp_args:Nccc \regex_tmp:w - { regex_#1:nnN } { regex_#1:NnN } { regex_#1_aux:NnnN } + \group_begin: + \regex_multi_match:n { \regex_extract: } + #1 + \regex_match:n {#2} + \regex_group_end_extract_seq:N #3 } -\cs_new_protected_nopar:Npn \regex_extract: +\cs_new_protected:Npn \regex_split_aux:nnN #1#2#3 { - \int_set_eq:NN \l_regex_submatch_start_int \l_regex_submatch_int - \if_meaning:w \c_true_bool \g_regex_success_bool - \prg_replicate:nn \l_regex_capturing_group_int - { - \tex_skip:D \l_regex_submatch_int \c_zero sp \scan_stop: - \int_incr:N \l_regex_submatch_int - } - \prop_map_inline:Nn \l_regex_success_submatches_prop + \group_begin: + \regex_multi_match:n { - \if_num:w ##1 \c_max_int - \exp_after:wN \regex_extract_aux_b:wn \int_use:N - \else: - \exp_after:wN \regex_extract_aux_e:wn \int_use:N + \if_num:w \l_regex_start_pos_int < \l_regex_success_pos_int + \regex_extract: + \tex_skip:D \l_regex_zeroth_submatch_int + = \l_regex_start_pos_int sp + plus \tex_skip:D \l_regex_zeroth_submatch_int \scan_stop: \fi: - \int_eval:w \l_regex_submatch_start_int + ##1 {##2} } - \fi: - } -\cs_new_protected:Npn \regex_extract_aux_b:wn #1 < #2 - { - \tex_skip:D #1 = #2 sp - plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop: - } -\cs_new_protected:Npn \regex_extract_aux_e:wn #1 > #2 - { - \tex_skip:D #1 - = 1 \tex_skip:D #1 plus #2 sp \scan_stop: + #1 + \regex_match:n {#2} + \tex_skip:D \l_regex_submatch_int + = \l_regex_start_pos_int sp plus \l_regex_max_pos_int sp \scan_stop: + \int_incr:N \l_regex_submatch_int + \if_meaning:w \c_true_bool \l_regex_empty_success_bool + \if_num:w \l_regex_start_pos_int = \l_regex_max_pos_int + \int_decr:N \l_regex_submatch_int + \fi: + \fi: + \regex_group_end_extract_seq:N #3 } \cs_new_protected:Npn \regex_group_end_extract_seq:N #1 { @@ -2227,7 +2401,7 @@ \tl_set:Nx \l_regex_internal_a_tl { \prg_stepwise_function:nnnN - \l_regex_max_state_int + { \c_two * \l_regex_max_state_int } \c_one { \l_regex_submatch_int - \c_one } \regex_extract_seq_aux:n @@ -2235,17 +2409,24 @@ \int_compare:nNnF { \flag_height:n { regex_begin } + \flag_height:n { regex_end } } = \c_zero - { \msg_kernel_error:nn { regex } { sequence-unbalanced } } - \tl_set:Nx \l_regex_internal_a_tl { \l_regex_internal_a_tl } - \exp_args:NNNo \group_end: - \tl_set:Nn #1 \l_regex_internal_a_tl + { + \msg_kernel_error:nnxxx { regex } { result-unbalanced } + { splitting~or~extracting~submatches } + { \flag_height:n { regex_end } } + { \flag_height:n { regex_begin } } + } + \use:x + { + \group_end: + \tl_set:Nn \exp_not:N #1 { \l_regex_internal_a_tl } + } } \cs_new:Npn \regex_extract_seq_aux:n #1 { \seq_item:n { \exp_after:wN \regex_extract_seq_aux:ww - \int_value:w \regex_submatch_nesting_aux:n {#1} ; #1; + \int_value:w \regex_submatch_balance:n {#1} ; #1; } } \cs_new:Npn \regex_extract_seq_aux:ww #1; #2; @@ -2254,184 +2435,124 @@ \flag_raise:n { regex_end } \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } } \fi: - \regex_query_submatch:w #2; + \regex_query_submatch:n {#2} \if_num:w #1 > \c_zero \flag_raise:n { regex_begin } \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } } \fi: } -\prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF } - { - \regex_match_aux:n - { \regex_aux_build_match:nn {#1} {#2} } - } -\prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF } - { - \regex_match_aux:n - { \regex_aux_use_match:Nn #1 {#2} } - } -\cs_new_protected:Npn \regex_match_aux:n #1 - { - \group_begin: - \tl_clear:N \l_regex_every_match_tl - \regex_disable_submatches: - #1 - \group_end: - \regex_aux_return: - } -\cs_new_protected_nopar:Npn \regex_count:nnN - { \regex_count_aux:NnnN \regex_aux_build_match:nn } -\cs_new_protected_nopar:Npn \regex_count:NnN - { \regex_count_aux:NnnN \regex_aux_use_match:Nn } -\cs_new_protected:Npn \regex_count_aux:NnnN #1#2#3#4 +\cs_new_protected_nopar:Npn \regex_extract: { - \group_begin: - \regex_disable_submatches: - \int_zero:N \l_regex_match_count_int - \tl_set:Nn \l_regex_every_match_tl + \if_meaning:w \c_true_bool \g_regex_success_bool + \int_set_eq:NN \l_regex_zeroth_submatch_int \l_regex_submatch_int + \prg_replicate:nn \l_regex_capturing_group_int { - \int_incr:N \l_regex_match_count_int - \regex_match_once: + \tex_skip:D \l_regex_submatch_int \c_zero sp \scan_stop: + \int_incr:N \l_regex_submatch_int } - #1 {#2} {#3} - \exp_args:NNNo - \group_end: - \int_set:Nn #4 { \int_use:N \l_regex_match_count_int } - } -\cs_new_protected:Npn \regex_extract_once_aux:NnnN #1#2#3#4 - { - \group_begin: - \tl_set:Nn \l_regex_every_match_tl { \regex_extract: } - #1 {#2} {#3} - \regex_group_end_extract_seq:N #4 + \prop_map_inline:Nn \l_regex_success_submatches_prop + { + \if_num:w ##1 \c_minus_one + \exp_after:wN \regex_extract_aux_e:wn \int_value:w + \else: + \exp_after:wN \regex_extract_aux_b:wn \int_value:w + \fi: + \int_eval:w \l_regex_zeroth_submatch_int + ##1 {##2} + } + \tex_skip:D \l_regex_zeroth_submatch_int + = \tex_the:D \tex_skip:D \l_regex_zeroth_submatch_int + minus \l_regex_start_pos_int sp \scan_stop: + \fi: } -\cs_new_protected:Npn \regex_extract_all_aux:NnnN #1#2#3#4 +\cs_new_protected:Npn \regex_extract_aux_b:wn #1 < #2 { - \group_begin: - \tl_set:Nn \l_regex_every_match_tl - { \regex_extract: \regex_match_once: } - #1 {#2} {#3} - \regex_group_end_extract_seq:N #4 + \tex_skip:D #1 = #2 sp + plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop: } -\cs_new_protected:Npn \regex_split_aux:NnnN #1#2#3#4 +\cs_new_protected:Npn \regex_extract_aux_e:wn #1 > #2 { - \group_begin: - \tl_set:Nn \l_regex_every_match_tl - { - \if_num:w \l_regex_start_index_int < \l_regex_success_index_int - \regex_extract: - \tex_skip:D \l_regex_submatch_start_int - = \l_regex_start_index_int sp - plus \tex_skip:D \l_regex_submatch_start_int \scan_stop: - \fi: - \regex_match_once: - } - #1 {#2} {#3} - \tex_skip:D \l_regex_submatch_int - = \l_regex_start_index_int sp - plus \l_regex_current_index_int sp \scan_stop: - \int_incr:N \l_regex_submatch_int - \if_num:w \l_regex_start_index_int = \l_regex_current_index_int - \if_meaning:w \c_true_bool \l_regex_success_empty_bool - \int_decr:N \l_regex_submatch_int - \fi: - \fi: - \regex_group_end_extract_seq:N #4 + \tex_skip:D #1 + = 1 \tex_skip:D #1 plus #2 sp \scan_stop: } -\cs_new_protected:Npn \regex_replace_once_aux:NnnN #1#2#3#4 +\cs_new_protected:Npn \regex_replace_once_aux:nnN #1#2#3 { \group_begin: - \tl_clear:N \l_regex_every_match_tl - \regex_replacement:n {#3} - \exp_args:Nno #1 {#2} #4 - \if_meaning:w \c_true_bool \g_regex_success_bool + \regex_single_match: + #1 + \regex_replacement:n {#2} + \exp_args:No \regex_match:n { #3 } + \if_meaning:w \c_false_bool \g_regex_success_bool + \group_end: + \else: \regex_extract: - \int_set:Nn \l_regex_internal_a_int - { \regex_nesting:n { \l_regex_submatch_start_int } } - \if_num:w \l_regex_internal_a_int = \c_zero - \else: - \msg_kernel_error:nnx { regex } { replace-unbalanced } - { \l_regex_internal_a_int } - \fi: + \int_set:Nn \l_regex_balance_int + { + \regex_replacement_balance_one_match:n + { \l_regex_zeroth_submatch_int } + } \tl_set:Nx \l_regex_internal_a_tl { - \if_num:w \l_regex_internal_a_int < \c_zero - \prg_replicate:nn { - \l_regex_internal_a_int } - { \exp_not:n { { \if_false: } \fi: } } - \fi: - \regex_toks_range:nn - { \l_regex_min_index_int } - { \tex_skip:D \l_regex_submatch_start_int } - \regex_replacement_tl:n { \l_regex_submatch_start_int } - \regex_toks_range:nn - { \etex_gluestretch:D \tex_skip:D \l_regex_submatch_start_int } - { \l_regex_max_index_int } - \if_num:w \l_regex_internal_a_int > \c_zero - \prg_replicate:nn { \l_regex_internal_a_int } - { \exp_not:n { \if_false: { \fi: } } } - \fi: + \regex_replacement_do_one_match:n { \l_regex_zeroth_submatch_int } + \regex_query_range:nn + { \etex_gluestretch:D \tex_skip:D \l_regex_zeroth_submatch_int } + { \l_regex_max_pos_int } } - \tl_set:Nx \l_regex_internal_a_tl { \l_regex_internal_a_tl } - \exp_args:NNNo \group_end: - \tl_set:Nn #4 \l_regex_internal_a_tl - \else: - \group_end: + \regex_group_end_replace:N #3 \fi: } -\cs_new_protected:Npn \regex_replace_all_aux:NnnN #1#2#3#4 +\cs_new_protected:Npn \regex_replace_all_aux:nnN #1#2#3 { \group_begin: - \tl_set:Nn \l_regex_every_match_tl - { - \regex_extract: - \tex_skip:D \l_regex_submatch_start_int - = \tex_the:D \tex_skip:D \l_regex_submatch_start_int - minus \l_regex_start_index_int sp \scan_stop: - \regex_match_once: - } - \regex_replacement:n {#3} - \exp_args:Nno #1 {#2} #4 - \int_set:Nn \l_regex_internal_a_int + \regex_multi_match:n { \regex_extract: } + #1 + \regex_replacement:n {#2} + \exp_args:No \regex_match:n {#3} + \int_set:Nn \l_regex_balance_int { 0 \prg_stepwise_function:nnnN - \l_regex_max_state_int + { \c_two * \l_regex_max_state_int } \l_regex_capturing_group_int { \l_regex_submatch_int - \c_one } - \regex_nesting:n + \regex_replacement_balance_one_match:n } - \if_num:w \l_regex_internal_a_int = \c_zero - \else: - \msg_kernel_error:nnx { regex } { replace-unbalanced } - { \l_regex_internal_a_int } - \fi: \tl_set:Nx \l_regex_internal_a_tl { - \if_num:w \l_regex_internal_a_int < \c_zero - \prg_replicate:nn { - \l_regex_internal_a_int } - { \exp_not:n { { \if_false: } \fi: } } - \fi: \prg_stepwise_function:nnnN - \l_regex_max_state_int + { \c_two * \l_regex_max_state_int } \l_regex_capturing_group_int { \l_regex_submatch_int - \c_one } - \regex_replace_all_aux:n - \regex_toks_range:nn - \l_regex_start_index_int \l_regex_max_index_int - \if_num:w \l_regex_internal_a_int > \c_zero - \prg_replicate:nn { \l_regex_internal_a_int } - { \exp_not:n { \if_false: { \fi: } } } - \fi: + \regex_replacement_do_one_match:n + \regex_query_range:nn + \l_regex_start_pos_int \l_regex_max_pos_int } - \tl_set:Nx \l_regex_internal_a_tl { \l_regex_internal_a_tl } - \exp_args:NNNo \group_end: - \tl_set:Nn #4 \l_regex_internal_a_tl + \regex_group_end_replace:N #3 } -\cs_new:Npn \regex_replace_all_aux:n #1 +\cs_new_protected_nopar:Npn \regex_group_end_replace:N #1 { - \regex_toks_range:nn - { \etex_glueshrink:D \tex_skip:D #1 } { \tex_skip:D #1 } - \regex_replacement_tl:n {#1} + \if_num:w \l_regex_balance_int = \c_zero + \else: + \msg_kernel_error:nnxxx { regex } { result-unbalanced } + { replacing } + { \int_max:nn { - \l_regex_balance_int } { \c_zero } } + { \int_max:nn { \l_regex_balance_int } { \c_zero } } + \fi: + \use:x + { + \group_end: + \tl_set:Nn \exp_not:N #1 + { + \if_int_compare:w \l_regex_balance_int < \c_zero + \prg_replicate:nn { - \l_regex_balance_int } + { { \if_false: } \fi: } + \fi: + \l_regex_internal_a_tl + \if_int_compare:w \l_regex_balance_int > \c_zero + \prg_replicate:nn { \l_regex_balance_int } + { \if_false: { \fi: } } + \fi: + } + } } \msg_kernel_new:nnnn { regex } { trailing-backslash } { Trailing~escape~character~\iow_char:N\\. } @@ -2453,6 +2574,13 @@ `\iow_char:N\\x\{\int_to_hexadecimal:n{#1}\}'.~ The~character~code~'#1'~is~larger~than~\int_use:N \c_max_char_int. } +\msg_kernel_new:nnnn { regex } { invalid-quantifier } + { Braced~quantifier~'#1'~may~not~be~followed~by~'#2'. } + { + The~character~'#2'~is~invalid~in~the~braced~quantifier~'#1'.~ + The~only~valid~quantifiers~are~'*',~'?',~'+',~'{<int>}',~ + '{<min>,}'~and~'{<min>,<max>}',~followed~or~not~by~'?'. + } \msg_kernel_new:nnnn { regex } { missing-rbrack } { Missing~right~bracket~inserted~in~regular~expression. } { @@ -2475,19 +2603,29 @@ LaTeX~came~across~a~closing~parenthesis~when~no~submatch~group~ was~open.~The~parenthesis~will~be~ignored. } -\msg_kernel_new:nnnn { regex } { class-bad-escape } - { Invalid~escape~\c_backslash_str #1~in~character~class. } +\msg_kernel_new:nnnn { regex } { bad-escape } { - The~escape~sequence~\iow_char:N\\#1~may~not~appear~within~ - a~character~class.~For~instance,~assertions~(which~match~zero~ - characters)~would~not~make~sense~there. + Invalid~escape~\c_backslash_str #1~ + \regex_if_in_cs:TF { within~a~control~sequence. } + { + \regex_if_in_class:TF + { in~a~character~class. } + { following~a~category~test. } + } } -\msg_kernel_new:nnnn { regex } { catcode-bad-escape } - { Invalid~escape~\c_backslash_str #1~following~category~test. } { - The~escape~sequence~\iow_char:N\\#1~may~not~appear~following~ - a~category~test~such~as~\iow_char:N\\cL~or~ - \iow_char:N\\c[\iow_char:N\^BE]. + The~escape~sequence~\iow_char:N\\#1~may~not~appear~ + \regex_if_in_cs:TF + { + within~a~control~sequence~test~introduced~by~ + \iow_char:N\\c\iow_char:N\{. + } + { + \regex_if_in_class:TF + { within~a~character~class~ } + { following~a~category~test~such~as~\iow_char:N\\cL~ } + because~it~does~not~match~exactly~one~character. + } } \msg_kernel_new:nnnn { regex } { range-missing-end } { Invalid~end-point~for~range~'#1-#2'~in~character~class. } @@ -2525,7 +2663,7 @@ regular~expression,~but~the~closing~']'~is~not~present. } \msg_kernel_new:nnnn { regex } { c-missing-category } - { Invalid~character~'#1'~following~\iow_char\\c~escape. } + { Invalid~character~'#1'~following~\iow_char:N\\c~escape. } { In~regular~expressions,~the~\iow_char:N\\c~escape~sequence~ may~only~be~followed~by~a~left~brace,~a~left~bracket,~or~a~ @@ -2547,78 +2685,102 @@ { encountered~an~escaped~alphanumeric~character '\iow_char:N\\#2'~ } when~parsing~the~argument~of~an~'\iow_char:N\\u\iow_char:N\{...\}'~escape. } -\msg_kernel_new:nnnn { regex } { sequence-unbalanced } +\msg_kernel_new:nnnn { regex } { posix-unsupported } + { POSIX~collating~element~'[#1 ~ #1]'~not~supported. } { - Missing~ - \flag_if_raised:nTF { regex_end } - { - left~ - \flag_if_raised:nTF { regex_begin } - { and~right~braces } { brace } - } - { right~brace } - \ inserted~in~extracted~match. + The~[.foo.]~and~[=bar=]~syntaxes~have~a~special~meaning~in~POSIX~ + regular~expressions.~This~is~not~supported~by~LaTeX.~Maybe~you~ + forgot~to~escape~a~left~bracket~in~a~character~class? } +\msg_kernel_new:nnnn { regex } { posix-unknown } + { POSIX~class~[:#1:]~unknown. } { - LaTeX~was~asked~to~extract~submatches~or~split~a~token~list~ - according~to~a~given~regular~expression,~but~some~of~the~resulting~ - items~were~not~balanced. + [:#1:]~is~not~among~the~known~POSIX~classes~ + [:alnum:],~[:alpha:],~[:ascii:],~[:blank:],~ + [:cntrl:],~[:digit:],~[:graph:],~[:lower:],~ + [:print:],~[:punct:],~[:space:],~[:upper:],~ + [:word:],~and~[:xdigit:]. } -\msg_kernel_new:nnnn { regex } { replace-unbalanced } - { The~result~of~a~replacement~does~not~have~balanced~braces. } +\msg_kernel_new:nnnn { regex } { posix-missing-close } + { Missing~closing~':]'~for~POSIX~class. } + { The~POSIX~syntax~'#1'~must~be~followed~by~':]',~not~'#2'. } +\msg_kernel_new:nnnn { regex } { result-unbalanced } + { Missing~brace~inserted~when~#1. } { - LaTeX~was~asked~to~do~some~regular~expression~replacement,~ + LaTeX~was~asked~to~do~some~regular~expression~operation,~ and~the~resulting~token~list~would~not~have~the~same~number~ - of~begin-group~and~end-group~tokens. \\ \\ - \ \ \ \ - \prg_case_int:nnn {#1} - { - { -1 } { A~left~brace~was } - { 1 } { A~right~brace~was } - } - { - \int_abs:n {#1} ~ - \int_compare:nNnTF {#1} < \c_zero { left } { right } ~ - braces ~ were - } - \ inserted. + of~begin-group~and~end-group~tokens.~Braces~were~inserted:~ + #2~left,~#3~right. } -\msg_kernel_new:nnnn { regex } { not-nfa } - { This~is~not~a~regular~expression~variable. } +\msg_kernel_new:nnnn { regex } { unknown-option } + { Unknown~option~`#1'~for~regular~expressions. } { - LaTeX~was~expecting~`#1'~to~be~a~regular~expression~variable.\\ - This~control~sequence~is~not~a~regex~variable.~It's~current~meaning~ - is~\\\\ - \ \ \ \ \token_to_str:N #1 = \token_to_meaning:N #1 . + The~only~available~option~is~'case-insensitive',~toggled~by~ + '(?i)'~and~'(?-i)'. } -\msg_kernel_new:nnn { regex } { nfa-misused } - { Automaton~#1 used~incorrectly. } -\msg_kernel_new:nnnn { regex } { c-command } - { Misused~\iow_char:N\\c~or\iow_char:N\\C~command~in~a~#1. } +\msg_kernel_new:nnnn { regex } { replacement-c } + { Misused~\iow_char:N\\c~command~in~a~replacement~text. } { - In~a~#1,~the~\iow_char:N\\C~escape~sequence~ + In~a~replacement~text,~the~\iow_char:N\\c~escape~sequence~ can~be~followed~by~one~of~the~letters~ABCDELMOPSTU~ - or~a~brace~group,~not~by~'#2'. - } -\msg_kernel_new:nnnn { regex } { unknown-option } - { Unknown~option~`#1'~for~regular~expressions. } - { - LaTeX~came~across~something~like~`(?#1)'~in~a~regular~expression,~ - but~the~option~`#1'~is~not~known.~It~will~be~ignored. + or~a~brace~group,~not~by~'#1'. } -\msg_kernel_new:nnnn { regex } { invalid-in-option } - { Invalid~character~in~option~of~a~regular~expression. } +\msg_kernel_new:nnnn { regex } { replacement-u } + { Misused~\iow_char:N\\u~command~in~a~replacement~text. } { - The~character~or~escape~sequence~`#1'~is~not~defined~ - as~an~option~within~regular~expressions. + In~a~replacement~text,~the~\iow_char:N\\u~escape~sequence~ + must~be~~followed~by~a~brace~group~holding~the~name~of~the~ + variable~to~use. } -\msg_kernel_new:nnnn { regex } { g-command } +\msg_kernel_new:nnnn { regex } { replacement-g } { Missing~brace~for~the~\iow_char:N\\g~construction~in~a~replacement~text. } { In~the~replacement~text~for~a~regular~expression~search,~ submatches~are~represented~either~as~\iow_char:N \\g{dd..d},~ or~\\d,~where~`d'~are~single~digits.~Here,~a~brace~is~missing. } +\msg_kernel_new:nnnn { regex } { replacement-catcode-end } + { + Missing~character~for~the~\iow_char:N\\c<category><character>~ + construction~in~a~replacement~text. + } + { + In~a~replacement~text,~the~\iow_char:N\\c~escape~sequence~ + can~be~followed~by~one~of~the~letters~ABCDELMOPSTU~representing~ + the~character~category.~Then,~a~character~must~follow.~LaTeX~ + reached~the~end~of~the~replacement~when~looking~for~that. + } +\msg_kernel_new:nnnn { regex } { replacement-null-space } + { TeX~cannot~build~a~space~token~with~character~code~0. } + { + You~asked~for~a~character~token~with~category~'space',~ + and~character~code~0,~for~instance~through~ + '\iow_char:N\\cS\iow_char:N\\x00'.~ + This~specific~case~is~impossible~and~will~be~replaced~ + by~a~normal~space. + } +\msg_kernel_new:nnnn { regex } { replacement-missing-rbrace } + { Missing~right~brace~inserted~in~replacement~text. } + { + There~were~\int_use:N \l_regex_replacement_csnames_int \ + missing~right~braces. + } +\cs_new:Npn \regex_msg_repeated:nnN #1#2#3 + { + \str_if_eq:xxF { #1 #2 } { 1 0 } + { + , ~ repeated ~ + \prg_case_int:nnn {#2} + { + { -1 } { #1~or~more~times,~\bool_if:NTF #3 { lazy } { greedy } } + { 0 } { #1~times } + } + { + between~#1~and~\int_eval:n {#1+#2}~times,~ + \bool_if:NTF #3 { lazy } { greedy } + } + } + } %% %% %% End of file `l3regex.sty'. diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty index d9ef6271899..88042a5337d 100644 --- a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty +++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty @@ -46,13 +46,15 @@ %% %% ----------------------------------------------------------------------- \RequirePackage{expl3} -\GetIdInfo$Id: l3str.dtx 3257 2012-01-29 13:37:03Z bruno $ +\GetIdInfo$Id: l3str.dtx 3460 2012-02-26 12:16:41Z will $ {L3 Experimental Strings} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\RequirePackage{l3tl-analysis,l3flag} +\RequirePackage{l3tl-analysis,l3tl-build,l3flag} \cs_if_exist:NF \use_ii_i:nn { \cs_new:Npn \use_ii_i:nn #1#2 { #2 #1 } } +\cs_new_eq:NN \str_new:N \tl_new:N +\cs_generate_variant:Nn \str_new:N { c } \tl_map_inline:nn { { set } @@ -435,15 +437,17 @@ \prg_return_true: \fi: } +\cs_new_eq:NN \str_show:n \tl_show:n +\cs_new_eq:NN \str_show:N \tl_show:N +\cs_generate_variant:Nn \str_show:N { c } \group_begin: - \tl_clear:N \l_str_internal_tl \char_set_catcode_other:n { \c_zero } - \tl_gset:Nx \g_str_result_tl { \tl_to_str:n { 0123456789ABCDEF } } - \exp_args:No \tl_map_inline:nn { \g_str_result_tl " } + \tl_set:Nx \l_str_internal_tl { \tl_to_str:n { 0123456789ABCDEF } } + \exp_args:No \tl_map_inline:nn { \l_str_internal_tl " } { \char_set_lccode:nn {`#1} { \c_zero } } - \tl_map_inline:Nn \g_str_result_tl + \tl_map_inline:Nn \l_str_internal_tl { - \tl_map_inline:Nn \g_str_result_tl + \tl_map_inline:Nn \l_str_internal_tl { \char_set_lccode:nn { \c_zero } {"#1##1} \tl_to_lowercase:n @@ -451,12 +455,9 @@ \tl_const:cx { c_str_byte_ \int_eval:n {"#1##1} _tl } { ^^@ #1 ##1 } - \tl_put_right:Nn \l_str_internal_tl { ^^@ } } } } - \tl_const:Nx \c_str_positive_bytes_tl - { \exp_after:wN \use_none:n \l_str_internal_tl } \group_end: \tl_const:cn { c_str_byte_-1_tl } { { } \use_none:n { } } \cs_new:Npn \str_output_byte:n #1 @@ -744,53 +745,20 @@ { \cs_new_protected_nopar:Npn \str_convert_encode_: { - \tex_lccode:D \c_zero \c_zero - \int_zero:N \l_str_internal_int - \tl_set_eq:NN \l_str_internal_tl \g_str_result_tl - \tl_gclear:N \g_str_result_tl - \exp_after:wN \str_encode_native_loop:w - \l_str_internal_tl \s_tl { \q_stop \prg_map_break: } \s_tl - \prg_break_point:n { \str_encode_native_flush: } + \int_zero:N \l_tl_build_offset_int + \tl_gset_build_x:Nw \g_str_result_tl + \exp_after:wN \str_encode_native_loop:w + \g_str_result_tl \s_tl { \q_stop \prg_map_break: } \s_tl + \prg_break_point:n { } + \tl_build_end: } \cs_new_protected:Npn \str_encode_native_loop:w #1 \s_tl #2 \s_tl { \use_none_delimit_by_q_stop:w #2 \q_stop - \if_num:w \l_str_internal_int = \c_two_hundred_fifty_five - \str_encode_native_flush: - \l_str_internal_int \c_zero - \fi: - \tex_advance:D \l_str_internal_int \c_one \tex_lccode:D \l_str_internal_int \int_eval:w #2 \int_eval_end: + \tl_to_lowercase:n { \tl_build_one:n { ^^@ } } \str_encode_native_loop:w } - \cs_new_protected_nopar:Npn \str_encode_native_flush: - { - \use:x - { - \tl_to_lowercase:n - { - \tl_gput_right:Nx \exp_not:N \g_str_result_tl - { - \exp_after:wN \str_encode_native_filter:N - \c_str_positive_bytes_tl - { ? = \c_zero \fi: \prg_map_break: } - \prg_break_point:n { } - } - } - } - } - \cs_new:Npn \str_encode_native_filter:N #1 - { - \if_num:w `#1 > \l_str_internal_int - \exp_after:wN \prg_map_break: - \fi: - \if_num:w \tex_lccode:D `#1 = \c_zero - ^^@ - \else: - #1 - \fi: - \str_encode_native_filter:N - } } \group_end: \cs_new_protected:Npn \str_declare_eight_bit_encoding:nnn #1#2#3 diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty index 6f82415d186..545d7ce7069 100644 --- a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty +++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty @@ -52,6 +52,7 @@ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \RequirePackage{l3str} \scan_new:N \s_tl +\tl_new:N \l_tl_analysis_internal_tl \cs_new_eq:NN \l_tl_analysis_token ? \cs_new_eq:NN \l_tl_analysis_char_token ? \int_new:N \l_tl_analysis_normal_int @@ -370,8 +371,8 @@ } \cs_new_protected:Npn \tl_show_analysis:n #1 { - \tl_set:Nn \l_tl_tmpa_tl {#1} - \tl_show_analysis:N \l_tl_tmpa_tl + \tl_set:Nn \l_tl_analysis_internal_tl {#1} + \tl_show_analysis:N \l_tl_analysis_internal_tl } \cs_new:Npn \tl_show_analysis_loop:wNw #1 \s_tl #2 #3 \s_tl { @@ -396,37 +397,55 @@ \exp_after:wN \token_to_str:N #1 ~ ( \exp_after:wN \token_to_meaning:N #1 ) } +\cs_new:Npn \tl_show_analysis_value:N #1 + { + \token_if_expandable:NF #1 + { + \token_if_chardef:NTF #1 \prg_map_break: { } + \token_if_mathchardef:NTF #1 \prg_map_break: { } + \token_if_dim_register:NTF #1 \prg_map_break: { } + \token_if_int_register:NTF #1 \prg_map_break: { } + \token_if_skip_register:NTF #1 \prg_map_break: { } + \token_if_toks_register:NTF #1 \prg_map_break: { } + \use_none:nnnn + \prg_break_point:n { } + \use:n { = \tex_the:D #1 } + } + } \cs_new:Npn \tl_show_analysis_cs:n #1 { \exp_args:No \tl_show_analysis_long:nn {#1} { control~sequence= } } \cs_new:Npn \tl_show_analysis_active:n #1 { \exp_args:No \tl_show_analysis_long:nn {#1} { active~character= } } \cs_new:Npn \tl_show_analysis_long:nn #1 { - \exp_args:Noo \tl_show_analysis_long_aux:nnn + \tl_show_analysis_long_aux:oofn { \token_to_str:N #1 } { \token_to_meaning:N #1 } + { \tl_show_analysis_value:N #1 } } -\cs_new:Npn \tl_show_analysis_long_aux:nnn #1#2#3 +\cs_new:Npn \tl_show_analysis_long_aux:nnnn #1#2#3#4 { \int_compare:nNnTF - { \str_length:n { #1 ~ ( #3 #2 ) } } + { \str_length:n { #1 ~ ( #4 #2 #3 ) } } > { \l_iow_line_length_int - \c_three } { - \str_substr:nnn { #1 ~ ( #3 #2 ) } \c_zero + \str_substr:nnn { #1 ~ ( #4 #2 #3 ) } \c_zero { \l_iow_line_length_int - \c_three - \str_length:N \c_tl_show_analysis_etc_str } \c_tl_show_analysis_etc_str } - { #1 ~ ( #3 #2 ) } + { #1 ~ ( #4 #2 #3 ) } } +\cs_generate_variant:Nn \tl_show_analysis_long_aux:nnnn { oof } \tl_const:Nx \c_tl_show_analysis_etc_str % ( { \token_to_str:N \ETC.) } \msg_kernel_new:nnn { tl-analysis } { show } { The~token~list~ - \str_if_eq:nnF {#1} { \l_tl_tmpa_tl } { \token_to_str:N #1 ~ } + \str_if_eq:nnF {#1} { \l_tl_analysis_internal_tl } + { \token_to_str:N #1 ~ } \tl_if_empty:NTF #1 { is~empty } { contains~the~tokens: } diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty new file mode 100644 index 00000000000..415a89f4897 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty @@ -0,0 +1,120 @@ +%% +%% This is file `l3tl-build.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3tl-build.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3tl-build.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3experimental bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{expl3} +\GetIdInfo$Id: l3tl-build.dtx 3039 2011-12-08 09:22:35Z bruno $ + {L3 Experimental Build of Token lists} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\int_new:N \l_tl_build_start_index_int +\int_new:N \l_tl_build_index_int +\tl_new:N \l_tl_build_result_tl +\cs_new_protected_nopar:Npn \tl_build_unpack: + { + \tl_put_right:Nx \l_tl_build_result_tl + { + \exp_after:wN \tl_build_unpack_loop:w + \int_use:N \l_tl_build_start_index_int ; + \prg_break_point:n { } + } + } +\cs_new:Npn \tl_build_unpack_loop:w #1 ; + { + \if_num:w #1 = \l_tl_build_index_int + \exp_after:wN \prg_map_break: + \fi: + \tex_the:D \tex_toks:D #1 \exp_stop_f: + \exp_after:wN \tl_build_unpack_loop:w + \int_use:N \int_eval:w #1 + \c_one ; + } +\cs_new_protected_nopar:Npn \tl_set_build:Nw + { \tl_set_build_aux:NNw \tl_set:Nn } +\cs_new_protected_nopar:Npn \tl_set_build_x:Nw + { \tl_set_build_aux:NNw \tl_set:Nx } +\cs_new_protected_nopar:Npn \tl_gset_build:Nw + { \tl_set_build_aux:NNw \tl_gset:Nn } +\cs_new_protected_nopar:Npn \tl_gset_build_x:Nw + { \tl_set_build_aux:NNw \tl_gset:Nx } +\cs_new_protected:Npn \tl_set_build_aux:NNw #1#2 + { + \group_begin: + \cs_set_nopar:Npn \tl_build_end_assignment:n + { \group_end: #1 #2 } + \int_zero:N \l_tl_build_start_index_int + \int_zero:N \l_tl_build_index_int + \tl_clear:N \l_tl_build_result_tl + } +\cs_new_protected_nopar:Npn \tl_build_end: + { + \tl_build_unpack: + \exp_args:No + \tl_build_end_assignment:n \l_tl_build_result_tl + } +\cs_new_eq:NN \tl_build_end_assignment:n \use_none:n +\cs_new_protected:Npn \tl_build_one:n #1 + { + \tex_toks:D \l_tl_build_index_int {#1} + \tex_advance:D \l_tl_build_index_int \c_one + \if_num:w \l_tl_build_index_int > \c_max_register_int + \tl_build_unpack: + \l_tl_build_index_int \l_tl_build_start_index_int + \fi: + } +\cs_new_protected:Npn \tl_build_one:o #1 + { + \tex_toks:D \l_tl_build_index_int \exp_after:wN {#1} + \tex_advance:D \l_tl_build_index_int \c_one + \if_num:w \l_tl_build_index_int > \c_max_register_int + \tl_build_unpack: + \l_tl_build_index_int \l_tl_build_start_index_int + \fi: + } +\cs_new_protected:Npn \tl_build_one:x #1 + { \use:x { \tl_build_one:n {#1} } } +%% +%% +%% End of file `l3tl-build.sty'. diff --git a/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty b/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty index 9d4a42407e3..ab210356d5c 100644 --- a/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty +++ b/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty @@ -47,7 +47,7 @@ %% ----------------------------------------------------------------------- %% \RequirePackage{xparse} -\GetIdInfo$Id: xcoffins.dtx 2963 2011-11-15 22:06:41Z joseph $ +\GetIdInfo$Id: xcoffins.dtx 3385 2012-02-12 20:37:09Z bruno $ {L3 Experimental design-level coffins} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} |