summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3regex.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3regex.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3regex.dtx361
1 files changed, 266 insertions, 95 deletions
diff --git a/macros/latex/contrib/l3kernel/l3regex.dtx b/macros/latex/contrib/l3kernel/l3regex.dtx
index 4962ca6fa2..7f384c8d56 100644
--- a/macros/latex/contrib/l3kernel/l3regex.dtx
+++ b/macros/latex/contrib/l3kernel/l3regex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
%
% \maketitle
%
@@ -1574,7 +1574,7 @@
\tl_put_right:Nx \l_@@_internal_a_tl
{
\exp_after:wN \@@_escape_loop:N \g_@@_internal_tl
- { break } \prg_break_point:
+ \scan_stop: \prg_break_point:
}
\exp_after:wN
\group_end:
@@ -1620,7 +1620,7 @@
%
% \begin{macro}
% {
-% \@@_escape_break:w, \@@_escape_/break:w,
+% \@@_escape_\scan_stop::w, \@@_escape_/\scan_stop::w,
% \@@_escape_/a:w, \@@_escape_/e:w, \@@_escape_/f:w,
% \@@_escape_/n:w, \@@_escape_/r:w, \@@_escape_/t:w
% }
@@ -1630,8 +1630,8 @@
% backslash. Spaces are ignored, and |\a|, |\e|, |\f|, |\n|, |\r|,
% |\t| take their meaning here.
% \begin{macrocode}
-\cs_new_eq:NN \@@_escape_break:w \prg_break:
-\cs_new:cpn { @@_escape_/break:w }
+\cs_new_eq:cN { @@_escape_ \iow_char:N\\scan_stop: :w } \prg_break:
+\cs_new:cpn { @@_escape_/ \iow_char:N\\scan_stop: :w }
{
\__kernel_msg_expandable_error:nn { regex } { trailing-backslash }
\prg_break:
@@ -1691,7 +1691,10 @@
% \begin{macrocode}
\cs_new:Npn \@@_escape_x_test:N #1
{
- \str_if_eq:nnTF {#1} { break } { ; }
+ \if_meaning:w \scan_stop: #1
+ \exp_after:wN \use_i:nnn \exp_after:wN ;
+ \fi:
+ \use:n
{
\if_charcode:w \c_space_token #1
\exp_after:wN \@@_escape_x_test:N
@@ -1719,7 +1722,10 @@
% \begin{macrocode}
\cs_new:Npn \@@_escape_x:N #1
{
- \str_if_eq:nnTF {#1} { break } { ; }
+ \if_meaning:w \scan_stop: #1
+ \exp_after:wN \use_i:nnn \exp_after:wN ;
+ \fi:
+ \use:n
{
\@@_hexadecimal_use:NTF #1
{ ; \@@_escape_loop:N }
@@ -1736,7 +1742,10 @@
% \begin{macrocode}
\cs_new:Npn \@@_escape_x_loop:N #1
{
- \str_if_eq:nnTF {#1} { break }
+ \if_meaning:w \scan_stop: #1
+ \exp_after:wN \use_ii:nnn
+ \fi:
+ \use_ii:nn
{ ; \@@_escape_x_loop_error:n { } {#1} }
{
\@@_hexadecimal_use:NTF #1
@@ -2251,7 +2260,7 @@
\prg_do_nothing: \prg_do_nothing:
}
{ }
- \if_int_compare:w \l_@@_group_level_int > 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_group_level_int > \c_zero_int
\__kernel_msg_error:nnx { regex } { missing-rparen }
{ \int_use:N \l_@@_group_level_int }
\prg_replicate:nn
@@ -3017,7 +3026,7 @@
}
\cs_new_protected:Npn \@@_compile_group_end:
{
- \if_int_compare:w \l_@@_group_level_int > 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_group_level_int > \c_zero_int
\tl_build_put_right:Nn \l_@@_build_tl { \if_false: { \fi: } }
\tl_build_end:N \l_@@_build_tl
\exp_args:NNNx
@@ -3597,7 +3606,7 @@
{
\@@_class:NnnnN \c_true_bool
{
- \if_int_compare:w "##3 = 0 \exp_stop_f:
+ \if_int_compare:w "##3 = \c_zero_int
\@@_item_exact_cs:n
{ \exp_after:wN \cs_to_str:N ##1 }
\else:
@@ -4314,7 +4323,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_class_repeat:nN #1#2
{
- \if_int_compare:w #1 = 0 \exp_stop_f:
+ \if_int_compare:w #1 = \c_zero_int
\@@_build_transitions_lazyness:NNNNN #2
\@@_action_free:n \l_@@_right_state_int
\@@_tests_action_cost:n \l_@@_left_state_int
@@ -4374,9 +4383,8 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_group_aux:nnnnN #1#2#3#4#5
{
- \if_int_compare:w #3 = 0 \exp_stop_f:
+ \if_int_compare:w #3 = \c_zero_int
\@@_build_new_state:
-%<assert>\assert_int:n { \l_@@_max_state_int = \l_@@_right_state_int + 1 }
\@@_build_transition_right:nNn \@@_action_free_group:n
\l_@@_left_state_int \l_@@_right_state_int
\fi:
@@ -4479,7 +4487,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_group_repeat:nn #1#2
{
- \if_int_compare:w #2 = 0 \exp_stop_f:
+ \if_int_compare:w #2 = \c_zero_int
\int_set:Nn \l_@@_max_state_int
{ \l_@@_left_state_int - 1 }
\@@_build_new_state:
@@ -4499,7 +4507,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_group_submatches:nNN #1#2#3
{
- \if_int_compare:w #1 > - 1 \exp_stop_f:
+ \if_int_compare:w #1 > - \c_one_int
\@@_toks_put_left:Nx #2 { \@@_action_submatch:nN {#1} < }
\@@_toks_put_left:Nx #3 { \@@_action_submatch:nN {#1} > }
\fi:
@@ -4523,7 +4531,7 @@
\l_@@_right_state_int \l_@@_max_state_int
\int_set_eq:NN \l_@@_internal_a_int \l_@@_left_state_int
\int_set_eq:NN \l_@@_internal_b_int \l_@@_max_state_int
- \if_int_compare:w \int_eval:n {#1} > 1 \exp_stop_f:
+ \if_int_compare:w \int_eval:n {#1} > \c_one_int
\int_set:Nn \l_@@_internal_c_int
{
( #1 - 1 )
@@ -4562,7 +4570,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_group_repeat:nnN #1#2#3
{
- \if_int_compare:w #2 = 0 \exp_stop_f:
+ \if_int_compare:w #2 = \c_zero_int
\@@_group_submatches:nNN {#1}
\l_@@_left_state_int \l_@@_right_state_int
\int_set:Nn \l_@@_internal_a_int
@@ -4633,7 +4641,7 @@
\@@_build_transition_right:nNn \@@_action_free:n
\l_@@_right_state_int \l_@@_max_state_int
}
- \if_int_compare:w #2 = 0 \exp_stop_f:
+ \if_int_compare:w #2 = \c_zero_int
\int_set:Nn \l_@@_right_state_int
{ \l_@@_left_state_int - 1 }
\else:
@@ -5588,7 +5596,7 @@
{ \@@_replacement_normal:n ##1 }
{#1}
\prg_do_nothing: \prg_do_nothing:
- \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int
\__kernel_msg_error:nnx { regex } { replacement-missing-rbrace }
{ \int_use:N \l_@@_replacement_csnames_int }
\tl_build_put_right:Nx \l_@@_build_tl
@@ -5747,7 +5755,7 @@
{
\tl_build_put_right:Nn \l_@@_build_tl
{ \@@_query_submatch:n { \int_eval:n { #1 + ##1 } } }
- \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int
\tl_put_right:Nn \l_@@_balance_tl
{
+ \@@_submatch_balance:n
@@ -5869,7 +5877,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_replacement_rbrace:N #1
{
- \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int
\tl_build_put_right:Nn \l_@@_build_tl { \cs_end: }
\int_decr:N \l_@@_replacement_csnames_int
\else:
@@ -5885,7 +5893,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_replacement_lbrace:N #1
{
- \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int
\__kernel_msg_error:nnn { regex } { cu-lbrace } { u }
\else:
\@@_replacement_normal:n {#1}
@@ -5990,7 +5998,7 @@
\char_set_catcode_group_begin:N \^^@
\cs_new_protected:Npn \@@_replacement_c_B:w
{
- \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int
\int_incr:N \l_@@_balance_int
\fi:
\@@_replacement_char:nNN
@@ -6030,7 +6038,7 @@
\char_set_catcode_group_end:N \^^@
\cs_new_protected:Npn \@@_replacement_c_E:w
{
- \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f:
+ \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int
\int_decr:N \l_@@_balance_int
\fi:
\@@_replacement_char:nNN
@@ -6091,7 +6099,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_replacement_c_S:w #1#2
{
- \if_int_compare:w `#2 = 0 \exp_stop_f:
+ \if_int_compare:w `#2 = \c_zero_int
\__kernel_msg_error:nn { regex } { replacement-null-space }
\fi:
\tex_lccode:D `\ = `#2 \scan_stop:
@@ -6298,8 +6306,8 @@
% \end{variable}
%
% \begin{variable}{@@_begin, @@_end}
-% Those flags are raised to indicate extra begin-group
-% or end-group tokens when extracting submatches.
+% Those flags are raised to indicate begin-group or end-group tokens
+% that had to be added when extracting submatches.
% \begin{macrocode}
\flag_new:n { @@_begin }
\flag_new:n { @@_end }
@@ -6340,6 +6348,15 @@
% \end{macrocode}
% \end{variable}
%
+% \begin{variable}{\l_@@_added_begin_int, \l_@@_added_end_int}
+% Keep track of the number of left/right braces to add when performing
+% a regex operation such as a replacement.
+% \begin{macrocode}
+\int_new:N \l_@@_added_begin_int
+\int_new:N \l_@@_added_end_int
+% \end{macrocode}
+% \end{variable}
+%
% \begin{macro}{\@@_return:}
% This function triggers either \cs{prg_return_false:} or
% \cs{prg_return_true:} as appropriate to whether a match was found or
@@ -6512,39 +6529,47 @@
%
% \begin{macro}{\@@_group_end_extract_seq:N}
% The end-points of submatches are stored as entries of two arrays
-% from \cs{l_@@_min_submatch_int} to
-% \cs{l_@@_submatch_int} (exclusive). Extract the relevant ranges
-% into \cs{l_@@_internal_a_tl}. We detect unbalanced results using
-% the two flags \texttt{__regex_begin} and \texttt{__regex_end}, raised
-% whenever we see too many begin-group or end-group tokens in a
-% submatch.
+% from \cs{l_@@_min_submatch_int} to \cs{l_@@_submatch_int}
+% (exclusive). Extract the relevant ranges into \cs{g_@@_internal_tl},
+% separated by \cs{@@_tmp:w} |{}|. We keep track in the two flags
+% \texttt{__regex_begin} and \texttt{__regex_end} of the number of
+% begin-group or end-group tokens added to make each of these items
+% overall balanced. At this step, |}{| is counted as being balanced
+% (same number of begin-group and end-group tokens). This problem is
+% caught by \cs{@@_extract_check:w}, explained later. After
+% complaining about any begin-group or end-group tokens we had to add,
+% we are ready to construct the user's sequence outside the group.
% \begin{macrocode}
\cs_new_protected:Npn \@@_group_end_extract_seq:N #1
{
\flag_clear:n { @@_begin }
\flag_clear:n { @@_end }
- \seq_set_from_function:NnN \l_@@_internal_seq
+ \cs_set_eq:NN \@@_tmp:w \scan_stop:
+ \__kernel_tl_gset:Nx \g_@@_internal_tl
{
\int_step_function:nnN { \l_@@_min_submatch_int }
- { \l_@@_submatch_int - 1 }
- }
- \@@_extract_seq_aux:n
- \int_compare:nNnF
- {
- \flag_height:n { @@_begin } +
- \flag_height:n { @@_end }
+ { \l_@@_submatch_int - 1 } \@@_extract_seq_aux:n
+ \@@_tmp:w
}
- = 0
+ \int_set:Nn \l_@@_added_begin_int
+ { \flag_height:n { @@_begin } }
+ \int_set:Nn \l_@@_added_end_int
+ { \flag_height:n { @@_end } }
+ \tex_afterassignment:D \@@_extract_check:w
+ \__kernel_tl_gset:Nx \g_@@_internal_tl
+ { \g_@@_internal_tl \if_false: { \fi: } }
+ \int_compare:nNnT
+ { \l_@@_added_begin_int + \l_@@_added_end_int } > 0
{
\__kernel_msg_error:nnxxx { regex } { result-unbalanced }
{ splitting~or~extracting~submatches }
- { \flag_height:n { @@_end } }
- { \flag_height:n { @@_begin } }
+ { \int_use:N \l_@@_added_begin_int }
+ { \int_use:N \l_@@_added_end_int }
}
- \seq_set_map_x:NNn \l_@@_internal_seq \l_@@_internal_seq {##1}
- \exp_args:NNNo
- \group_end:
- \tl_set:Nn #1 { \l_@@_internal_seq }
+ \group_end:
+ \cs_set_eq:NN \@@_tmp:w \@@_extract_map_loop:w
+ \seq_set_from_function:NnN #1
+ { \@@_extract_map:N } \exp_not:n
}
% \end{macrocode}
% \end{macro}
@@ -6557,25 +6582,134 @@
% \begin{macrocode}
\cs_new:Npn \@@_extract_seq_aux:n #1
{
+ \@@_tmp:w { }
\exp_after:wN \@@_extract_seq_aux:ww
\int_value:w \@@_submatch_balance:n {#1} ; #1;
}
\cs_new:Npn \@@_extract_seq_aux:ww #1; #2;
{
- \if_int_compare:w #1 < 0 \exp_stop_f:
- \flag_raise:n { @@_end }
- \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } }
+ \if_int_compare:w #1 < \c_zero_int
+ \prg_replicate:nn {-#1}
+ {
+ \flag_raise:n { @@_begin }
+ \exp_not:n { { \if_false: } \fi: }
+ }
\fi:
\@@_query_submatch:n {#2}
- \if_int_compare:w #1 > 0 \exp_stop_f:
- \flag_raise:n { @@_begin }
- \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } }
+ \if_int_compare:w #1 > \c_zero_int
+ \prg_replicate:nn {#1}
+ {
+ \flag_raise:n { @@_end }
+ \exp_not:n { \if_false: { \fi: } }
+ }
\fi:
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_extract:}
+% \begin{macro}
+% {
+% \@@_extract_check:w, \@@_extract_check:n,
+% \@@_extract_check_loop:w, \@@_extract_check_end:w
+% }
+% In \cs{@@_group_end_extract_seq:N} we had to expand
+% \cs{g_@@_internal_tl} to turn \cs{if_false:} constructions into
+% actual begin-group and end-group tokens. This is done with a
+% \cs{__kernel_tl_gset:Nx} assignment, and \cs{@@_extract_check:w} is
+% run immediately after this assignment ends, thanks to the
+% \tn{afterassignment} primitive. If all of the items were properly
+% balanced (enough begin-group tokens before end-group tokens, so |}{|
+% is not) then \cs{@@_extract_check:w} is called just before the
+% closing brace of the \cs{__kernel_tl_gset:Nx} (thanks to our sneaky
+% \cs{if_false:} |{| \cs{fi:} |}| construction), and finds that there
+% is nothing left to expand. If any of the items is unbalanced, the
+% assignment gets ended early by an extra end-group token, and our
+% check finds more tokens needing to be expanded in a new
+% \cs{__kernel_tl_gset:Nx} assignment. We need to add a begin-group
+% and an end-group tokens to the unbalanced item, namely to the last
+% item found so far, which we reach through a loop.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_extract_check:w
+ {
+ \exp_after:wN \@@_extract_check:n
+ \exp_after:wN { \if_false: } \fi:
+ }
+\cs_new_protected:Npn \@@_extract_check:n #1
+ {
+ \tl_if_empty:nF {#1}
+ {
+ \int_incr:N \l_@@_added_begin_int
+ \int_incr:N \l_@@_added_end_int
+ \tex_afterassignment:D \@@_extract_check:w
+ \__kernel_tl_gset:Nx \g_@@_internal_tl
+ {
+ \exp_after:wN \@@_extract_check_loop:w
+ \g_@@_internal_tl
+ \@@_tmp:w \@@_extract_check_end:w
+ #1
+ }
+ }
+ }
+\cs_new:Npn \@@_extract_check_loop:w #1 \@@_tmp:w #2
+ {
+ #2
+ \exp_not:o {#1}
+ \@@_tmp:w { }
+ \@@_extract_check_loop:w \prg_do_nothing:
+ }
+% \end{macrocode}
+% Arguments of \cs{@@_extract_check_end:w} are: |#1| is the part of
+% the item before the extra end-group token; |#2| is junk; |#3| is
+% \cs{prg_do_nothing:} followed by the not-yet-expanded part of the
+% item after the extra end-group token. In the replacement text, the
+% first brace and the \cs{if_false:} |{| \cs{fi:} |}| construction are
+% the added begin-group and end-group tokens (the latter being not-yet
+% expanded, just like~|#3|), while the closing brace after
+% \cs{exp_not:o} |{#1}| replaces the extra end-group token that had
+% ended the assignment early. In particular this means that the
+% character code of that end-group token is lost.
+% \begin{macrocode}
+\cs_new:Npn \@@_extract_check_end:w
+ \exp_not:o #1#2 \@@_extract_check_loop:w #3 \@@_tmp:w
+ {
+ { \exp_not:o {#1} }
+ #3
+ \if_false: { \fi: }
+ \@@_tmp:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \@@_extract_map:N,
+% \@@_extract_map_aux:NNn,
+% \@@_extract_map_loop:w
+% }
+% This receives a |seq| internal function and maps it over all items
+% in \cs{g_@@_internal_tl}. This token list takes the form
+% \cs{@@_tmp:w} |{}| \meta{item_1} \cs{@@_tmp:w} |{}| \meta{item_2}
+% \ldots{} \cs{@@_tmp:w}, and the calling code has set \cs{@@_tmp:w}
+% equal to \cs{@@_extract_map_loop:w}. The loop is otherwise pretty
+% standard, with \cs{prg_do_nothing:} to avoid losing braces.
+% \begin{macrocode}
+\cs_new:Npn \@@_extract_map:N #1
+ {
+ \exp_after:wN \@@_extract_map_aux:NNn
+ \exp_after:wN #1
+ \g_@@_internal_tl \use_none:nnn
+ }
+\cs_new:Npn \@@_extract_map_aux:NNn #1#2#3
+ { #3 #2 #1 \prg_do_nothing: }
+\cs_new:Npn \@@_extract_map_loop:w #1#2 \@@_tmp:w #3
+ {
+ \exp_after:wN #1 \exp_after:wN {#2}
+ #3 \@@_extract_map_loop:w #1 \prg_do_nothing:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_extract:, \@@_extract_aux:w}
% Our task here is to store the list of end-points of submatches, and
% store them in appropriate array entries, from
% \cs{l_@@_zeroth_submatch_int} upwards. First, we store in
@@ -6598,19 +6732,24 @@
\__kernel_intarray_gset:Nnn \g_@@_submatch_prev_intarray
{ \l_@@_zeroth_submatch_int } { \l_@@_start_pos_int }
\int_zero:N \l_@@_internal_a_int
- \clist_map_inline:Nn \l_@@_success_submatches_tl
- {
- \if_int_compare:w \l_@@_internal_a_int < \l_@@_capturing_group_int
- \__kernel_intarray_gset:Nnn \g_@@_submatch_begin_intarray
- { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int } {##1}
- \else:
- \__kernel_intarray_gset:Nnn \g_@@_submatch_end_intarray
- { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int - \l_@@_capturing_group_int } {##1}
- \fi:
- \int_incr:N \l_@@_internal_a_int
- }
+ \exp_after:wN \@@_extract_aux:w \l_@@_success_submatches_tl
+ \prg_break_point: \@@_use_none_delimit_by_q_recursion_stop:w ,
+ \q_@@_recursion_stop
\fi:
}
+\cs_new_protected:Npn \@@_extract_aux:w #1 ,
+ {
+ \prg_break: #1 \prg_break_point:
+ \if_int_compare:w \l_@@_internal_a_int < \l_@@_capturing_group_int
+ \__kernel_intarray_gset:Nnn \g_@@_submatch_begin_intarray
+ { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int } {#1}
+ \else:
+ \__kernel_intarray_gset:Nnn \g_@@_submatch_end_intarray
+ { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int - \l_@@_capturing_group_int } {#1}
+ \fi:
+ \int_incr:N \l_@@_internal_a_int
+ \@@_extract_aux:w
+ }
% \end{macrocode}
% \end{macro}
%
@@ -6708,36 +6847,65 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_group_end_replace:N}
-% If the brace balance is not $0$, raise an error. Then set the user's
-% variable |#1| to the \texttt{x}-expansion of
-% \cs{l_@@_internal_a_tl}, adding the appropriate braces to produce
-% a balanced result. And end the group.
+% \begin{macro}
+% {
+% \@@_group_end_replace:N, \@@_group_end_replace_try:,
+% \@@_group_end_replace_check:w, \@@_group_end_replace_check:n
+% }
+% At this stage \cs{l_@@_internal_a_tl} (|x|-expands to the desired
+% result). Guess from \cs{l_@@_balance_int} the number of braces to
+% add before or after the result then try expanding. The simplest
+% case is when \cs{l_@@_internal_a_tl} together with the braces we
+% insert via \cs{prg_replicate:nn} give a balanced result, and the
+% assignment ends at the \cs{if_false:} |{| \cs{fi:} |}| construction:
+% then \cs{@@_group_end_replace_check:w} sees that there is no
+% material left and we successfully found the result. The harder case
+% is that expanding \cs{l_@@_internal_a_tl} may produce extra closing
+% braces and end the assignment early. Then we grab the remaining code
+% using; importantly, what follows has not yet been expanded so that
+% \cs{@@_group_end_replace_check:n} grabs everything until the last
+% brace in \cs{@@_group_end_replace_try:}, letting us try again with
+% an extra surrounding pair of braces.
% \begin{macrocode}
\cs_new_protected:Npn \@@_group_end_replace:N #1
{
- \if_int_compare:w \l_@@_balance_int = 0 \exp_stop_f:
- \else:
- \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
- { replacing }
- { \int_max:nn { - \l_@@_balance_int } { 0 } }
- { \int_max:nn { \l_@@_balance_int } { 0 } }
- \fi:
- \use:x
+ \int_set:Nn \l_@@_added_begin_int
+ { \int_max:nn { - \l_@@_balance_int } { 0 } }
+ \int_set:Nn \l_@@_added_end_int
+ { \int_max:nn { \l_@@_balance_int } { 0 } }
+ \@@_group_end_replace_try:
+ \int_compare:nNnT { \l_@@_added_begin_int + \l_@@_added_end_int } > 0
{
- \group_end:
- \tl_set:Nn \exp_not:N #1
- {
- \if_int_compare:w \l_@@_balance_int < 0 \exp_stop_f:
- \prg_replicate:nn { - \l_@@_balance_int }
- { { \if_false: } \fi: }
- \fi:
- \l_@@_internal_a_tl
- \if_int_compare:w \l_@@_balance_int > 0 \exp_stop_f:
- \prg_replicate:nn { \l_@@_balance_int }
- { \if_false: { \fi: } }
- \fi:
- }
+ \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
+ { replacing } { \int_use:N \l_@@_added_begin_int }
+ { \int_use:N \l_@@_added_end_int }
+ }
+ \group_end:
+ \tl_set_eq:NN #1 \g_@@_internal_tl
+ }
+\cs_new_protected:Npn \@@_group_end_replace_try:
+ {
+ \tex_afterassignment:D \@@_group_end_replace_check:w
+ \__kernel_tl_gset:Nx \g_@@_internal_tl
+ {
+ \prg_replicate:nn { \l_@@_added_begin_int } { { \if_false: } \fi: }
+ \l_@@_internal_a_tl
+ \prg_replicate:nn { \l_@@_added_end_int } { \if_false: { \fi: } }
+ \if_false: { \fi: }
+ }
+ }
+\cs_new_protected:Npn \@@_group_end_replace_check:w
+ {
+ \exp_after:wN \@@_group_end_replace_check:n
+ \exp_after:wN { \if_false: } \fi:
+ }
+\cs_new_protected:Npn \@@_group_end_replace_check:n #1
+ {
+ \tl_if_empty:nF {#1}
+ {
+ \int_incr:N \l_@@_added_begin_int
+ \int_incr:N \l_@@_added_end_int
+ \@@_group_end_replace_try:
}
}
% \end{macrocode}
@@ -7551,6 +7719,7 @@
%^^A recursion condition
%^^A (?(DEFINE)... define subpattern for reference
%^^A (?(assert)... assertion condition
+%^^A (?(?=..)..|..) positive/negative look ahead/behind condition
%^^A (*ACCEPT) force successful match
%^^A (*FAIL) force backtrack; synonym (*F)
%^^A (*COMMIT) overall failure, no advance of starting point
@@ -7567,8 +7736,10 @@
%^^A + possessive quantifiers
%^^A (?>...) atomic, non-capturing group
%^^A (?#....) comment (not nestable)
-%^^A (?JmsUx) options (duplicate names; multiline; single line;
-%^^A ungreedy; extended)
+%^^A (?Jms-UxX) options (duplicate names; multiline; single line;
+%^^A unset what follows; ungreedy; extended;
+%^^A error on bad escapes)
+%^^A (?i:...|...) convenient shorthand for (?:(?i)...|...)
%^^A (*NO_START_OPT) no start-match optimization (PCRE_NO_START_OPTIMIZE)
%^^A (*UTF8) set UTF-8 mode (PCRE_UTF8)
%^^A (*UCP) set PCRE_UCP (use Unicode properties for \d etc)