获取文件的完整AST /复杂代码

Ale*_*kin 2 metaprogramming abstract-syntax-tree julia

朱莉娅手册指出

每个Julia程序都以字符串开头:

julia> prog = "1 + 1"
"1 + 1"
Run Code Online (Sandbox Code Playgroud)

我可以很容易地获得简单表达式的AST,甚至可以在quote/ 的帮助下获得一个函数,如果我在字符串中包含表达式code_*,则可以使用Meta.parse/ Meta.show_sexpr

问题:是否有办法获取编码的整个AST,可能包括几个原子表达式?像,读取源文件并将其转换为AST?

Mas*_*son 5

如果要使用Julia而不是FemtoLisp进行此操作,则可以执行

function parse_file(path::AbstractString)
    code = read(path, String)
    Meta.parse("begin $code end")
end
Run Code Online (Sandbox Code Playgroud)

这将采用一个文件路径,将其读取并解析为一个可以计算的大表达式。

这来自@NHDaly的答案,在这里:https ://stackoverflow.com/a/54317201/751061

如果您已经将文件作为字符串,并且不想再次读取,则可以执行

parse_all(code::AbstractString) = Meta.parse("begin $code end")
Run Code Online (Sandbox Code Playgroud)

Nathan Daly和Taine Zhao在Slack上指出,此代码不适用于模块:

julia> eval(parse_all("module M x = 1 end"))
ERROR: syntax: "module" expression not at top level
Stacktrace:
 [1] top-level scope at REPL[50]:1
 [2] eval at ./boot.jl:331 [inlined]
 [3] eval(::Expr) at ./client.jl:449
 [4] |>(::Expr, ::typeof(eval)) at ./operators.jl:823
 [5] top-level scope at REPL[50]:1
Run Code Online (Sandbox Code Playgroud)

可以将其固定如下:

julia> eval_all(ex::Expr) = ex.head == :block ? for e in ex eval_all(e) end : eval(e);

julia> eval_all(ex::Expr) = ex.head == :block ? eval.(ex.args) : eval(e);

julia> eval_all(parse_all("module M x = 1 end"));

julia> M.x
1
Run Code Online (Sandbox Code Playgroud)

由于提问者不相信上面的代码会产生一棵树,因此这是的输出的图形表示形式parse_all,清楚地显示了树结构。

在此处输入图片说明

如果您感到好奇,则标记的那些叶子#= none:1 =#是行号节点,指示每个后面的表达式所在的行。

正如评论中所建议的,默认情况下,也可以Meta.show_sexpr将一个Expr对象应用于一个对象,以获取AST的更多“轻快”表示,而无需执行所有漂亮的打印julia操作:

julia> (Meta.show_sexpr ? Meta.parse)("begin x = 1\n y = 2\n z = ?(x^2 + y^2)\n end")
(:block,
  :(#= none:1 =#),
  (:(=), :x, 1),
  :(#= none:2 =#),
  (:(=), :y, 2),
  :(#= none:3 =#),
  (:(=), :z, (:call, :?, (:call, :+, (:call, :^, :x, 2), (:call, :^, :y, 2))))
)
Run Code Online (Sandbox Code Playgroud)

  • 这种结构不是树吗? (2认同)