【问题标题】:Lua source code manipulation: get innermost function() location for a given lineLua源代码操作:获取给定行的最内层函数()位置
【发布时间】:2013-08-30 19:37:57
【问题描述】:

我有一个语法正确的 Lua 5.1 源代码文件。

我在该文件中有一个位置(行和字符偏移)。

我需要获取包含该位置的最里面的function() 主体的右括号的字节偏移量(或确定该位置属于文件的主块)。

即:

本地函数 foo() ^ 结果 打印(“酒吧”) ^ 输入 结尾 本地 foo = 函数() ^ 结果 打印(“酒吧”) ^ 输入 结尾 本地 foo = 函数() 返回函数() ^ 结果 打印(“酒吧”) ^ 输入 结尾 结尾

...等等。

我如何稳健地做到这一点?

【问题讨论】:

  • 您可以使用哪些类型的库?你可能需要一个 Lua 解析器。
  • 无论我需要什么,只要它是理智的(并且最好不要在 GPL 下)。
  • 实际上,在这种特定情况下,我认为单独使用正则表达式应该是可行的(可能在反向源操作时)。但是基于库的解决方案会更好。
  • "我如何稳健地做到这一点?" 你编写了一个解析器。如果您想“稳健地”进行严格的源代码操作,您可以编写一个解析器。 Lua's syntax 并不复杂。因此,只需获取您最喜欢的解析工具并编写一个。
  • 嗯,有几个 Lua 解析器。 Metalua、luafish、Cheese、LuaParse、LuaInspect、Leg 等

标签: lua


【解决方案1】:

编辑:我原来的答案没有考虑到“最里面”的要求。我已经考虑到了这一点

要使事情“健壮”,有几个考虑因素。

首先,跳过字符串和注释内容很重要,以避免在以下情况下出现错误输出:

foo = function()
    print(" function() ")
    -- function()
    print("bar")
            ^ input
end

考虑到 Lua 的嵌套字符串和注释语法,这可能有点困难。例如,考虑输入以嵌套字符串或注释开头的情况:

foo = function()
    print([[
        bar = function()
            print("baz")
                    ^ input
        end
    ]])
end

因此,如果您想要一个完全健壮的系统,在到达函数参数列表的末尾之前只向后解析是不可接受的,因为您可能没有向后解析足够远的距离以达到 [[ 这将使无效你的比赛。因此,有必要将 整个 文件解析到您的位置(除非您在这些奇怪的情况下可以接受不正确的匹配。如果这是一个编辑器插件,这些“不正确”的结果实际上可能是可取的,因为它们允许您使用相同的插件编辑以字符串文字形式存储在其他 lua 代码中的 lua 代码)。

因为您尝试匹配的特定语法没有任何“嵌套”,所以不需要成熟的解析器。但是,您将需要维护一个堆栈来跟踪范围。考虑到这一点,您需要做的就是从头开始逐个字符地遍历源文件,应用以下逻辑:

  1. 每次遇到"' 时,忽略直到结束"' 的字符。小心处理像 \"\\ 这样的转义
  2. 每次遇到-- 时,忽略注释的结束换行符之前的字符。请注意,仅当注释不是多行注释时才这样做。
  3. 每次遇到多行字符串开头符号(如[[[=[等),或遇到多行注释符号(如--[[--[=[等)时忽略向上的字符直到右方括号在它们之间具有适当数量的匹配等号
  4. 遇到单词边界时,检查它后面的字符是否可以开始一个以end 结尾的块(例如,ifwhileforfunction 等。不要包括repeat)。如果是这样,则将位置推送到范围堆栈上。在这种情况下,“单词边界”是任何不能用作 lua 标识符的字符(这是为了防止在 abcfunction() 这样的情况下匹配)。文件的开头也被视为单词边界。
  5. 如果遇到单词边界并且后面跟着end,则弹出堆栈的顶部元素。如果堆栈没有元素,请报告语法错误。

当您最终向前并到达“输入”位置时,从堆栈中弹出元素,直到找到function 范围。从该位置前进到下一个),忽略cmets 中的)(如果它跨越多行或包含内联--[[ ]] cmets,理论上可以在参数列表中找到)。那个位置就是你的结果。

这应该处理所有情况,包括使用function 语法糖的情况,例如

function foo()
    print("bar")
end

你没有在你的例子中包括,但我想你仍然想匹配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多