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}

1 Answer 1

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, 2020 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 Mar 27, 2020 at 16:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .