[latex3-commits] [git/LaTeX3-latex3-latex3] main: Fix error check for unbalanced braces in regex replacement (see #377) (9ede50e4c)
Bruno Le Floch
blflatex at gmail.com
Thu May 13 00:12:33 CEST 2021
Repository : https://github.com/latex3/latex3
On branch : main
Link : https://github.com/latex3/latex3/commit/9ede50e4cbb98b7189af3349d1ca1f9a413aaa00
>---------------------------------------------------------------
commit 9ede50e4cbb98b7189af3349d1ca1f9a413aaa00
Author: Bruno Le Floch <blflatex at gmail.com>
Date: Thu May 13 00:12:33 2021 +0200
Fix error check for unbalanced braces in regex replacement (see #377)
>---------------------------------------------------------------
9ede50e4cbb98b7189af3349d1ca1f9a413aaa00
l3kernel/l3regex.dtx | 90 +++++++++++++++++++++++----------
l3kernel/testfiles/m3regex006.lvt | 2 +-
l3kernel/testfiles/m3regex006.tlg | 104 +++++++++++++++++++++++++++++---------
3 files changed, 145 insertions(+), 51 deletions(-)
diff --git a/l3kernel/l3regex.dtx b/l3kernel/l3regex.dtx
index 37ba50587..3cdb00818 100644
--- a/l3kernel/l3regex.dtx
+++ b/l3kernel/l3regex.dtx
@@ -6349,6 +6349,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
@@ -6717,36 +6726,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}
diff --git a/l3kernel/testfiles/m3regex006.lvt b/l3kernel/testfiles/m3regex006.lvt
index 2b4290454..42f69b8d5 100644
--- a/l3kernel/testfiles/m3regex006.lvt
+++ b/l3kernel/testfiles/m3regex006.lvt
@@ -145,7 +145,7 @@
\test:nnnTF { ([^c])a } { \1 \cB< \0 } { ab{c}ade } \TRUE \ERROR
\test:nnnTF { ([^c])..a } { \c{\1} } { ab{c}ade } \TRUE \ERROR
\test:nnnTF { [c-z] } { \x00 \x{02} } { ab{c}ade } \TRUE \ERROR
- \test:nnnTF { (.) b(.) } { \cB\x5c\2\2 } { aba{b}#d } \TRUE \ERROR
+ \test:nnnTF { (.) b(.) } { \}\}\{\{\cB\x5c\2\2 } { aba{b}#d } \TRUE \ERROR
\test:nnnTF { \# (.*?)c } { \c{use:n} \1 } { a#{b}c#d } \TRUE \ERROR
}
diff --git a/l3kernel/testfiles/m3regex006.tlg b/l3kernel/testfiles/m3regex006.tlg
index 14da26466..ea8f261b7 100644
--- a/l3kernel/testfiles/m3regex006.tlg
+++ b/l3kernel/testfiles/m3regex006.tlg
@@ -556,80 +556,136 @@ For immediate help type H <return>.
l. ... }
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: 0 left, 1 right.
+Braces were inserted: 2 left, 3 right.
TRUE
-macro:->\aa{b}##d}
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
+Braces were inserted: 2 left, 3 right.
TRUE
-macro:->\aa{b}##d}
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
-macro:->\aa{b}##d}
+Braces were inserted: 2 left, 3 right.
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
-macro:->\aa{b}##d}
+Braces were inserted: 2 left, 3 right.
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
+Braces were inserted: 2 left, 3 right.
TRUE
-macro:->\aa{b}##d}
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
+Braces were inserted: 2 left, 3 right.
TRUE
-macro:->\aa{b}##d}
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
-macro:->\aa{b}##d}
+Braces were inserted: 2 left, 3 right.
+macro:->{{}}{{\aa{b}##d}}}
! LaTeX3 Error: Missing brace inserted when replacing.
For immediate help type H <return>.
...
l. ... }
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: 0 left, 1 right.
-macro:->\aa{b}##d}
+Braces were inserted: 2 left, 3 right.
+macro:->{{}}{{\aa{b}##d}}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
TRUE
-macro:->\aa\}}##d
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
TRUE
-macro:->\aa\}}##d
-macro:->\aa\}}##d
-macro:->\aa\}}##d
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
TRUE
-macro:->\aa\}}##d
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
TRUE
-macro:->\aa\}}##d
-macro:->\aa\}}##d
-macro:->\aa\}}##d
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
+macro:->{{}}{{\aa}}{{\}}##d}}
+! LaTeX3 Error: Missing brace inserted when replacing.
+For immediate help type H <return>.
+ ...
+l. ... }
+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, 2 right.
+macro:->{{}}{{\aa}}{{\}}##d}}
macro:->aba{b}##d
TRUE
macro:->a\use:n {b}##d
More information about the latex3-commits
mailing list.