blefloch / latex-unravel

Watching TeX digest tokens
24 stars 1 forks source link

\unless\ifcsname throws low level error #50

Closed Skillmon closed 2 years ago

Skillmon commented 2 years ago

If the \unless primitive is used with \ifcsname a low level Missing \endcsname is thrown in \unravel. Consider the following MWE:

\documentclass[]{article}

\usepackage{unravel}

\begin{document}
\unravel
  {%
    \unless\ifcsname section\endcsname
      not
    \fi
    defined
  }
\end{document}

The bug will be triggered for both defined and undefined macros being tested.

PhelypeOleinik commented 2 years ago

\__unravel_get_lastnamedcs: tries to reconstruct the control sequence by doing

\cs:w \exp_after:wN \use_none:n \l__unravel_head_tl

where \l__unravel_head_tl is the input so far:

\unless\ifcsname section\endcsname

then \use_none:n consumes the \unless (it should consume \ifcsname), and you have:

\cs:w \ifcsname section\endcsname

which explains the error.

Checking for \reverse_if:N instead of unconditionally removing the first token seems to solve the problem:

\RequirePackage{unravel}

\ExplSyntaxOn
\cs_gset_protected:Npn \__unravel_get_lastnamedcs:
  {
    \group_begin:
    \__unravel_prev_input_get:N \l__unravel_head_tl
    \show\l__unravel_head_tl
    \tl_gset:No \g__unravel_lastnamedcs_tl
      { \cs:w \exp_after:wN \__unravel_check_unless:w \l__unravel_head_tl }
    \group_end:
  }
\cs_new:Npn \__unravel_check_unless:w #1
  { \if_meaning:w \reverse_if:N #1 \exp_after:wN \use_none:n \fi: }
\ExplSyntaxOff

\unravel{\edef\x{\unless\ifcsname section\endcsname not \fi defined}}

\stop