Julia的宏能否访问嵌套函数?

3

我正在尝试使用Julia的宏。我特别感兴趣的一件事是,能够在不完全编译代码的情况下提取函数的可达调用图。所谓“可达调用图”,是指在一个函数体内找到的所有潜在可到达的函数,以及这些函数中的函数,依此类推。

例如:

do_something(x::Int) = println(x*2)
do_something(x::String) = println(x)

function foo(a, b)::Bool
    do_something_with(a)
    do_something_with(b)
    return true
end

# Ideally something like this would be accessible from Base
functions_in_codebase = [:do_something, :foo]

# Not correct, but gets the idea across
macro access_call_graph(f)
    tokens = f.text.tokens
    graph = [f]
    for t in tokens
        go_deeper = t in functions_in_codebase
        !go_deeper && append!(graph, access_call_graph(get_function_for(t))...)
    end
    return graph
end

access_call_graph(foo)
# Should get something like the following, nesting notwithstanding:
# foo
# do_something, do_something

这个方法有些不够完善,但是能够在解析时访问调用图谱,即使只是潜在可访问的函数,对于我想要做的事情非常有用。如果我必须完全编译代码才能使这种方法起作用,那将会大大削弱其效益。

这种方法是否可行?


2
到目前为止,你写的方式行不通。首先,宏不是函数,它们的调用看起来像 @access_call_graph(foo)。另外,宏只在解析时看到表达式,所以该调用只看到符号:foo,而不是函数。:foo 肯定不会有 .text.tokens 字段。你编写的 access_call_graph 的方式更像是运行时操作的函数。这让我想起了函数 code_warntype。宏 @code_warntype 更为人所知,但这个宏所做的就是将一个表达式处理成调用函数版本的表达式。 - BatWannaBe
1个回答

3

@code_lowered 可以很有用:

julia> code = @code_lowered foo(1,"2")
CodeInfo(
1 ─ %1 = Main.Bool
│        Main.do_something_with(a)
│        Main.do_something_with(b)
│   %4 = Base.convert(%1, true)
│   %5 = Core.typeassert(%4, %1)
└──      return %5
)

为了获取函数调用,你可以这样做:
julia> code.first.code
5-element Vector{Any}:
 :(Main.do_something_with)
 :((%1)(_2))
 :(Main.do_something_with)
 :((%3)(_3))
 :(return true)

3
结合上面@BatWannaBe的评论,这基本上是正确的答案,但情况很快就会变得复杂,因为你需要为每个方法而不是函数进行递归。我将指向我的软件包IRTracker.jl,它不再维护,但几乎可以实现OP想要的功能,并可作为使用IRTools.jl编写类似功能的示例。我建议您以后者为起点。 - phipsgabler
2
@phipsgabler 只是在扩展你的第一句话,OP需要对每个方法进行递归,而不仅仅是函数,因为同一函数的不同方法可以调用不同的嵌套函数。对于 @access_call_graph f(y) 的调用图将根据 y 的类型而异:f(x::Int) = g(x) vs f(x::Float64) = h(x)。因此,虽然 OP 可能不想要完整的编译,但 OP 需要类型推断部分来查找嵌套方法。我想一个适用于 函数 @access_call_graphs f 的版本可以迭代所有现有的方法 Base.methods(f) - BatWannaBe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接