
Considerar
\documentclass[12pt]{article}
\usepackage{luacode}
%\usepackage{luacr}
%\usepackage{miscellaneous}
\begin{document}
\global\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
if i<30 then
i=i+1
tex.sprint(i .. [[, \F]])
end
end
\end{luacode*}
\F
\end{document}
Problema:
TeX capacity exceeded, sorry [text input levels=15].
Pelo que posso ver tex.sprint
é "equivalente" a um \input
que contém o conteúdo impresso, podendo ter \input
15 níveis no máximo.
Pergunta:
- por que oeliminação de recursão de caudanão funciona quando a entrada é de uma linha em vez de uma lista de tokens?
- como corrigir o problema? Supondo que eu precise
tex.sprint()
, por exemplo, imprimir mais algum conteúdo de string à direita de\F
.
enquanto isso encontro uma solução alternativa usando token.put_next()
, coloco um \relax e pego depois.
Responder1
Você pode forçar o tex a desenrolar a pilha de entrada antes de recorrer, olhando para frente com\expandafter
\documentclass[12pt]{article}
%\usepackage{luacr}
%\usepackage{miscellaneous}
\begin{document}
\def\F{\expanded{\noexpand\directlua{f()}\expandafter}}
\directlua{
i=0
function f()
if i<30 then
i=i+1
tex.sprint(i .. [[, \string\F]])
end
end
}
\F
\end{document}
Responder2
0.texio.closeinput()
Sugerido porum comentário
Código:
%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
\begin{document}
\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
if i~=0 then
texio.closeinput()
end
if i<20000 then
i=i+1
tex.sprint(i .. [[, \F]])
end
end
\end{luacode*}
\F
\end{document}
O manual explica...
Esta função deve ser usada com cuidado. Ele atua como \endinput mas no final de Lua. Você pode usá-lo para (mais ou menos) forçar um salto de volta para o TeX.
o que significa que ele elimina o conteúdo restante do "arquivo" superior.
Nota/esclarecimento do manual,
- isso não acontecerealmentevolte para o TeX, o seguinte conteúdo Lua ainda é executado
tex.print()
comandos anteriores também são descartados- ao contrário
\endinput
do seguinte conteúdo na linha é descartado - masse houver alguns tokens pendentes colocados,
token.put_next()
eles serão mantidos enquanto aqueles depois dele - aplica-se apenas ao "arquivo"/pseudoarquivo real em vez de, por exemplo, lista de tokens de argumento
1. Use token.put_next no token de continuação
%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
\begin{document}
\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
if i<20000 then
i=i+1
tex.sprint(i .. [[, ]])
token.put_next(token.create("F"))
end
end
\end{luacode*}
\F
\end{document}
(experimentalmente, token.put_next()
afinal tudo vem tex.*print()
, independente da ordem no código)
Eu acho que a razão pela qual esse método funciona é que ao expandir uma macro, ao contrário de quando token.get_next()
ou token.scan_toks()
etc. é executado, o TeX desenrola a pilha de entrada (mesmo no caso de a macro não ter nenhum argumento como neste caso)
2. Use futurelet
%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
%\usepackage{miscellaneous}
%\tracingmacros=1
\begin{document}
\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
if i<20000 then
i=i+1
tex.sprint(i .. [[, \immediateassignment\futurelet\a\F]])
end
end
\end{luacode*}
\expanded{\F}
\end{document}
\immediateassignment
usado para fazê-lo funcionar em contexto somente de expansão.
Observe que se o token a seguir for um notexpanded
token, ele será alterado.
3. (funciona apenas parcialmente, não use) Use token.put_next em outro token e get_next de dentro de Lua
%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
%\usepackage{miscellaneous}
%\tracingmacros=1
\begin{document}
\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
token.get_next() -- the relax token, either the original one or result of put_next
if i<3000 then
i=i+1
tex.sprint(i .. [[, \F]])
token.put_next(token.create("relax"))
end
end
\end{luacode*}
\F\relax
\end{document}
Isso não faz a recursividade final adequada (de alguma forma, token.get_next()
não elimina o nível de entrada se estiver esgotado); portanto, se 3000 for aumentado para um valor maior, você verá
TeX capacity exceeded, sorry [input stack size=5000].