1

How can you pass multiple arguments from a tex command to a lua function, whilst also escaping them

Or how do I modify

(imports)

\usepackage{luacode}
\newcommand{\example}[1]{
    \directlua{
        function debug(...)
            local arr = {...}
            for i, v in pairs(arr) do
                print(v)
            end
        end
        debug(#1)
    }
}

such that

\example{\notDefined, aNilValue, 5}

produces standard output of

\notDefined
aNilValue
5

instead of throwing

  • Undefined control sequence (latex error)
  • or printing nothing because the variable aNilValue is not defined

I've tried using \luastring{\unexpanded{...}} with \docsvlist but i keep getting runaway arguments

EDIT Clearification, all passed arguments should be strings so local arr = {...} should equal in the example {"\\notDefined", "aNilValue", "5"}

6
  • you could make it a list of strings so in Lua debug("\\notDefined", "aNilValue", "5") but it seems you want to pass 5 as an integer and aNilValue as an undefined Lua variable? – David Carlisle Sep 23 '20 at 22:35
  • No output should be, ''\\notDefined↵aNilValue↵5↵". Yes I could just pass the strings, but that's missing the point of the question. The point here is how avoid having to manually escape and quote the variables, first for less type work and second to avoid errors. That's why I started with \luastring and unexpanded. – Sam Coutteau Sep 23 '20 at 22:42
  • no I understand you want the input to not have explict escaping, but it isn't clear what you want the Lua input to be, whether the tex 5 is a Lua string "5" or a Lua integer 5, but I'll post an answer, see if it's any use:-) – David Carlisle Sep 23 '20 at 22:45
  • note \luastring isn't a defined command, you are presumably using an unspecified package that defines it? – David Carlisle Sep 23 '20 at 22:48
  • 1
    @Mico I know: it was just a hint to Sam to make his question clearer for others (which he did, thanks:-) – David Carlisle Sep 24 '20 at 6:36
2

It could take more care of white space but this makes a lua string of the whole list then splits on commas so every item is interpreted as a string.

\newcommand{\example}[1]{%
    \directlua{
        function debug(s)
            for v in string.gmatch(s,'[^,]*') do
                print(v)
            end
        end
        debug("\luaescapestring{\detokenize{#1}}",",")
    }%
}

\typeout{}

\example{\notDefined, aNilValue, 5}

\stop

produces terminal output


\notDefined 
 aNilValue
 5
3
  • What does \typeout{} and \stop do here?, it doesn't seem necessary? – Sam Coutteau Sep 23 '20 at 23:00
  • try it without, it just forces a newline so the first print is away from the latex startup banner in the terminal output. @SamCoutteau – David Carlisle Sep 23 '20 at 23:09
  • @SamCoutteau I'm sorry I didn't answer about \stop that is just to make a complete test latex document, you can run the code above in lualatex and it shows the test output then exits. Posting fragments (as in your question:-) makes it harder for other people to run the code. – David Carlisle Sep 24 '20 at 19:30
0

This solution uses LaTeX3's comma separated list. The arguments of \example will be written to the log file.

\documentclass{article}
\usepackage{expl3}

\directlua{
  function debug(...)
      local arr = {...}
      for i, v in pairs(arr) do
          texio.write_nl(v)
      end
  end
}

\ExplSyntaxOn
\newcommand{\example}[1]{
  % construct comma separated list
  \clist_set:Nn \l_tmpa_clist {#1}
  % construct lua string for each component
  % and store them in a sequence
  \seq_clear:N \l_tmpa_seq
  \clist_map_inline:Nn \l_tmpa_clist {
    \str_set:Nn \l_tmpa_str {##1}
    \seq_put_right:Nx \l_tmpa_seq {"\luaescapestring{\l_tmpa_str}"}
  }
  \directlua{debug(\seq_use:Nn \l_tmpa_seq {,})}
}
\ExplSyntaxOff

\begin{document}
\example{\notDefined, aNilValue, 5}
\end{document}

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.