获取文件/复杂代码的整个 CAST
Getting the whole AST of the file / complex code
朱莉娅手册states:
Every Julia program starts life as a string:
julia> prog = "1 + 1"
"1 + 1"
在 quote
/ code_*
或使用 Meta.parse
/ Meta.show_sexpr
的帮助下,我可以轻松获得简单表达式的 AST,甚至是函数我在字符串中有表达式。
问题:有没有办法得到代码片段的整个 AST,可能包括几个原子表达式?比如,读取源文件并将其转换为 AST?
Julia 解析器的 FemtoLisp 实现中有 jl-parse-file
。您可以从 Lisp REPL (julia --lisp
) 调用它,它 returns 是整个文件的 S 表达式。由于 Julia 的 Expr
与 Lisp S 表达式没有太大区别,这可能足以满足您的需要。
我仍然想知道如何从 Julia 中访问此结果。如果我没理解错的话,Lisp函数是not exported from libjulia, so there's no direct way to just use a ccall
. But maybe a variant of jl_parse_eval_all
可以实现的
如果您想从 Julia 而不是 FemtoLisp 执行此操作,您可以执行
function parse_file(path::AbstractString)
code = read(path, String)
Meta.parse("begin $code end")
end
这会接收一个文件路径,读取它并将其解析为一个可以计算的大表达式。
这来自@NHDaly 的回答,在这里:
如果您的文件已经是一个字符串并且不想再次阅读它,您可以改为
parse_all(code::AbstractString) = Meta.parse("begin $code end")
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
这可以按如下方式解决:
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
由于提问者不相信上面的代码产生了一棵树,这里是parse_all
输出的图形表示,清楚地显示了树结构。
如果您好奇的话,那些标记为 #= none:1 =#
的叶子是行号节点,指示每个后续表达式发生的行。
正如评论中所建议的那样,也可以将 Meta.show_sexpr
应用于 Expr
对象以获得更多 "lispy" 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))))
)
朱莉娅手册states:
Every Julia program starts life as a string:
julia> prog = "1 + 1" "1 + 1"
在 quote
/ code_*
或使用 Meta.parse
/ Meta.show_sexpr
的帮助下,我可以轻松获得简单表达式的 AST,甚至是函数我在字符串中有表达式。
问题:有没有办法得到代码片段的整个 AST,可能包括几个原子表达式?比如,读取源文件并将其转换为 AST?
Julia 解析器的 FemtoLisp 实现中有 jl-parse-file
。您可以从 Lisp REPL (julia --lisp
) 调用它,它 returns 是整个文件的 S 表达式。由于 Julia 的 Expr
与 Lisp S 表达式没有太大区别,这可能足以满足您的需要。
我仍然想知道如何从 Julia 中访问此结果。如果我没理解错的话,Lisp函数是not exported from libjulia, so there's no direct way to just use a ccall
. But maybe a variant of jl_parse_eval_all
可以实现的
如果您想从 Julia 而不是 FemtoLisp 执行此操作,您可以执行
function parse_file(path::AbstractString)
code = read(path, String)
Meta.parse("begin $code end")
end
这会接收一个文件路径,读取它并将其解析为一个可以计算的大表达式。
这来自@NHDaly 的回答,在这里:
如果您的文件已经是一个字符串并且不想再次阅读它,您可以改为
parse_all(code::AbstractString) = Meta.parse("begin $code end")
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
这可以按如下方式解决:
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
由于提问者不相信上面的代码产生了一棵树,这里是parse_all
输出的图形表示,清楚地显示了树结构。
如果您好奇的话,那些标记为 #= none:1 =#
的叶子是行号节点,指示每个后续表达式发生的行。
正如评论中所建议的那样,也可以将 Meta.show_sexpr
应用于 Expr
对象以获得更多 "lispy" 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))))
)