Passing arguments from TeX to a Lua functionLuaLaTeX set a path in luaCannot access arguments in a lua...

Does Nitrogen inside commercial airliner wheels prevent blowouts on touchdown?

Looking for a soft substance that doesn't dissolve underwater

Why do most published works in medical imaging try to reduce false positives?

What to do when you've set the wrong ISO for your film?

Statue View: 2, 3, 5, 7

Is CD audio quality good enough?

Is real public IP Address hidden when using a system wide proxy in Windows 10?

How do I know what is the origin IP if I ping from a router to a host of an external network in packet tracer?

how to grep in the output of ls -a

Is the Starlink array really visible from Earth?

What is quasi-aromaticity?

Image processing: Removal of two spots in fundus images

Why colon to denote that a value belongs to a type?

Where is the logic in castrating fighters?

Writing with dry erase marker on Shabbos, is it permitted?

Should breaking down something like a door be adjudicated as an attempt to beat its AC and HP, or as an ability check against a set DC?

Why does a perfectly-identical repetition of a drawing command given within an earlier loop 𝘯𝘰𝘵 produce exactly the same line?

Why aren't space telescopes put in GEO?

Were pens caps holes designed to prevent death by suffocation if swallowed?

What is the largest (size) solid object ever dropped from an airplane to impact the ground in freefall?

How to make a villain fall in love?

Plot twist where the antagonist wins

Ticket to ride, 1910: What are the big cities

Which is the common name of Mind Flayers?



Passing arguments from TeX to a Lua function


LuaLaTeX set a path in luaCannot access arguments in a lua blockPrint large macro block from Lua to TeXDoes Lua(La)TeX use external lua or built in?Accessing MySQL or SQLite from Lua(La)TeXPass macro to be parsed by lua function in directluaPrint TeX PDF page with luaPassing LaTeX blocks to LuaPassing arguments to LuaLaTeX with LuaSQLLuaTeX: Call a Lua function with two optional argumentsConTeXt passing current counter value to lua













3















The following code is a simple example of passing arguments from TeX to Lua. Just passing the arguments directly (the version without luastringN) gives an error.



(./luafunction.aux)./luafunction.lua:2: attempt to concatenate local 's' (a nil value)
stack traceback:
./luafunction.lua:2: in function 'joinstring'
[directlua]:1: in main chunk.
joinstring #1#2-> directlua {joinstring(#1, #2)}

l.19 joinstring{foo}{bar}


I noticed that other code used the macro luastringN when passing arguments from TeX to Lua, so I did too. But this is completely Cargo Cult programming, because I have no idea why. The docunentation in the luacode manual isn't very enlightening. On section 1.2 on page 3 of the v1.2a manual where luastringN is documented, it talks about escaping special characters. But there are no special characters in my example. And I don't understand what special handling is required to pass from TeX to Lua. Explanations appreciated - feel free to dumb it down.



Additionally, this answer to the question "LuaLaTeX set a path in lua" mentioned that one should use token.get_macro instead. The documentation on pg 10.6.4 of the luatex v 1.10 manual says:




The get_macro function can be used to get the content of a macro




but I'm not sure what that means. Also, I did a search in TeX SE for token.get_macro, and got two hits.



So is that a better choice, and if so, why? And what does the get_macro function do, exactly?



documentclass{article}
usepackage{luacode}
usepackage{filecontents}
begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
tex.sprint(s .. t)
end

end{filecontents*}
directlua{require "luafunction2.lua"}
begin{document}

newcommandjoinstring[2]
{
% directlua{joinstring(#1, #2)}
directlua{joinstring(luastringN{#1}, luastringN{#2})}
}

joinstring{foo}{bar}

end{document}


Chat room discussion starts around here










share|improve this question

























  • your example runs without error in texlive 2019

    – David Carlisle
    11 hours ago











  • If all you are wondering about is how a TeX argument #1 or whatever should be passed to Lua, you are overthinking things: is that the core question?

    – Joseph Wright
    11 hours ago






  • 1





    @DavidCarlisle The version without luastringN gives the error. I'll edit to clarify.

    – Faheem Mitha
    11 hours ago











  • @JosephWright That's one of my questions, yes. I ask several related ones here. Why is that "overthinking"?

    – Faheem Mitha
    11 hours ago













  • @FaheemMitha Well for example get_macro is in an entirely different area

    – Joseph Wright
    11 hours ago
















3















The following code is a simple example of passing arguments from TeX to Lua. Just passing the arguments directly (the version without luastringN) gives an error.



(./luafunction.aux)./luafunction.lua:2: attempt to concatenate local 's' (a nil value)
stack traceback:
./luafunction.lua:2: in function 'joinstring'
[directlua]:1: in main chunk.
joinstring #1#2-> directlua {joinstring(#1, #2)}

l.19 joinstring{foo}{bar}


I noticed that other code used the macro luastringN when passing arguments from TeX to Lua, so I did too. But this is completely Cargo Cult programming, because I have no idea why. The docunentation in the luacode manual isn't very enlightening. On section 1.2 on page 3 of the v1.2a manual where luastringN is documented, it talks about escaping special characters. But there are no special characters in my example. And I don't understand what special handling is required to pass from TeX to Lua. Explanations appreciated - feel free to dumb it down.



Additionally, this answer to the question "LuaLaTeX set a path in lua" mentioned that one should use token.get_macro instead. The documentation on pg 10.6.4 of the luatex v 1.10 manual says:




The get_macro function can be used to get the content of a macro




but I'm not sure what that means. Also, I did a search in TeX SE for token.get_macro, and got two hits.



So is that a better choice, and if so, why? And what does the get_macro function do, exactly?



documentclass{article}
usepackage{luacode}
usepackage{filecontents}
begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
tex.sprint(s .. t)
end

end{filecontents*}
directlua{require "luafunction2.lua"}
begin{document}

newcommandjoinstring[2]
{
% directlua{joinstring(#1, #2)}
directlua{joinstring(luastringN{#1}, luastringN{#2})}
}

joinstring{foo}{bar}

end{document}


Chat room discussion starts around here










share|improve this question

























  • your example runs without error in texlive 2019

    – David Carlisle
    11 hours ago











  • If all you are wondering about is how a TeX argument #1 or whatever should be passed to Lua, you are overthinking things: is that the core question?

    – Joseph Wright
    11 hours ago






  • 1





    @DavidCarlisle The version without luastringN gives the error. I'll edit to clarify.

    – Faheem Mitha
    11 hours ago











  • @JosephWright That's one of my questions, yes. I ask several related ones here. Why is that "overthinking"?

    – Faheem Mitha
    11 hours ago













  • @FaheemMitha Well for example get_macro is in an entirely different area

    – Joseph Wright
    11 hours ago














3












3








3








The following code is a simple example of passing arguments from TeX to Lua. Just passing the arguments directly (the version without luastringN) gives an error.



(./luafunction.aux)./luafunction.lua:2: attempt to concatenate local 's' (a nil value)
stack traceback:
./luafunction.lua:2: in function 'joinstring'
[directlua]:1: in main chunk.
joinstring #1#2-> directlua {joinstring(#1, #2)}

l.19 joinstring{foo}{bar}


I noticed that other code used the macro luastringN when passing arguments from TeX to Lua, so I did too. But this is completely Cargo Cult programming, because I have no idea why. The docunentation in the luacode manual isn't very enlightening. On section 1.2 on page 3 of the v1.2a manual where luastringN is documented, it talks about escaping special characters. But there are no special characters in my example. And I don't understand what special handling is required to pass from TeX to Lua. Explanations appreciated - feel free to dumb it down.



Additionally, this answer to the question "LuaLaTeX set a path in lua" mentioned that one should use token.get_macro instead. The documentation on pg 10.6.4 of the luatex v 1.10 manual says:




The get_macro function can be used to get the content of a macro




but I'm not sure what that means. Also, I did a search in TeX SE for token.get_macro, and got two hits.



So is that a better choice, and if so, why? And what does the get_macro function do, exactly?



documentclass{article}
usepackage{luacode}
usepackage{filecontents}
begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
tex.sprint(s .. t)
end

end{filecontents*}
directlua{require "luafunction2.lua"}
begin{document}

newcommandjoinstring[2]
{
% directlua{joinstring(#1, #2)}
directlua{joinstring(luastringN{#1}, luastringN{#2})}
}

joinstring{foo}{bar}

end{document}


Chat room discussion starts around here










share|improve this question
















The following code is a simple example of passing arguments from TeX to Lua. Just passing the arguments directly (the version without luastringN) gives an error.



(./luafunction.aux)./luafunction.lua:2: attempt to concatenate local 's' (a nil value)
stack traceback:
./luafunction.lua:2: in function 'joinstring'
[directlua]:1: in main chunk.
joinstring #1#2-> directlua {joinstring(#1, #2)}

l.19 joinstring{foo}{bar}


I noticed that other code used the macro luastringN when passing arguments from TeX to Lua, so I did too. But this is completely Cargo Cult programming, because I have no idea why. The docunentation in the luacode manual isn't very enlightening. On section 1.2 on page 3 of the v1.2a manual where luastringN is documented, it talks about escaping special characters. But there are no special characters in my example. And I don't understand what special handling is required to pass from TeX to Lua. Explanations appreciated - feel free to dumb it down.



Additionally, this answer to the question "LuaLaTeX set a path in lua" mentioned that one should use token.get_macro instead. The documentation on pg 10.6.4 of the luatex v 1.10 manual says:




The get_macro function can be used to get the content of a macro




but I'm not sure what that means. Also, I did a search in TeX SE for token.get_macro, and got two hits.



So is that a better choice, and if so, why? And what does the get_macro function do, exactly?



documentclass{article}
usepackage{luacode}
usepackage{filecontents}
begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
tex.sprint(s .. t)
end

end{filecontents*}
directlua{require "luafunction2.lua"}
begin{document}

newcommandjoinstring[2]
{
% directlua{joinstring(#1, #2)}
directlua{joinstring(luastringN{#1}, luastringN{#2})}
}

joinstring{foo}{bar}

end{document}


Chat room discussion starts around here







luatex






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 11 hours ago







Faheem Mitha

















asked 12 hours ago









Faheem MithaFaheem Mitha

3,39854064




3,39854064













  • your example runs without error in texlive 2019

    – David Carlisle
    11 hours ago











  • If all you are wondering about is how a TeX argument #1 or whatever should be passed to Lua, you are overthinking things: is that the core question?

    – Joseph Wright
    11 hours ago






  • 1





    @DavidCarlisle The version without luastringN gives the error. I'll edit to clarify.

    – Faheem Mitha
    11 hours ago











  • @JosephWright That's one of my questions, yes. I ask several related ones here. Why is that "overthinking"?

    – Faheem Mitha
    11 hours ago













  • @FaheemMitha Well for example get_macro is in an entirely different area

    – Joseph Wright
    11 hours ago



















  • your example runs without error in texlive 2019

    – David Carlisle
    11 hours ago











  • If all you are wondering about is how a TeX argument #1 or whatever should be passed to Lua, you are overthinking things: is that the core question?

    – Joseph Wright
    11 hours ago






  • 1





    @DavidCarlisle The version without luastringN gives the error. I'll edit to clarify.

    – Faheem Mitha
    11 hours ago











  • @JosephWright That's one of my questions, yes. I ask several related ones here. Why is that "overthinking"?

    – Faheem Mitha
    11 hours ago













  • @FaheemMitha Well for example get_macro is in an entirely different area

    – Joseph Wright
    11 hours ago

















your example runs without error in texlive 2019

– David Carlisle
11 hours ago





your example runs without error in texlive 2019

– David Carlisle
11 hours ago













If all you are wondering about is how a TeX argument #1 or whatever should be passed to Lua, you are overthinking things: is that the core question?

– Joseph Wright
11 hours ago





If all you are wondering about is how a TeX argument #1 or whatever should be passed to Lua, you are overthinking things: is that the core question?

– Joseph Wright
11 hours ago




1




1





@DavidCarlisle The version without luastringN gives the error. I'll edit to clarify.

– Faheem Mitha
11 hours ago





@DavidCarlisle The version without luastringN gives the error. I'll edit to clarify.

– Faheem Mitha
11 hours ago













@JosephWright That's one of my questions, yes. I ask several related ones here. Why is that "overthinking"?

– Faheem Mitha
11 hours ago







@JosephWright That's one of my questions, yes. I ask several related ones here. Why is that "overthinking"?

– Faheem Mitha
11 hours ago















@FaheemMitha Well for example get_macro is in an entirely different area

– Joseph Wright
11 hours ago





@FaheemMitha Well for example get_macro is in an entirely different area

– Joseph Wright
11 hours ago










3 Answers
3






active

oldest

votes


















3














All that luastringN does here is provide a wrapper for luaescapestring plus a few wrinkles. I'd just write that out, at least for a 'practice' file



documentclass{article}
usepackage{filecontents}
begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
tex.sprint(s .. t)
end
end{filecontents*}
directlua{require "luafunction2.lua"}
begin{document}

newcommandjoinstring[2]
{%
directlua{joinstring(
"luaescapestring{unexpanded{#1}}",
"luaescapestring{unexpanded{#2}}")
}%
}

joinstring{foo}{bar}

end{document}


Notice that luaescapestring carries out (e-type) expansion, so we need unexpanded to avoid strange stuff happening. Also notice the " characters, which are needed to tell Lua we are passing a string. We don't have to worry about any " in the TeX input as luaescapestring makes them safe.






share|improve this answer































    2














    Since the Lua function tex.sprint expects to operate on strings (either string constants, variables of type string, or something that can be coerced into type string on the fly), defining the LaTeX-side macro as



    newcommandjoinstring[2]{directlua{joinstring(#1,#2)}}


    and then running



    joinstring{foo}{bar}


    is incorrect, because foo and bar are not automatically converted into what Lua recognizes as strings. Indeed, the error message you reproduced shows that Lua considers foo and bar to be of type nil. Variables of type nil are definitely going to trip up the string concatenation operation .. in the tex.sprint ( s .. t ) instruction.



    The two obvious remedies are





    1. Place explicit quotation marks around the arguments of joinstring, i.e., run



      joinstring{"foo"}{"bar"}



    2. define the LaTeX macro as



      newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}


      I suppose that one could say that luastring{#1} and especially luastringN{#1} are elaborations (say, to prohibit expansion of #1) of the "#1" approach. They are also more robust in the sense that they can handle unbalanced (single and double) quote marks in their arguments; unbalanced double-quote marks is something that would trip up the "#1" approach.






    A full MWE that implements the second idea -- notice that for the simple code at hand it's not necessary to load the luacode package:



    enter image description here



    documentclass{article}
    directlua{function joinstring (s,t) tex.sprint (s..t) end}
    newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}
    begin{document}
    joinstring{foo}{bar}
    end{document}





    share|improve this answer





















    • 1





      Let us continue this discussion in chat.

      – Joseph Wright
      10 hours ago



















    1














    As an alternative to the luaescapestring based solution in the other answers, you can also use the token library to pass arguments from TeX to Lua. This leads to minor speed improvements, because LuaTeX doesn't have to escape the string only for Lua to parse it again. So you might consider it especially when you expect long strings. Also this avoids mixing TeX and Lua code which can help if you later decide to use your code with luafunction (or luadef).



    Anyway, you first have to decide if you want (e-type) expansion or not. The token functions always expand the arguments, so you have to apply unexpanded if you do not want this. Then you can use token.scan_argument to read a argument that is given directly after the whole Lua code. If you decide to read an expanded argument, you can also handle the argument reading entirely through Lua, but then slightly different scanning rules apply. Especially in simple cases no braces are required around string arguments.



    Here are some examples to see the actual effects of the different options:



    documentclass{article}
    usepackage{luacode}
    usepackage{filecontents}
    begin{filecontents*}{luafunction2.lua}
    function joinstring (s, t)
    tex.write(s, ', ' , t, ': ')
    tex.sprint(s .. t .. '.')
    end
    end{filecontents*}
    directlua{require "luafunction2.lua"}
    begin{document}

    newcommandjoinstring[2]{
    directlua{joinstring(token.scan_argument(), token.scan_argument())}%
    {unexpanded{#1}}{unexpanded{#2}}
    }

    newcommandexpandedjoinstring[2]
    {
    directlua{joinstring(token.scan_argument(), token.scan_argument())}%
    {#1}{#2}%
    }

    newcommandotherexpandedjoinstring
    {
    directlua{joinstring(token.scan_argument(), token.scan_argument())}%
    }

    newcommandfoo{foo}
    newcommandBar{bar}
    verb|joinstring{foo}{bar}|: joinstring{foo}{bar}\
    verb|joinstring{foo}{Bar}|: joinstring{foo}{Bar}\
    verb|joinstring foo bar|: joinstring foo bar\
    verb|expandedjoinstring{foo}{bar}|: expandedjoinstring{foo}{bar}\
    verb|expandedjoinstring{foo}{Bar}|: expandedjoinstring{foo}{Bar}\
    verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
    verb|otherexpandedjoinstring{foo}{bar}|: otherexpandedjoinstring{foo}{bar}\
    verb|otherexpandedjoinstring{foo}{Bar}|: otherexpandedjoinstring{foo}{Bar}\
    verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
    end{document}


    enter image description here






    share|improve this answer
























      Your Answer








      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "85"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f492630%2fpassing-arguments-from-tex-to-a-lua-function%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      3














      All that luastringN does here is provide a wrapper for luaescapestring plus a few wrinkles. I'd just write that out, at least for a 'practice' file



      documentclass{article}
      usepackage{filecontents}
      begin{filecontents*}{luafunction2.lua}
      function joinstring (s, t)
      tex.sprint(s .. t)
      end
      end{filecontents*}
      directlua{require "luafunction2.lua"}
      begin{document}

      newcommandjoinstring[2]
      {%
      directlua{joinstring(
      "luaescapestring{unexpanded{#1}}",
      "luaescapestring{unexpanded{#2}}")
      }%
      }

      joinstring{foo}{bar}

      end{document}


      Notice that luaescapestring carries out (e-type) expansion, so we need unexpanded to avoid strange stuff happening. Also notice the " characters, which are needed to tell Lua we are passing a string. We don't have to worry about any " in the TeX input as luaescapestring makes them safe.






      share|improve this answer




























        3














        All that luastringN does here is provide a wrapper for luaescapestring plus a few wrinkles. I'd just write that out, at least for a 'practice' file



        documentclass{article}
        usepackage{filecontents}
        begin{filecontents*}{luafunction2.lua}
        function joinstring (s, t)
        tex.sprint(s .. t)
        end
        end{filecontents*}
        directlua{require "luafunction2.lua"}
        begin{document}

        newcommandjoinstring[2]
        {%
        directlua{joinstring(
        "luaescapestring{unexpanded{#1}}",
        "luaescapestring{unexpanded{#2}}")
        }%
        }

        joinstring{foo}{bar}

        end{document}


        Notice that luaescapestring carries out (e-type) expansion, so we need unexpanded to avoid strange stuff happening. Also notice the " characters, which are needed to tell Lua we are passing a string. We don't have to worry about any " in the TeX input as luaescapestring makes them safe.






        share|improve this answer


























          3












          3








          3







          All that luastringN does here is provide a wrapper for luaescapestring plus a few wrinkles. I'd just write that out, at least for a 'practice' file



          documentclass{article}
          usepackage{filecontents}
          begin{filecontents*}{luafunction2.lua}
          function joinstring (s, t)
          tex.sprint(s .. t)
          end
          end{filecontents*}
          directlua{require "luafunction2.lua"}
          begin{document}

          newcommandjoinstring[2]
          {%
          directlua{joinstring(
          "luaescapestring{unexpanded{#1}}",
          "luaescapestring{unexpanded{#2}}")
          }%
          }

          joinstring{foo}{bar}

          end{document}


          Notice that luaescapestring carries out (e-type) expansion, so we need unexpanded to avoid strange stuff happening. Also notice the " characters, which are needed to tell Lua we are passing a string. We don't have to worry about any " in the TeX input as luaescapestring makes them safe.






          share|improve this answer













          All that luastringN does here is provide a wrapper for luaescapestring plus a few wrinkles. I'd just write that out, at least for a 'practice' file



          documentclass{article}
          usepackage{filecontents}
          begin{filecontents*}{luafunction2.lua}
          function joinstring (s, t)
          tex.sprint(s .. t)
          end
          end{filecontents*}
          directlua{require "luafunction2.lua"}
          begin{document}

          newcommandjoinstring[2]
          {%
          directlua{joinstring(
          "luaescapestring{unexpanded{#1}}",
          "luaescapestring{unexpanded{#2}}")
          }%
          }

          joinstring{foo}{bar}

          end{document}


          Notice that luaescapestring carries out (e-type) expansion, so we need unexpanded to avoid strange stuff happening. Also notice the " characters, which are needed to tell Lua we are passing a string. We don't have to worry about any " in the TeX input as luaescapestring makes them safe.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 11 hours ago









          Joseph WrightJoseph Wright

          207k23568897




          207k23568897























              2














              Since the Lua function tex.sprint expects to operate on strings (either string constants, variables of type string, or something that can be coerced into type string on the fly), defining the LaTeX-side macro as



              newcommandjoinstring[2]{directlua{joinstring(#1,#2)}}


              and then running



              joinstring{foo}{bar}


              is incorrect, because foo and bar are not automatically converted into what Lua recognizes as strings. Indeed, the error message you reproduced shows that Lua considers foo and bar to be of type nil. Variables of type nil are definitely going to trip up the string concatenation operation .. in the tex.sprint ( s .. t ) instruction.



              The two obvious remedies are





              1. Place explicit quotation marks around the arguments of joinstring, i.e., run



                joinstring{"foo"}{"bar"}



              2. define the LaTeX macro as



                newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}


                I suppose that one could say that luastring{#1} and especially luastringN{#1} are elaborations (say, to prohibit expansion of #1) of the "#1" approach. They are also more robust in the sense that they can handle unbalanced (single and double) quote marks in their arguments; unbalanced double-quote marks is something that would trip up the "#1" approach.






              A full MWE that implements the second idea -- notice that for the simple code at hand it's not necessary to load the luacode package:



              enter image description here



              documentclass{article}
              directlua{function joinstring (s,t) tex.sprint (s..t) end}
              newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}
              begin{document}
              joinstring{foo}{bar}
              end{document}





              share|improve this answer





















              • 1





                Let us continue this discussion in chat.

                – Joseph Wright
                10 hours ago
















              2














              Since the Lua function tex.sprint expects to operate on strings (either string constants, variables of type string, or something that can be coerced into type string on the fly), defining the LaTeX-side macro as



              newcommandjoinstring[2]{directlua{joinstring(#1,#2)}}


              and then running



              joinstring{foo}{bar}


              is incorrect, because foo and bar are not automatically converted into what Lua recognizes as strings. Indeed, the error message you reproduced shows that Lua considers foo and bar to be of type nil. Variables of type nil are definitely going to trip up the string concatenation operation .. in the tex.sprint ( s .. t ) instruction.



              The two obvious remedies are





              1. Place explicit quotation marks around the arguments of joinstring, i.e., run



                joinstring{"foo"}{"bar"}



              2. define the LaTeX macro as



                newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}


                I suppose that one could say that luastring{#1} and especially luastringN{#1} are elaborations (say, to prohibit expansion of #1) of the "#1" approach. They are also more robust in the sense that they can handle unbalanced (single and double) quote marks in their arguments; unbalanced double-quote marks is something that would trip up the "#1" approach.






              A full MWE that implements the second idea -- notice that for the simple code at hand it's not necessary to load the luacode package:



              enter image description here



              documentclass{article}
              directlua{function joinstring (s,t) tex.sprint (s..t) end}
              newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}
              begin{document}
              joinstring{foo}{bar}
              end{document}





              share|improve this answer





















              • 1





                Let us continue this discussion in chat.

                – Joseph Wright
                10 hours ago














              2












              2








              2







              Since the Lua function tex.sprint expects to operate on strings (either string constants, variables of type string, or something that can be coerced into type string on the fly), defining the LaTeX-side macro as



              newcommandjoinstring[2]{directlua{joinstring(#1,#2)}}


              and then running



              joinstring{foo}{bar}


              is incorrect, because foo and bar are not automatically converted into what Lua recognizes as strings. Indeed, the error message you reproduced shows that Lua considers foo and bar to be of type nil. Variables of type nil are definitely going to trip up the string concatenation operation .. in the tex.sprint ( s .. t ) instruction.



              The two obvious remedies are





              1. Place explicit quotation marks around the arguments of joinstring, i.e., run



                joinstring{"foo"}{"bar"}



              2. define the LaTeX macro as



                newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}


                I suppose that one could say that luastring{#1} and especially luastringN{#1} are elaborations (say, to prohibit expansion of #1) of the "#1" approach. They are also more robust in the sense that they can handle unbalanced (single and double) quote marks in their arguments; unbalanced double-quote marks is something that would trip up the "#1" approach.






              A full MWE that implements the second idea -- notice that for the simple code at hand it's not necessary to load the luacode package:



              enter image description here



              documentclass{article}
              directlua{function joinstring (s,t) tex.sprint (s..t) end}
              newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}
              begin{document}
              joinstring{foo}{bar}
              end{document}





              share|improve this answer















              Since the Lua function tex.sprint expects to operate on strings (either string constants, variables of type string, or something that can be coerced into type string on the fly), defining the LaTeX-side macro as



              newcommandjoinstring[2]{directlua{joinstring(#1,#2)}}


              and then running



              joinstring{foo}{bar}


              is incorrect, because foo and bar are not automatically converted into what Lua recognizes as strings. Indeed, the error message you reproduced shows that Lua considers foo and bar to be of type nil. Variables of type nil are definitely going to trip up the string concatenation operation .. in the tex.sprint ( s .. t ) instruction.



              The two obvious remedies are





              1. Place explicit quotation marks around the arguments of joinstring, i.e., run



                joinstring{"foo"}{"bar"}



              2. define the LaTeX macro as



                newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}


                I suppose that one could say that luastring{#1} and especially luastringN{#1} are elaborations (say, to prohibit expansion of #1) of the "#1" approach. They are also more robust in the sense that they can handle unbalanced (single and double) quote marks in their arguments; unbalanced double-quote marks is something that would trip up the "#1" approach.






              A full MWE that implements the second idea -- notice that for the simple code at hand it's not necessary to load the luacode package:



              enter image description here



              documentclass{article}
              directlua{function joinstring (s,t) tex.sprint (s..t) end}
              newcommandjoinstring[2]{directlua{joinstring("#1","#2")}}
              begin{document}
              joinstring{foo}{bar}
              end{document}






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited 9 hours ago

























              answered 11 hours ago









              MicoMico

              292k32402789




              292k32402789








              • 1





                Let us continue this discussion in chat.

                – Joseph Wright
                10 hours ago














              • 1





                Let us continue this discussion in chat.

                – Joseph Wright
                10 hours ago








              1




              1





              Let us continue this discussion in chat.

              – Joseph Wright
              10 hours ago





              Let us continue this discussion in chat.

              – Joseph Wright
              10 hours ago











              1














              As an alternative to the luaescapestring based solution in the other answers, you can also use the token library to pass arguments from TeX to Lua. This leads to minor speed improvements, because LuaTeX doesn't have to escape the string only for Lua to parse it again. So you might consider it especially when you expect long strings. Also this avoids mixing TeX and Lua code which can help if you later decide to use your code with luafunction (or luadef).



              Anyway, you first have to decide if you want (e-type) expansion or not. The token functions always expand the arguments, so you have to apply unexpanded if you do not want this. Then you can use token.scan_argument to read a argument that is given directly after the whole Lua code. If you decide to read an expanded argument, you can also handle the argument reading entirely through Lua, but then slightly different scanning rules apply. Especially in simple cases no braces are required around string arguments.



              Here are some examples to see the actual effects of the different options:



              documentclass{article}
              usepackage{luacode}
              usepackage{filecontents}
              begin{filecontents*}{luafunction2.lua}
              function joinstring (s, t)
              tex.write(s, ', ' , t, ': ')
              tex.sprint(s .. t .. '.')
              end
              end{filecontents*}
              directlua{require "luafunction2.lua"}
              begin{document}

              newcommandjoinstring[2]{
              directlua{joinstring(token.scan_argument(), token.scan_argument())}%
              {unexpanded{#1}}{unexpanded{#2}}
              }

              newcommandexpandedjoinstring[2]
              {
              directlua{joinstring(token.scan_argument(), token.scan_argument())}%
              {#1}{#2}%
              }

              newcommandotherexpandedjoinstring
              {
              directlua{joinstring(token.scan_argument(), token.scan_argument())}%
              }

              newcommandfoo{foo}
              newcommandBar{bar}
              verb|joinstring{foo}{bar}|: joinstring{foo}{bar}\
              verb|joinstring{foo}{Bar}|: joinstring{foo}{Bar}\
              verb|joinstring foo bar|: joinstring foo bar\
              verb|expandedjoinstring{foo}{bar}|: expandedjoinstring{foo}{bar}\
              verb|expandedjoinstring{foo}{Bar}|: expandedjoinstring{foo}{Bar}\
              verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
              verb|otherexpandedjoinstring{foo}{bar}|: otherexpandedjoinstring{foo}{bar}\
              verb|otherexpandedjoinstring{foo}{Bar}|: otherexpandedjoinstring{foo}{Bar}\
              verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
              end{document}


              enter image description here






              share|improve this answer




























                1














                As an alternative to the luaescapestring based solution in the other answers, you can also use the token library to pass arguments from TeX to Lua. This leads to minor speed improvements, because LuaTeX doesn't have to escape the string only for Lua to parse it again. So you might consider it especially when you expect long strings. Also this avoids mixing TeX and Lua code which can help if you later decide to use your code with luafunction (or luadef).



                Anyway, you first have to decide if you want (e-type) expansion or not. The token functions always expand the arguments, so you have to apply unexpanded if you do not want this. Then you can use token.scan_argument to read a argument that is given directly after the whole Lua code. If you decide to read an expanded argument, you can also handle the argument reading entirely through Lua, but then slightly different scanning rules apply. Especially in simple cases no braces are required around string arguments.



                Here are some examples to see the actual effects of the different options:



                documentclass{article}
                usepackage{luacode}
                usepackage{filecontents}
                begin{filecontents*}{luafunction2.lua}
                function joinstring (s, t)
                tex.write(s, ', ' , t, ': ')
                tex.sprint(s .. t .. '.')
                end
                end{filecontents*}
                directlua{require "luafunction2.lua"}
                begin{document}

                newcommandjoinstring[2]{
                directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                {unexpanded{#1}}{unexpanded{#2}}
                }

                newcommandexpandedjoinstring[2]
                {
                directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                {#1}{#2}%
                }

                newcommandotherexpandedjoinstring
                {
                directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                }

                newcommandfoo{foo}
                newcommandBar{bar}
                verb|joinstring{foo}{bar}|: joinstring{foo}{bar}\
                verb|joinstring{foo}{Bar}|: joinstring{foo}{Bar}\
                verb|joinstring foo bar|: joinstring foo bar\
                verb|expandedjoinstring{foo}{bar}|: expandedjoinstring{foo}{bar}\
                verb|expandedjoinstring{foo}{Bar}|: expandedjoinstring{foo}{Bar}\
                verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
                verb|otherexpandedjoinstring{foo}{bar}|: otherexpandedjoinstring{foo}{bar}\
                verb|otherexpandedjoinstring{foo}{Bar}|: otherexpandedjoinstring{foo}{Bar}\
                verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
                end{document}


                enter image description here






                share|improve this answer


























                  1












                  1








                  1







                  As an alternative to the luaescapestring based solution in the other answers, you can also use the token library to pass arguments from TeX to Lua. This leads to minor speed improvements, because LuaTeX doesn't have to escape the string only for Lua to parse it again. So you might consider it especially when you expect long strings. Also this avoids mixing TeX and Lua code which can help if you later decide to use your code with luafunction (or luadef).



                  Anyway, you first have to decide if you want (e-type) expansion or not. The token functions always expand the arguments, so you have to apply unexpanded if you do not want this. Then you can use token.scan_argument to read a argument that is given directly after the whole Lua code. If you decide to read an expanded argument, you can also handle the argument reading entirely through Lua, but then slightly different scanning rules apply. Especially in simple cases no braces are required around string arguments.



                  Here are some examples to see the actual effects of the different options:



                  documentclass{article}
                  usepackage{luacode}
                  usepackage{filecontents}
                  begin{filecontents*}{luafunction2.lua}
                  function joinstring (s, t)
                  tex.write(s, ', ' , t, ': ')
                  tex.sprint(s .. t .. '.')
                  end
                  end{filecontents*}
                  directlua{require "luafunction2.lua"}
                  begin{document}

                  newcommandjoinstring[2]{
                  directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                  {unexpanded{#1}}{unexpanded{#2}}
                  }

                  newcommandexpandedjoinstring[2]
                  {
                  directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                  {#1}{#2}%
                  }

                  newcommandotherexpandedjoinstring
                  {
                  directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                  }

                  newcommandfoo{foo}
                  newcommandBar{bar}
                  verb|joinstring{foo}{bar}|: joinstring{foo}{bar}\
                  verb|joinstring{foo}{Bar}|: joinstring{foo}{Bar}\
                  verb|joinstring foo bar|: joinstring foo bar\
                  verb|expandedjoinstring{foo}{bar}|: expandedjoinstring{foo}{bar}\
                  verb|expandedjoinstring{foo}{Bar}|: expandedjoinstring{foo}{Bar}\
                  verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
                  verb|otherexpandedjoinstring{foo}{bar}|: otherexpandedjoinstring{foo}{bar}\
                  verb|otherexpandedjoinstring{foo}{Bar}|: otherexpandedjoinstring{foo}{Bar}\
                  verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
                  end{document}


                  enter image description here






                  share|improve this answer













                  As an alternative to the luaescapestring based solution in the other answers, you can also use the token library to pass arguments from TeX to Lua. This leads to minor speed improvements, because LuaTeX doesn't have to escape the string only for Lua to parse it again. So you might consider it especially when you expect long strings. Also this avoids mixing TeX and Lua code which can help if you later decide to use your code with luafunction (or luadef).



                  Anyway, you first have to decide if you want (e-type) expansion or not. The token functions always expand the arguments, so you have to apply unexpanded if you do not want this. Then you can use token.scan_argument to read a argument that is given directly after the whole Lua code. If you decide to read an expanded argument, you can also handle the argument reading entirely through Lua, but then slightly different scanning rules apply. Especially in simple cases no braces are required around string arguments.



                  Here are some examples to see the actual effects of the different options:



                  documentclass{article}
                  usepackage{luacode}
                  usepackage{filecontents}
                  begin{filecontents*}{luafunction2.lua}
                  function joinstring (s, t)
                  tex.write(s, ', ' , t, ': ')
                  tex.sprint(s .. t .. '.')
                  end
                  end{filecontents*}
                  directlua{require "luafunction2.lua"}
                  begin{document}

                  newcommandjoinstring[2]{
                  directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                  {unexpanded{#1}}{unexpanded{#2}}
                  }

                  newcommandexpandedjoinstring[2]
                  {
                  directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                  {#1}{#2}%
                  }

                  newcommandotherexpandedjoinstring
                  {
                  directlua{joinstring(token.scan_argument(), token.scan_argument())}%
                  }

                  newcommandfoo{foo}
                  newcommandBar{bar}
                  verb|joinstring{foo}{bar}|: joinstring{foo}{bar}\
                  verb|joinstring{foo}{Bar}|: joinstring{foo}{Bar}\
                  verb|joinstring foo bar|: joinstring foo bar\
                  verb|expandedjoinstring{foo}{bar}|: expandedjoinstring{foo}{bar}\
                  verb|expandedjoinstring{foo}{Bar}|: expandedjoinstring{foo}{Bar}\
                  verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
                  verb|otherexpandedjoinstring{foo}{bar}|: otherexpandedjoinstring{foo}{bar}\
                  verb|otherexpandedjoinstring{foo}{Bar}|: otherexpandedjoinstring{foo}{Bar}\
                  verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
                  end{document}


                  enter image description here







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 4 hours ago









                  Marcel KrügerMarcel Krüger

                  13.2k11636




                  13.2k11636






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f492630%2fpassing-arguments-from-tex-to-a-lua-function%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Taj Mahal Inhaltsverzeichnis Aufbau | Geschichte | 350-Jahr-Feier | Heutige Bedeutung | Siehe auch |...

                      Baia Sprie Cuprins Etimologie | Istorie | Demografie | Politică și administrație | Arii naturale...

                      Nicolae Petrescu-Găină Cuprins Biografie | Opera | In memoriam | Varia | Controverse, incertitudini...