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
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
|
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 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
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 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
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
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
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.
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]{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
Place explicit quotation marks around the arguments of
joinstring
, i.e., run
joinstring{"foo"}{"bar"}
define the LaTeX macro as
newcommandjoinstring[2]{directlua{joinstring("#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:
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}
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:
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}
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
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.
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
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.
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
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.
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.
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]{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
Place explicit quotation marks around the arguments of
joinstring
, i.e., run
joinstring{"foo"}{"bar"}
define the LaTeX macro as
newcommandjoinstring[2]{directlua{joinstring("#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:
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}
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]{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
Place explicit quotation marks around the arguments of
joinstring
, i.e., run
joinstring{"foo"}{"bar"}
define the LaTeX macro as
newcommandjoinstring[2]{directlua{joinstring("#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:
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}
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]{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
Place explicit quotation marks around the arguments of
joinstring
, i.e., run
joinstring{"foo"}{"bar"}
define the LaTeX macro as
newcommandjoinstring[2]{directlua{joinstring("#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:
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}
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
Place explicit quotation marks around the arguments of
joinstring
, i.e., run
joinstring{"foo"}{"bar"}
define the LaTeX macro as
newcommandjoinstring[2]{directlua{joinstring("#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:
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}
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:
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}
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:
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}
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:
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}
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}
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