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? Sep 23, 2020 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. Sep 23, 2020 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:-) Sep 23, 2020 at 22:45
  • note \luastring isn't a defined command, you are presumably using an unspecified package that defines it? Sep 23, 2020 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:-) Sep 24, 2020 at 6:36

2 Answers 2

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? Sep 23, 2020 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 Sep 23, 2020 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. Sep 24, 2020 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}

You must log in to answer this question.

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