2

Why can I use

\startluacode
context.mymacro("\noexpand\\iftrue")
\stopluacode

But not

\startluacode
context.mymacro([[\noexpand\iftrue]])
\stopluacode

Or not

\startluacode
context.mymacro([[\unexpanded{\iftrue}]])
\stopluacode

Or not

\startluacode
context.mymacro("\luaescapestring{\normalunexpanded{\iftrue}}")
\stopluacode

Where I believe \iftrue to be an expandable primitive.

edit

\def\mymacro#1{%
    \let\mycond#1%
    \show\mycond}
4

\startluacode<code>\stopluacode translates roughly to:

\begingroup
  <catcode settings> (basically verbatim, but \ is catcode 0)
  <shorthands> (\\ is defined to be the two backslash characters, as
    well as \|, \-, \(, \), \{, \}, etc.)
\normalexpanded {\endgroup \noexpand \directlua {<code>}}

and what's biting you here is that the <code> is expanded twice: once by \normalexpanded (the \expanded primitive), and once more by \directlua.

The first one works because once the expansion of \normalexpanded is over, you are left with \directlua{context.mymacro("\\iftrue")}, which does what you want. Note that since \\ is defined to expand to \12\12, you don't need \noexpand there, so you can simplify the first example to:

\startluacode
context.mymacro("\\iftrue")
\stopluacode

The second one:

\startluacode
context.mymacro([[\noexpand\iftrue]])
\stopluacode

doesn't work because the \noexpand disappears with \normalexpanded, and you are left with \directlua{context.mymacro([[\iftrue]])}, and then \directlua expands the \iftrue too early. You'd need two rounds of \noexpand:

\startluacode
context.mymacro([[\noexpand\noexpand\noexpand\iftrue]])
\stopluacode

The third one:

\startluacode
context.mymacro([[\unexpanded{\iftrue}]])
\stopluacode

doesn't work for three reasons: first, in ConTeXt \unexpanded is the \protected primitive, not \unexpanded. You need \normalunexpanded here. Second, inside \startluacode braces are catcode 12, so \normalunexpanded will throw a Missing { inserted error. And third is the same as above: you have two rounds of expansion, so you need two \normalunexpanded:

\everyluacode\expandafter{\the\everyluacode
  \catcode`\{=1 \catcode`\}=2\relax} % catcode setting to have braces be braces
\startluacode
context.mymacro([[\normalunexpanded{\normalunexpanded{\iftrue}}]])
\stopluacode

The fourth one:

\startluacode
context.mymacro("\luaescapestring{\normalunexpanded{\iftrue}}")
\stopluacode

doesn't work for the same reason as above: braces are catcode 12, so \luaescapestring never sees the { it needs and throws a Missing { inserted error. You need to set the right catcodes first:

\everyluacode\expandafter{\the\everyluacode
  \catcode`\{=1 \catcode`\}=2\relax} % catcode setting to have braces be braces
\startluacode
context.mymacro("\luaescapestring{\normalunexpanded{\iftrue}}")
\stopluacode
2
  • Don't the catcodes expire after \endgroup? And what benefit is there to using \normalexpanded? – user19087 Mar 27 '20 at 15:03
  • 2
    @user19087 They do, but at the time the \(normal)expanded grabs the <code> as argument, the catcodes in force are the Lua ones, so everything is tokenized as catcode 12. I don't know for sure why ConTeXt uses \normalexpanded there, but I'd guess it's to use the shorthands defined earlier without having to execute the Lua code itself in a group. This allows you, to use, for example, \startluacode context.mymacro("\\iftrue")\stopluacode – Phelype Oleinik Mar 27 '20 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.