# LuaTeX: Is there a way to define new named tex box purely on lua side (with desired checks)?

So far in my dealings with named tex boxes in luatex, I am able to set/get/copy its contents in lua code, but don't know how define new tex box in lua. The manual doesn't have a method explicitly meant for that (while it has all other box manipulation methods). Is there a way to do this in lua? Below is the skeleton of code to build upon. Function createbox is passed name of the box to be created, and it acts like calling \newsavebox (with name test).

\documentclass{article}

\begin{filecontents*}{texbox.lua}
function createbox(boxname)
if <box of name boxname does not exist> then -- luatex equivalent of ifcsname?
tex.print("\\newbox\\" .. boxname)
end
end
\end{filecontents*}

\directlua{require"texbox.lua"}

\begin{document}

\directlua{createbox('mybox')} % use lua method instead of using \newsavebox on tex side

\setbox\mybox = \hbox{Hello World}

\box\mybox

\end{document}


• note that unlike \newcommand, \newbox and friends (following the tradition of plain tex) do not check that the csname is undefined, \newbox\frac will over-write \frac with no warning. Oct 3, 2020 at 8:28

Register allocation is a macro format defined thing so not in the luatex manual. You appear to be using lualatex so box allocation is count 14 (which happens to be the same as plain tex) and the following shows how they can be allocated from tex or lua in the same sequence.

You could check that the name (\luaboxa here) is new, but the tex defined \newbox does not do that (see the multiple calls to \newbox\zzz below) , you can use \newbox\frac or \newbox\section and break the document with no warning.

It does check that you have not run out of registers. Here I more or less directly re-implement the LaTeX \e@alloc macro in Lua. Now the function new_box also checks if the box of that name is already defined, if yes it doesn't allocate a new box register for it. This is the intended behavior requested in the question, and should also save one from accidentally allocating more than one box register for a given boxname.

\documentclass{article}

\newbox\texboxa
\typeout{texboxa: \number\texboxa}

\directlua{
function e_alloc(nm,c,ta,tb,cs)
tex.setcount("global",c,tex.count[c]+1)
e_check_alloc(c,ta,tb,nm)
tex.setcount("global","allocationnumber",tex.count[c])
token.set_char(cs,tex.count[c],"global")
texio.write("log",cs .."=" .. tex.count[c])
end
function e_check_alloc(c,ta,tb,nm)
if ( tex.count[c] >= ta) then
if (tex.count[c] == ta)then
tex.setcount("global",c,256)
if(nm=="count") then
tex.setcount("global",c,tex.count[c]+10)
end
end
if(tex.count[c]>=tb) then
error("No room for a new " .. nm)
end
end
end

% \insc@unt is a count register
% \float@count is a chardef token, accessed via .mode
function new_box(b)
if not token.is_defined(b) then
e_alloc("box",14,tex.count["insc@unt"],token.create("float@count").mode,b)
end
end
new_box("luaboxa")
}
\typeout{luaboxa: \number\luaboxa}

\newbox\texboxb
\typeout{texboxb: \number\texboxb}

\count14=198

% 199 256 257 with tex
%\newbox\zzz \typeout{zzz: \number\zzz}
%\newbox\zzz \typeout{zzz: \number\zzz}
%\newbox\zzz \typeout{zzz: \number\zzz}

% 199 199 199 -- better with Lua
\directlua{new_box("zzz")}\typeout{zzz: \number\zzz}
\directlua{new_box("zzz")}\typeout{zzz: \number\zzz}
\directlua{new_box("zzz")}\typeout{zzz: \number\zzz}

\begin{document}

\directlua{new_box("zzz")}\setbox\zzz=\hbox{Hello World}\copy\zzz\typeout{zzz: \number\zzz}

\directlua{new_box("zzz")}\setbox\zzz=\hbox{Foo World}\copy\zzz\typeout{zzz: \number\zzz}

\directlua{new_box("zzb")}\setbox\zzb=\hbox{Bar World}\copy\zzb\typeout{zzb: \number\zzb}

\directlua{new_box("zzz")}\setbox\zzz=\hbox{ooF World}\copy\zzz\typeout{zzz: \number\zzz}

\setbox\zzz=\hbox{Sham World}\copy\zzz\typeout{zzz: \number\zzz}
\copy\zzb\typeout{zzb: \number\zzb}

\end{document}


The terminal output is

texboxa: 45

luaboxa: 46
texboxb: 47

zzz: 199
zzz: 199
zzz: 199
zzz: 199
zzz: 199

zzb: 257
zzz: 199
zzz: 199
zzb: 257


showing how the allocation correctly jumps to the etex extended registers without over-writing the float boxes. It also shows that new box registers are not allocated for a boxname (if user tries to again create a box with same name), thus saving box register resources.

Compiled output is:

The terminal output is

texboxa: 45
luaboxa: 46
texboxb: 47


from

\documentclass{article}

\newbox\texboxa
\typeout{texboxa: \number\texboxa}

\directlua{
tex.setcount("global",14,tex.count[14]+1)
token.set_char("luaboxa",tex.count[14],"global")
}
\typeout{luaboxa: \number\luaboxa}

\newbox\texboxb
\typeout{texboxb: \number\texboxb}

\begin{document}

\end{document}


You could check that the name (\luaboxa here) is new, but the tex defined \newbox does not do that, you can use \newbox\frac or \newbox\section and break the document with no warning. It does check that you have not run out of registers, so defining it as a function with error checking to match \newbox you could have

\directlua{
function new_box(b)
if tex.count[14] > 65534 then
error("No room for a new box register")
else
tex.setcount("global",14,tex.count[14]+1)
token.set_char(b,tex.count[14],"global")
end
end
new_box("luaboxa")
}


Note this is only safe if the box allocation has already passed 255, a more complete version that avoids over-writing float boxes would need to re-implement \e@alloc in Lua, to be added shortly.....

• see for example the Lua allocators such as luatexbase.new_whatsit in ltluatex.lua in the latex base distribution. Oct 3, 2020 at 8:25
• Looking at the first two if statements in e_check_alloc, I wonder if you intended to type something different in e_check_alloc. In the current form, e_check_alloc will execute anything only if tex.count[c] == ta, so why surround it with a superset condition check tex.count[c] >= ta? As a bonus, some documentation would also help. Thanks! Oct 3, 2020 at 21:12
• @reportaman sorry got my if..end nesting messed up, fixed. The documentation is as for the tex one in ltplain.dtx (texdoc source2e pages 17-19 but I may add something here later, perhaps. Oct 3, 2020 at 21:30
• @DavidCarlisle Dave will you please update this with an example of using the functions that are now provided in source2e Jul 30, 2021 at 8:53
• @YiannisLazarides not sure I understand your comment, I don't think any new functions have been added since I wrote this? Jul 30, 2021 at 23:09