Lua源代码操作:获取给定行的最内层函数()位置

Lua源代码操作:获取给定行的最内层函数()位置,lua,Lua,我有一个语法正确的Lua5.1源代码文件 我在该文件中有一个位置(行和字符偏移) 我需要获取包含该位置的最里面的函数()主体的右括号的偏移量(以字节为单位)(或者找出该位置属于文件的主块) 即: 局部函数foo() ^结果 打印(“条”) ^输入 结束 本地foo=函数() ^结果 打印(“条”) ^输入 结束 本地foo=函数() 返回函数() ^结果 打印(“条”) ^输入 结束 结束 ……等等 我怎样才能有力地做到这一点呢?编辑:我最初的回答没有考虑到“最里面的”要求。我已经考虑到了这一点

我有一个语法正确的Lua5.1源代码文件

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

我需要获取包含该位置的最里面的
函数()
主体的右括号的偏移量(以字节为单位)(或者找出该位置属于文件的主块)

即:

局部函数foo() ^结果 打印(“条”) ^输入 结束 本地foo=函数() ^结果 打印(“条”) ^输入 结束 本地foo=函数() 返回函数() ^结果 打印(“条”) ^输入 结束 结束 ……等等


我怎样才能有力地做到这一点呢?

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

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

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

foo = function()
    print(" function() ")
    -- function()
    print("bar")
            ^ input
end
考虑到Lua的嵌套字符串和注释语法,这可能有点困难。例如,考虑输入以嵌套字符串或注释开始的情况:

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

由于您试图匹配的特定语法没有任何类型的“嵌套”,因此不需要一个完整的解析器。但是,您需要维护一个堆栈来跟踪作用域。考虑到这一点,您只需从一开始就逐个字符地对源文件进行检查,应用以下逻辑:

  • 每次遇到
    时,忽略直到结束
    为止的字符。小心处理像
    \“
    \
    这样的转义
  • 每次遇到
    --
    时,请忽略注释结束换行符之前的字符。请注意,仅当注释不是多行注释时才这样做
  • 每次遇到多行字符串开头符号(如
    [[
    [=[
    等)或多行注释符号(如
    -[[
    -[=[
    等)时,忽略这些字符,直到最后的方括号中有适当数量的匹配等号为止
  • 当遇到单词边界时,检查其后面的字符是否可以开始一个以
    结尾的块(例如,
    if
    while
    for
    function
    ,等等)。如果是这样,推动作用域堆栈上的位置。单词边界“在这种情况下,是不能用作lua标识符的任何字符(这是为了防止在类似
    abcfunction()
    )的情况下进行匹配)。文件的开头也被视为单词边界
  • 如果遇到单词边界,然后是
    end
    ,则弹出堆栈的顶部元素。如果堆栈没有元素,则抱怨语法错误
  • 当您最终向前一步并到达“输入”位置时,从堆栈中弹出元素,直到找到
    函数
    作用域。从该位置向前一步到下一个
    ,忽略注释中的
    (理论上可以在参数列表中找到,如果它跨越多行或包含内联
    --[]]
    comments)。这个职位就是你的结果

    这应该可以处理每种情况,包括使用
    函数
    语法糖的情况,例如

    function foo()
        print("bar")
    end
    

    您的示例中没有包含但我想您仍然希望匹配的库。

    您可以使用什么样的库来实现这一点?您可能需要一个Lua解析器。无论我需要什么,只要它是正常的(最好不在GPL下)。实际上,在这种特定情况下,我认为仅使用regexps就可以实现(可能是在反向源代码上操作时)。但基于库的解决方案更可取。“我如何稳健地做到这一点?”您可以编写解析器。如果您想“稳健地”进行认真的源代码操作,你可以编写一个解析器。并不复杂。所以,只需获取你最喜欢的解析工具并编写一个。好吧,有几种Lua解析器。Metalua、luafish、Cheese、luapase、LuaInspect、Leg等等。
    foo = function()
        print(" function() ")
        -- function()
        print("bar")
                ^ input
    end
    
    foo = function()
        print([[
            bar = function()
                print("baz")
                        ^ input
            end
        ]])
    end
    
    function foo()
        print("bar")
    end