1

假设我正在使用使用 luarocks 安装的 lua 库,并且我想查看该库中函数的定义。在 ipython 中可以使用

??function_name

在终端中查看定义,在matlab中我可以使用

哪个函数名

然后使用我的编辑器查看返回的路径。我怎么能做类似的事情来找到 lua 库的函数定义?

4

1 回答 1

3

在'plain' Lua/JIT 中,你可以说并且会得到一个包含(以及其他)字段的表,和。debug.getinfo( func )short_srcsourcelinedefined

对于 Lua 函数,short_src将是文件名,或者stdin如果它是在 REPL 中定义的。(source格式略有不同,文件名以 为前缀@=前缀用于 C 函数或交互定义的内容,对于loaded 函数,它将是加载的实际字符串。)

你可以把它打包成一个函数,比如

function sourceof( f )
    local info = debug.getinfo( f, "S" )
    return info.short_src, info.linedefined
end

或者甚至可以启动一个编辑器并将其指向那里,例如(对于 vim)

function viewsource( f )
    -- get info & check it's actually from a file
    local info = debug.getinfo( f, "S" )
    local src, line = info.source, info.linedefined
    if src == "=[C]"   then  return nil, "Is a C function."  end
    local path = src:match "^@(.*)$"
    if path then
        -- start vim (or an other editor if you adapt the format string)
        return os.execute( ("vim -fR %q +%d"):format( path, line ) )
    end
    return nil, "Was defined at run time."
end

只是为了好玩,这里还有另一个版本,如果它可以在某个地方找到它,它会返回代码。(这也适用于在运行时生成的函数,例如通过调用load,并且不存在源文件。您也可以通过将loaded 片段转储到临时文件并打开它来朝另一个方向工作……)

-- helper to extract the source block defining the function
local function funclines( str, line1, lineN, filename )
    -- if linedefined / lastlinedefined are 0, this is the main chunk's function
    if line1 == 0 and lineN == 0 then
        filename = filename and filename.." (main chunk)"
                             or "(chunk defined at runtime)"
        return "-- "..filename.."\n"..str
    end
    -- add line info to file name or use placeholder
    filename = filename and filename..":"..line1 or "(defined at runtime)"
    -- get the source block
    local phase, skip, grab = 1, line1-1, lineN-(line1-1)
    local ostart, oend -- these will be the start/end offsets
    if skip == 0 then  phase, ostart = 2, 0  end -- starts at first line
    for pos in str:gmatch "\n()" do
        if phase == 1 then -- find offset of linedefined
            skip = skip - 1 ; if skip == 0 then  ostart, phase = pos, 2  end 
        else -- phase == 2, find offset of lastlinedefined+1
            grab = grab - 1 ; if grab == 0 then  oend = pos-2 ; break  end
        end
    end
    return "-- "..filename.."\n"..str:sub( ostart, oend )
end

function dumpsource( f )
    -- get info & line numbers
    local info = debug.getinfo( f, "S" )
    local src, line, lastline = info.source, info.linedefined, info.lastlinedefined
    -- can't do anything for a C function
    if src == "=[C]" then  return nil, "Is a C function."  end
    if src == "=stdin" then  return nil, "Was defined interactively."  end
    -- for files, fetch the definition
    local path = src:match "^@(.*)$"
    if path then
        local f = io.open( path )
        local code = f:read '*a' 
        f:close( )
        return funclines( code, line, lastline, path )
    end
    -- otherwise `load`ed, so `source`/`src` _is_ the source
    return funclines( src, line, lastline )
end

结束语:如果将代码粘贴到 Lua/JIT REPL 中,local则 s 在定义之间消失,因为每一行(或最小的完整行组)都是它自己的块。do常见的解决方法(您可能知道)是将所有内容作为*paste*包装到一个块中end,但另一种方法是load[[*paste* ]]()(可能带有更多=的 s like[===[]===]。)如果您以这种方式粘贴,则上述dumpsource(或任何其他使用debug.getinfo) 的函数将能够获得函数的来源。这也意味着如果你定义了一个不错的函数,但它从历史记录和滚动缓冲区中消失了,你可以通过这种方式恢复它(如果你定义它loading 而不是直接喂给口译员)。然后,无需复制粘贴也可以将源保存在文件中,并且不需要编辑>>提示。

于 2015-04-26T00:35:43.063 回答