A comment below has clarified my problem, it has nothing to do with lua. In the code snippet below:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \sops_format_set_expr:n #1 {
\tl_set:Nn \l_tmpa_tl {A+\overline{(B+A)}}
\tl_replace_all:Nnn \l_tmpa_tl {+}{\cup}
\tl_use:N \l_tmpa_tl
}
\NewDocumentCommand{\seval}{ m }{
$\sops_format_set_expr:n {#1}$
}
\ExplSyntaxOff
\begin{document}
\seval{A+-(B+A)}
\end{document}
Is there a better way to perform the replacement + to \cup, than (for example) iterating over the string A+\overline{(B+A)} with \tl_head, checking for head=group along the way, and then piecing it back together?
Background: I'm making a little package to evaluate and format some set expressions. I have code to do the evaluation, however printing is an issue. I have code in lua that will evaluate an expression of the form A+(B*C) (with + interpreted as set union, and * interpreted as intersection) and print the resulting set. Finding an appropriate way to handle complements, resulted in (what I felt was) the need to use pattern matching in lua to handle balanced delimiters properly. As a result, part of the code does some string manipulation in lua, and spits it back to tex to be formatted.
Question: The code below attempts to take a string of the form -(<stuff>), and replace it with \overline{(<stuff>)} in tex. See an earlier question of mine for reference.
\begingroup
\catcode`\%=12\relax
\gdef\patmatch{"%-(%b())","\noexpand\\overline{%1}"}
\endgroup
\def\setcomp#1{%
\directlua{
local s, _ = string.gsub("\luatexluaescapestring{#1}",\patmatch)
tex.sprint(s)
%tex.sprint(-2,s)
}
}
I would like to have tex parse the resulting string (?) to replace * with \cap and + with \cup. The issue is that in the replacement, tex does not recognize any + that is handled by lua in the string substitution above. The code below "accomplishes" the substitution:
\cs_new_protected:Npn \sops_format_set_expr:n #1 {
\tl_set:Nx \l_tmpa_tl {\setcomp{#1}}
\tl_replace_all:Nnn \l_tmpa_tl {+}{\cup}
\tl_use:N \l_tmpa_tl
}
\NewDocumentCommand{\seval}{ m }{
$\sops_format_set_expr:n {#1}$
}
When \seval is called on something like \seval{A+-(B+A)}, the -(B+A) is first handled by the string substitution and replaced with \overline{(B+A)}, when we have A+\overline{(B+A)} to be scanned for replacement of + with \cup. The problem is that the first occurrence of + (the one not involved with the string substitution) is recognized, while the second one is not. I blindly attempted to use string.sprint(-2,s) as commented in the first code block above, in which case the second + is recognized, but the macro is not.
As usual, my puny brain is unable to handle the intricacies of tex/lua catcode interaction. Could someone please explain what the problem is, and how to fix it? MWE below.
\documentclass{article}
\usepackage{xparse}
\begingroup
\catcode`\%=12\relax
\gdef\patmatch{"%-(%b())","\noexpand\\overline{%1}"}
\endgroup
\def\setcomp#1{%
\directlua{
local s, _ = string.gsub("\luatexluaescapestring{#1}",\patmatch)
tex.sprint(s)
}
}
\ExplSyntaxOn
\cs_new_protected:Npn \sops_format_set_expr:n #1 {
\tl_set:Nx \l_tmpa_tl {\setcomp{#1}}
\tl_replace_all:Nnn \l_tmpa_tl {+}{\cup}
\tl_use:N \l_tmpa_tl
}
\NewDocumentCommand{\seval}{ m }{
$\sops_format_set_expr:n {#1}$
}
\ExplSyntaxOff
\begin{document}
\seval{A+-(B+A)}
\end{document}
\tl_replaceworks on a “item” basis, not on a token basis. So if you have{+}it's seen not as{,+and}(three tokens) but as{+}(one item), and you can't reach the+inside a group{}. – Manuel Sep 18 '14 at 22:43\tl_head, handling a group as the head separately, and piecing back together? – Scott H. Sep 18 '14 at 23:01