summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3luatex.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3luatex.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3luatex.dtx128
1 files changed, 122 insertions, 6 deletions
diff --git a/macros/latex/contrib/l3kernel/l3luatex.dtx b/macros/latex/contrib/l3kernel/l3luatex.dtx
index ac63d0f89a..918f36c3ac 100644
--- a/macros/latex/contrib/l3kernel/l3luatex.dtx
+++ b/macros/latex/contrib/l3kernel/l3luatex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2021-11-12}
+% \date{Released 2021-11-22}
%
% \maketitle
%
@@ -370,9 +370,47 @@ local scan_int = token.scan_int or token.scan_integer
local scan_string = token.scan_string
local scan_keyword = token.scan_keyword
local put_next = token.put_next
+local token_create = token.create
+% \end{macrocode}
+%
+% Since token.create only returns useful values after the tokens
+% has been added to TeX's hash table, we define a variant which
+% defines it first if necessary.
+% \begin{macrocode}
+local token_create_safe
+do
+ local is_defined = token.is_defined
+ local set_char = token.set_char
+ local runtoks = tex.runtoks
+ local let_token = token_create'let'
-local true_tok = token.create'prg_return_true:'
-local false_tok = token.create'prg_return_false:'
+ function token_create_safe(s)
+ local orig_token = token_create(s)
+ if is_defined(s, true) then
+ return orig_token
+ end
+ set_char(s, 0)
+ local new_token = token_create(s)
+ runtoks(function()
+ put_next(let_token, new_token, orig_token)
+ end)
+ return new_token
+ end
+end
+
+local true_tok = token_create_safe'prg_return_true:'
+local false_tok = token_create_safe'prg_return_false:'
+% \end{macrocode}
+% In Con\TeX{}t lmtx \texttt{token.command_id} does not exist,
+% but it can easily be emulated with Con\TeX{}t's \texttt{tokens.commands}.
+% \begin{macrocode}
+local command_id = token.command_id
+if not command_id and tokens and tokens.commands then
+ local id_map = tokens.commands
+ function command_id(name)
+ return id_map[name]
+ end
+end
% \end{macrocode}
%
% \begin{macrocode}
@@ -642,9 +680,8 @@ end)
% a function instead of an index into the functions table.
% \begin{macrocode}
local luacmd do
- local token_create = token.create
local set_lua = token.set_lua
- local undefined_cs = token.command_id'undefined_cs'
+ local undefined_cs = command_id'undefined_cs'
if not context and not luatexbase then require'ltluatex' end
if luatexbase then
@@ -665,7 +702,7 @@ local luacmd do
local register = context.functions.register
local functions = context.functions.known
function luacmd(name, func, ...)
- local tok = token.create(name)
+ local tok = token_create(name)
if tok.command == undefined_cs then
token.set_lua(name, register(func), ...)
else
@@ -677,6 +714,85 @@ end
% \end{macrocode}
% \end{macro}
%
+% \subsection{Preserving iniTeX Lua data for runs}
+%
+% \begin{macrocode}
+%<@@=lua>
+% \end{macrocode}
+%
+% The Lua state is not dumped when a forat is written, therefore any Lua
+% variables filled doing format building need to be restored in order to
+% be accessible during normal runs.
+%
+% We provide some kernel-internal helpers for this. They will only be available if
+% \texttt{luatexbase} is available. This is not a big restriction though, because
+% Con\TeX{}t (which does not use \texttt{luatexbase}) does not load \pkg{expl3}
+% in the format.
+%
+% \begin{macrocode}
+local register_luadata, get_luadata
+
+if luatexbase then
+ local register = token_create'@expl@luadata@bytecode'.index
+ if status.ini_version then
+% \end{macrocode}
+%
+% \begin{macro}{register_luadata}
+% \texttt{register_luadata} is only available during format generation.
+% It accept a string which uniquely identifies the data object and has to be
+% provided to retrieve it later. Additionally it accepts a function which is
+% called in the \texttt{pre_dump} callback and which has to return a string that
+% evaluates to a valid Lua object to be preserved.
+% \begin{macrocode}
+ local luadata, luadata_order = {}, {}
+
+ function register_luadata(name, func)
+ if luadata[name] then
+ error(format("LaTeX error: data name %q already in use", name))
+ end
+ luadata[name] = func
+ luadata_order[#luadata_order + 1] = func and name
+ end
+% \end{macrocode}
+% \end{macro}
+%
+% The actual work is done in \texttt{pre_dump}. The \texttt{luadata_order} is used
+% to ensure that the order is consistent over multiple runs.
+% \begin{macrocode}
+ luatexbase.add_to_callback("pre_dump", function()
+ if next(luadata) then
+ local str = "return {"
+ for i=1, #luadata_order do
+ local name = luadata_order[i]
+ str = format('%s[%q]=%s,', str, name, luadata[name]())
+ end
+ lua.bytecode[register] = assert(load(str .. "}"))
+ end
+ end, "ltx.luadata")
+ else
+% \end{macrocode}
+%
+% \begin{macro}{get_luadata}
+% \texttt{get_luadata} is only available if data should be restored.
+% It accept the identifier which was used when the data object was registered and
+% returns the associated object. Every object can only be retrieved once.
+% \begin{macrocode}
+ local luadata = lua.bytecode[register]
+ if luadata then
+ lua.bytecode[register] = nil
+ luadata = luadata()
+ end
+ function get_luadata(name)
+ if not luadata then return end
+ local data = luadata[name]
+ luadata[name] = nil
+ return data
+ end
+ end
+end
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macrocode}
%</lua>
% \end{macrocode}