Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/JuliaLowering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ _include("syntax_macros.jl")

_include("eval.jl")
_include("compat.jl")
_include("hooks.jl")

function __init__()
_register_kinds()
Expand Down
51 changes: 51 additions & 0 deletions src/hooks.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Becomes `Core._lower()` upon activating JuliaLowering.

Returns an svec with the lowered code (usually expr) as its first element, and
(until integration is less experimental) whatever we want after it
"""
function core_lowering_hook(@nospecialize(code), mod::Module,
file="none", line=0, world=typemax(Csize_t), warn=false)
if !(code isa SyntaxTree || code isa Expr)
# e.g. LineNumberNode, integer...
return Core.svec(code)
end

# TODO: fix in base
file = file isa Ptr{UInt8} ? unsafe_string(file) : file
line = !(line isa Int64) ? Int64(line) : line

st0 = code isa Expr ? expr_to_syntaxtree(code, LineNumberNode(line, file)) : code
try
ctx1, st1 = expand_forms_1( mod, st0)
ctx2, st2 = expand_forms_2( ctx1, st1)
ctx3, st3 = resolve_scopes( ctx2, st2)
ctx4, st4 = convert_closures(ctx3, st3)
ctx5, st5 = linearize_ir( ctx4, st4)
ex = to_lowered_expr(mod, st5)
return Core.svec(ex, st5, ctx5)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so I see that in JuliaLang/julia#58207 you allowed for the trailing elements of this to be anything and we'll specify it later (seems reasonable). Are st5 and ctx5 used by JETLS somehow? (I see they're not used by the C code as expected ... who knows what the ctx5 API even is 😅 )

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used by JETLS yet, and even if it was, you're free to "break" this non-API. JETLS does use ctx objects outside of Core._lower, though, I think mostly for the binding table.

I see they're not used by the C code as expected

The C code unfortunately has no idea what a SyntaxTree is yet. I ran into this when trying to make Core._parse produce a syntax tree---toplevel.c had no way to positively check the thing it parsed was a SyntaxTree, and I had to smuggle it through by wrapping it in Expr in the parse hook, which is pretty goofy.

catch exc
@error("JuliaLowering failed — falling back to flisp!",
exception=(exc,catch_backtrace()),
code=code, file=file, line=line, mod=mod)
return Base.fl_lower(code, mod, file, line, world, warn)
end
end

# TODO: Write a parser hook here. The input to `core_lowering_hook` should
# eventually be a (convertible to) SyntaxTree, but we need to make updates to
# the parsing API to include a parameter for AST type.

const _has_v1_13_hooks = isdefined(Core, :_lower)

function activate!(enable=true)
if !_has_v1_13_hooks
error("Cannot use JuliaLowering without `Core._lower` binding or in $VERSION < 1.13")
end

if enable
Core._setlowerer!(core_lowering_hook)
else
Core._setlowerer!(Base.fl_lower)
end
end
38 changes: 38 additions & 0 deletions test/hooks.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const JL = JuliaLowering

@testset "hooks" begin
test_mod = Module()

@testset "`core_lowering_hook`" begin
# Non-AST types are often sent through lowering
stuff = Any[LineNumberNode(1), 123, 123.123, true, "foo", test_mod]
for s in stuff
@test JL.core_lowering_hook(s, test_mod) == Core.svec(s)
end

for ast_type in (Expr, JL.SyntaxTree)
ex = parsestmt(ast_type, "[1,2,3] .+= 1")
out = JL.core_lowering_hook(ex, test_mod)
@test out isa Core.SimpleVector && out[1] isa Expr
val = Core.eval(test_mod, out[1])
@test val == [2,3,4]
end
end

@testset "integration: `JuliaLowering.activate!`" begin
prog = parseall(Expr, "global asdf = 1")
JL.activate!()
out = Core.eval(test_mod, prog)
JL.activate!(false)
@test out === 1
@test isdefined(test_mod, :asdf)

prog = parseall(Expr, "module M; x = 1; end")
JL.activate!()
out = Core.eval(test_mod, prog)
JL.activate!(false)
@test out isa Module
@test isdefined(test_mod, :M)
@test isdefined(test_mod.M, :x)
end
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ include("utils.jl")
include("scopes.jl")
include("typedefs.jl")
include("compat.jl")
include("hooks.jl")
end
Loading