覆盖全局 Lua 变量“尝试索引 NN 值”

覆盖全局 Lua 变量“尝试索引 NN 值”

我有一个 Lua 文件(太旧了,记不清我到底做了什么),其中包含以下行:

local arg_cnt = debug.getinfo(formatter).nparams

这会触发错误信息

attempt to index a boolean value (global 'debug')

debug是一个具有内省功能的 Lua 表,我显然想使用它,而且它在我一两年前编写代码时就必须能够正常工作。

我如何确定为什么它不再起作用?

在这种情况中,我最初的怀疑是它debug在某些时候被覆盖,但是所有的搜索和查找都无法指向可能发生这种情况的地方。

是否有可能核心发生了变化,所以我必须明确启用表格debug?我在当前 Ubuntu 版本的存储库版本上

lualatex --version
This is LuaHBTeX, Version 1.12.0 (TeX Live 2020/Debian)

答案1

当试图找出谁负责更改 Lua 中的全局变量时,临时将元表分配给全局表有时很有用。(我强烈建议不要在调试之外这样做,并让元表尽可能接近普通表,否则您会得到各种奇怪的行为。)

因此,为了debug通过元方法检测全局变量的更改,您必须删除该debug表。实际上,您可以通过元方法将其放回原处__index。然后,您可以使用__newindex来检测尝试创建一个新的全局变量,debug在这种情况下,您可以打印警告,使用原始调试表来获取有关负责的 Lua 函数的信息。如果它被重置,那么在 中就没什么用了\directlua,但您可以使用 LuaTeX 的状态表来额外提供当前的 TeX 文件和行。

您必须在加载任何可能负责的内容之前执行此操作,最好将其放在之前\documentclass

\directlua{
  local debug = debug
  local traceback, getinfo = debug.traceback, debug.getinfo
  _G.debug = nil
  setmetatable(_G, {
    __index = {debug = debug},
    __newindex = function(t, k, v)
      if k == "debug" then
        local guilty = getinfo(2)
        texio.write_nl("We found the naughty party: " .. (guilty.name or "nameless devil") .. " in " .. guilty.source .. " at line " .. guilty.currentline)
        texio.write_nl("TeX is currently reading " .. status.filename .. " at line " .. status.linenumber)
      end
      return rawset(t, k, v)
    end,
  })
}
\documentclass{article}
\usepackage{grandmother}
\begin{document}
\end{document}

例如,这将提供输出

...
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size10.clo))
(./grandmother.sty
We found the naughty party: rose_tylor in @./bad_wolf.lua at line 2
TeX is currently reading ./grandmother.sty at line 4)
(/usr/local/texlive/2020/texmf-dist/tex/latex/l3backend/l3backend-luatex.def)
...

表示rose_tylor文件中的某个函数./bad_wolf.lua正在发生变化debug,变化发生在文件的第 2 行,并在第 4 行加载grandmother.sty

答案2

这不是问题的具体答案,但无论如何我都想写一个通用答案。

attempt to index a boolean value (global 'debug')

是一个 Lua 错误消息,它告诉您正在尝试使用 Lua 表的成员,但是您视为表的表不再是表。

getinfo()就我而言,我尝试从表中调用该函数debug(该表内置于 Lua 中并且应该可以在任何地方使用),但是当调用它时,Lua 发现了一个布尔值(truefalse)。

这个观察结果很可能表明内置表debug在某个时候已被布尔值覆盖,要么在你的序言中,要么作为一个错误在包中。

为了找到罪魁祸首,插入

\directlua{print(debug)}
\directlua{debug.go}

在你的序言中此评论第一行将打印表地址 - 只要还有表格 - 第二行将导致错误并停止编译。您可以遍历序言的每一步,以准确找到问题的根源。

潜在问题

这个问题的原因是典型的 Lua 编程错误,在本例中是在一个包中。为了创建状态标志,包中包含了以下行

debug = false

debug将变量设置false为其默认值,然后在输出调试信息的函数中使用该默认值。

问题在于,Lua 中的变量默认位于全局命名空间中(与 Python 的行为相反) - 这意味着上面的行会覆盖全局变量并有效地“杀死”整个内置 Lua 表。

这是一个很好的例子,永远不要忘记在 Lua 中尽可能使用局部变量:

local debug = false

这种方式debug只适用于当前模块,并且不是影响同名的全局表。

相关内容