Passing arguments from TeX to a Lua functionLuaLaTeX 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
Count rotary dial pulses in a phone number (including letters)
A steel cutting sword?
Simple fuzz pedal using breadboard
Using credit/debit card details vs swiping a card in a payment (credit card) terminal
Ticket to ride, 1910: What are the big cities
Defining the standard model of PA so that a space alien could understand
What kind of metaphor is "trees in the wind"?
What is the object moving across the ceiling in this stock footage?
how to grep in the output of ls -a
Why does Mjolnir fall down in Age of Ultron but not in Endgame?
Where have Brexit voters gone?
Simple function that simulates survey results based on sample size and probability
Line of lights moving in a straight line , with a few following
Is the field of q-series 'dead'?
How should I introduce map drawing to my players?
Writing with dry erase marker on Shabbos, is it permitted?
Why colon to denote that a value belongs to a type?
Employer demanding to see degree after poor code review
How strong are Wi-Fi signals?
What is quasi-aromaticity?
How to pull out the underlying query syntax being used by dataset?
Flying domestically in the US, is my State Issued ID all I need to get past security?
Why aren't space telescopes put in GEO?
Computing the matrix powers of a non-diagonalizable matrix
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
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 joinstringfoobar
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?
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
% directluajoinstring(#1, #2)
directluajoinstring(luastringN#1, luastringN#2)
joinstringfoobar
enddocument
Chat room discussion starts around here
luatex
|
show 8 more comments
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 joinstringfoobar
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?
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
% directluajoinstring(#1, #2)
directluajoinstring(luastringN#1, luastringN#2)
joinstringfoobar
enddocument
Chat room discussion starts around here
luatex
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 withoutluastringN
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 exampleget_macro
is in an entirely different area
– Joseph Wright♦
11 hours ago
|
show 8 more comments
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 joinstringfoobar
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?
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
% directluajoinstring(#1, #2)
directluajoinstring(luastringN#1, luastringN#2)
joinstringfoobar
enddocument
Chat room discussion starts around here
luatex
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 joinstringfoobar
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?
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
% directluajoinstring(#1, #2)
directluajoinstring(luastringN#1, luastringN#2)
joinstringfoobar
enddocument
Chat room discussion starts around here
luatex
luatex
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 withoutluastringN
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 exampleget_macro
is in an entirely different area
– Joseph Wright♦
11 hours ago
|
show 8 more comments
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 withoutluastringN
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 exampleget_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
|
show 8 more comments
3 Answers
3
active
oldest
votes
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
documentclassarticle
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
%
directluajoinstring(
"luaescapestringunexpanded#1",
"luaescapestringunexpanded#2")
%
joinstringfoobar
enddocument
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.
add a comment |
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]directluajoinstring(#1,#2)
and then running
joinstringfoobar
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
Place explicit quotation marks around the arguments of
joinstring
, i.e., runjoinstring"foo""bar"
define the LaTeX macro as
newcommandjoinstring[2]directluajoinstring("#1","#2")
I suppose that one could say that
luastring#1
and especiallyluastringN#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:
documentclassarticle
directluafunction joinstring (s,t) tex.sprint (s..t) end
newcommandjoinstring[2]directluajoinstring("#1","#2")
begindocument
joinstringfoobar
enddocument
1
Let us continue this discussion in chat.
– Joseph Wright♦
10 hours ago
add a comment |
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:
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.write(s, ', ' , t, ': ')
tex.sprint(s .. t .. '.')
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
unexpanded#1unexpanded#2
newcommandexpandedjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
#1#2%
newcommandotherexpandedjoinstring
directluajoinstring(token.scan_argument(), token.scan_argument())%
newcommandfoofoo
newcommandBarbar
verb|joinstringfoobar|: joinstringfoobar\
verb|joinstringfooBar|: joinstringfooBar\
verb|joinstring foo bar|: joinstring foo bar\
verb|expandedjoinstringfoobar|: expandedjoinstringfoobar\
verb|expandedjoinstringfooBar|: expandedjoinstringfooBar\
verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
verb|otherexpandedjoinstringfoobar|: otherexpandedjoinstringfoobar\
verb|otherexpandedjoinstringfooBar|: otherexpandedjoinstringfooBar\
verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
enddocument
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
documentclassarticle
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
%
directluajoinstring(
"luaescapestringunexpanded#1",
"luaescapestringunexpanded#2")
%
joinstringfoobar
enddocument
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.
add a comment |
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
documentclassarticle
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
%
directluajoinstring(
"luaescapestringunexpanded#1",
"luaescapestringunexpanded#2")
%
joinstringfoobar
enddocument
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.
add a comment |
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
documentclassarticle
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
%
directluajoinstring(
"luaescapestringunexpanded#1",
"luaescapestringunexpanded#2")
%
joinstringfoobar
enddocument
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.
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
documentclassarticle
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.sprint(s .. t)
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
%
directluajoinstring(
"luaescapestringunexpanded#1",
"luaescapestringunexpanded#2")
%
joinstringfoobar
enddocument
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.
answered 11 hours ago
Joseph Wright♦Joseph Wright
207k23568897
207k23568897
add a comment |
add a comment |
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]directluajoinstring(#1,#2)
and then running
joinstringfoobar
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
Place explicit quotation marks around the arguments of
joinstring
, i.e., runjoinstring"foo""bar"
define the LaTeX macro as
newcommandjoinstring[2]directluajoinstring("#1","#2")
I suppose that one could say that
luastring#1
and especiallyluastringN#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:
documentclassarticle
directluafunction joinstring (s,t) tex.sprint (s..t) end
newcommandjoinstring[2]directluajoinstring("#1","#2")
begindocument
joinstringfoobar
enddocument
1
Let us continue this discussion in chat.
– Joseph Wright♦
10 hours ago
add a comment |
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]directluajoinstring(#1,#2)
and then running
joinstringfoobar
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
Place explicit quotation marks around the arguments of
joinstring
, i.e., runjoinstring"foo""bar"
define the LaTeX macro as
newcommandjoinstring[2]directluajoinstring("#1","#2")
I suppose that one could say that
luastring#1
and especiallyluastringN#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:
documentclassarticle
directluafunction joinstring (s,t) tex.sprint (s..t) end
newcommandjoinstring[2]directluajoinstring("#1","#2")
begindocument
joinstringfoobar
enddocument
1
Let us continue this discussion in chat.
– Joseph Wright♦
10 hours ago
add a comment |
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]directluajoinstring(#1,#2)
and then running
joinstringfoobar
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
Place explicit quotation marks around the arguments of
joinstring
, i.e., runjoinstring"foo""bar"
define the LaTeX macro as
newcommandjoinstring[2]directluajoinstring("#1","#2")
I suppose that one could say that
luastring#1
and especiallyluastringN#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:
documentclassarticle
directluafunction joinstring (s,t) tex.sprint (s..t) end
newcommandjoinstring[2]directluajoinstring("#1","#2")
begindocument
joinstringfoobar
enddocument
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]directluajoinstring(#1,#2)
and then running
joinstringfoobar
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
Place explicit quotation marks around the arguments of
joinstring
, i.e., runjoinstring"foo""bar"
define the LaTeX macro as
newcommandjoinstring[2]directluajoinstring("#1","#2")
I suppose that one could say that
luastring#1
and especiallyluastringN#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:
documentclassarticle
directluafunction joinstring (s,t) tex.sprint (s..t) end
newcommandjoinstring[2]directluajoinstring("#1","#2")
begindocument
joinstringfoobar
enddocument
edited 9 hours ago
answered 11 hours ago
MicoMico
292k32402789
292k32402789
1
Let us continue this discussion in chat.
– Joseph Wright♦
10 hours ago
add a comment |
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
add a comment |
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:
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.write(s, ', ' , t, ': ')
tex.sprint(s .. t .. '.')
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
unexpanded#1unexpanded#2
newcommandexpandedjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
#1#2%
newcommandotherexpandedjoinstring
directluajoinstring(token.scan_argument(), token.scan_argument())%
newcommandfoofoo
newcommandBarbar
verb|joinstringfoobar|: joinstringfoobar\
verb|joinstringfooBar|: joinstringfooBar\
verb|joinstring foo bar|: joinstring foo bar\
verb|expandedjoinstringfoobar|: expandedjoinstringfoobar\
verb|expandedjoinstringfooBar|: expandedjoinstringfooBar\
verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
verb|otherexpandedjoinstringfoobar|: otherexpandedjoinstringfoobar\
verb|otherexpandedjoinstringfooBar|: otherexpandedjoinstringfooBar\
verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
enddocument
add a comment |
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:
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.write(s, ', ' , t, ': ')
tex.sprint(s .. t .. '.')
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
unexpanded#1unexpanded#2
newcommandexpandedjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
#1#2%
newcommandotherexpandedjoinstring
directluajoinstring(token.scan_argument(), token.scan_argument())%
newcommandfoofoo
newcommandBarbar
verb|joinstringfoobar|: joinstringfoobar\
verb|joinstringfooBar|: joinstringfooBar\
verb|joinstring foo bar|: joinstring foo bar\
verb|expandedjoinstringfoobar|: expandedjoinstringfoobar\
verb|expandedjoinstringfooBar|: expandedjoinstringfooBar\
verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
verb|otherexpandedjoinstringfoobar|: otherexpandedjoinstringfoobar\
verb|otherexpandedjoinstringfooBar|: otherexpandedjoinstringfooBar\
verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
enddocument
add a comment |
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:
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.write(s, ', ' , t, ': ')
tex.sprint(s .. t .. '.')
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
unexpanded#1unexpanded#2
newcommandexpandedjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
#1#2%
newcommandotherexpandedjoinstring
directluajoinstring(token.scan_argument(), token.scan_argument())%
newcommandfoofoo
newcommandBarbar
verb|joinstringfoobar|: joinstringfoobar\
verb|joinstringfooBar|: joinstringfooBar\
verb|joinstring foo bar|: joinstring foo bar\
verb|expandedjoinstringfoobar|: expandedjoinstringfoobar\
verb|expandedjoinstringfooBar|: expandedjoinstringfooBar\
verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
verb|otherexpandedjoinstringfoobar|: otherexpandedjoinstringfoobar\
verb|otherexpandedjoinstringfooBar|: otherexpandedjoinstringfooBar\
verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
enddocument
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:
documentclassarticle
usepackageluacode
usepackagefilecontents
beginfilecontents*luafunction2.lua
function joinstring (s, t)
tex.write(s, ', ' , t, ': ')
tex.sprint(s .. t .. '.')
end
endfilecontents*
directluarequire "luafunction2.lua"
begindocument
newcommandjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
unexpanded#1unexpanded#2
newcommandexpandedjoinstring[2]
directluajoinstring(token.scan_argument(), token.scan_argument())%
#1#2%
newcommandotherexpandedjoinstring
directluajoinstring(token.scan_argument(), token.scan_argument())%
newcommandfoofoo
newcommandBarbar
verb|joinstringfoobar|: joinstringfoobar\
verb|joinstringfooBar|: joinstringfooBar\
verb|joinstring foo bar|: joinstring foo bar\
verb|expandedjoinstringfoobar|: expandedjoinstringfoobar\
verb|expandedjoinstringfooBar|: expandedjoinstringfooBar\
verb|expandedjoinstring foo bar|: expandedjoinstring foo bar\
verb|otherexpandedjoinstringfoobar|: otherexpandedjoinstringfoobar\
verb|otherexpandedjoinstringfooBar|: otherexpandedjoinstringfooBar\
verb|otherexpandedjoinstring foo bar|: otherexpandedjoinstring foo bar\
enddocument
answered 4 hours ago
Marcel KrügerMarcel Krüger
13.2k11636
13.2k11636
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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