4

Given this example code:

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn

\group_begin:
\char_set_catcode_active:n { `\* }
\cs_new_protected:Npn \foo #1
  {
    \group_begin:
    \char_set_catcode_active:N \ 
    \char_set_lccode:nn { `\* } { `\  }
    \tex_lowercase:D { \cs_set:Npn * } { Y }
%    \tl_lower_case:n { \cs_set:Npn * } { Y }
    #1
    \group_end:
  }
\group_end:

\ExplSyntaxOff

\begin{document}
\begingroup
\catcode`\ \active
\gdef {X}
\gdef\fooarg{   }
\endgroup

\fooarg

\expandafter\foo\expandafter{\fooarg}
\end{document}

Within the argument of \foo active space characters are re-mapped to a new meaning. To not bring an active space into scope for the whole definition of \foo, the \lowercase trick was used.

There are two issues with this code:

  1. The relevant line of the trick uses a "do not use" function, namely \tex_lowercase:D. Is there a more idiomatic way for replacing that whole pattern using expl3-only functions?
  2. According to the documentation of \char_set_lccode:nn, \tl_lower_case:n seem to be the "official" \tex_lowercase:D replacement function. But when used in the above code it produces an error

    ! Undefined control sequence.
    <argument> *
    

    not only for * but also for several other characters. Why does this happen?

siracusa
  • 13,411

1 Answers1

4

There's no need to use the \lowercase trick (at the expense of defining an additional function) for locally setting the meaning of an active character, thanks to \char_set_active_eq:nN.

However, you should not define \foo with an argument, or the argument would be collected and tokenized before the space becomes active.

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn

\cs_new_protected:Npn \foo
  {
    \group_begin:
    \cs_set:Npn \siracusa_test: { Y }
    \char_set_active_eq:nN { `\  } \siracusa_test:
    \char_set_catcode_active:n { `\  }
    \__siracusa_foo:n
  }
\cs_new_protected:Npn \__siracusa_foo:n #1
  {
    #1
    \group_end:
  }

\ExplSyntaxOff

\begin{document}
\begingroup
\catcode`\ \active
\gdef {X}
\gdef\fooarg{   }
\endgroup

\fooarg

\expandafter\foo\expandafter{\fooarg}
\end{document}

enter image description here

egreg
  • 1,121,712
  • 2
    Perhaps worth adding that the reason we have \char_set_active_eq:nN using a second function is that the latter should be a well-defined and documented code-level construct. – Joseph Wright Jun 24 '19 at 09:41