2

Consider the following MWE. If I pass some TeX code to Lua (via \directlua) and Lua tries to pass it back to TeX (via tex.sprint), the following problem becomes apparent.

The code below prints

text is  \newcommand {\foo }{##1} \foo  end

As you can see, the # doubles once passed to Lua, and of course this breaks the macro \foo.

It's necessary to wrap the text argument in \detokenize or similar, in order to stop TeX expanding it before passing to to Lua, but both \detokenize and \unexpanded have this issue.

This question: Macro char # doubles when made letter? is probably the same phenomenon. And also How do I expand exactly once a macro which takes an argument.

Suggestions on how to work around this would be appreciated. I'd obviously prefer an approach whereby I wrap the argument passed to luafun inside \NewDocumentCommand in something, rather than adding extra special code to every occurence of # in my text.

And in this context, are there any other unpleasant surprises lurking in the wings with other special TeX characters? If so, please warn me now.

\documentclass[12pt]{article}
\usepackage{xparse}
\usepackage{filecontents}
\begin{filecontents*}{fn.lua}
function luafun (text)
   texio.write_nl(string.format([[text is %s end]], text))
   tex.sprint(text)
end
\end{filecontents*}
\directlua{local scratch = require "fn.lua"}

\NewDocumentCommand{\luafun}{+m}
{
  \directlua{luafun([[\detokenize{#1}]])}
  %\directlua{luafun([[\unexpanded{#1}]])}
}
\begin{document}

\luafun
{
  \newcommand{\foo}[1]{#1}
  %\foo{foo}
}

\end{document}
  • The correct way to pass TeX tokens to Lua is with \directlua{luafun("\luaescapestring{\unexpanded{#1}}")}. Everything else will suffer from things like the hash doubling problem. – Henri Menke Jun 28 at 6:42
  • @HenriMenke I was just posting exactly the same as an answer! – Joseph Wright Jun 28 at 6:43
4

You need \unexpanded here because of it's toks-like behaviour. You also need to properly escape the tokens, so [[ .. ]] won't work. Try instead

\NewDocumentCommand{\luafun}{+m}
  {%
    \directlua{luafun("\luaescapestring{\unexpanded{#1}}")}%
  }
  • Additional spaces in the code also addressed .... – Joseph Wright Jun 28 at 6:43
  • "toks-like behaviour"? – Faheem Mitha Jun 28 at 6:44
  • Thanks. I'm relieved the solution is so simple. I had horrid visions of having to pepper my text with abstruse code in order to get it to work. – Faheem Mitha Jun 28 at 6:46
  • Why are the extra % needed? I realise they get rid of newlines, but why is that a an issue here? – Faheem Mitha Jun 28 at 6:47
  • "toks" is presumably a reference to the macro \toks, which (I think) is a token register. But the relevance still escapes me. – Faheem Mitha Jun 28 at 6:55

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.