Skip to content

Conversation

@mlechu
Copy link
Member

@mlechu mlechu commented Nov 21, 2025

I'm assuming this macro (which is defined as "go find the file or REPL history
entry this Expr came from and re-parse the text to SyntaxTree") is mostly
for convenience in interactive environments. It's also breakable at
precompile time with changes in the way we expand quote, and it takes a
noticable amount of time in inference. This change just uses the
less-convenient @ast form like the rest of the project.

I'm assuming this macro (which is defined as "go find the file or REPL history
     entry this Expr came from and re-parse the text to SyntaxTree") is mostly
     for convenience in interactive environments.  It's also breakable at
     precompile time with changes in the way we expand `quote`, and it takes a
     noticable amount of time in inference.  This change just uses the
     less-convenient `@ast` form like the rest of the project.
@mlechu mlechu requested a review from c42f November 21, 2025 18:57
@mlechu mlechu added the compiler:lowering Syntax lowering (compiler front end, 2nd stage) label Nov 21, 2025
Copy link
Member

@topolarity topolarity left a comment

Choose a reason for hiding this comment

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

It's also breakable at precompile time with changes in the way we expand quote

Can you elaborate?

This change just uses the less-convenient @ast form like the rest of the project.

The @ast form is probably fine for now, but it's worth mentioning that having proper non-hacky SyntaxTree quoting is probably required for "new style" macros eventually. The current implementation (

macro SyntaxTree(ex_old)
# The implementation here is hilarious and arguably very janky: we
# 1. Briefly check but throw away the Expr-AST
if !(Meta.isexpr(ex_old, :quote) || ex_old isa QuoteNode)
throw(ArgumentError("@SyntaxTree expects a `quote` block or `:`-quoted expression"))
end
# 2. Re-parse the current source file as SyntaxTree instead
fname = isnothing(__source__.file) ? error("No current file") : String(__source__.file)
if occursin(r"REPL\[\d+\]", fname)
# Assume we should look at last history entry in REPL
try
# Wow digging in like this is an awful hack but `@SyntaxTree` is
# already a hack so let's go for it I guess 😆
text = Base.active_repl.mistate.interface.modes[1].hist.history[end]
if !occursin("@SyntaxTree", text)
error("Text not found in last REPL history line")
end
catch
error("Text not found in REPL history")
end
else
text = read(fname, String)
end
full_ex = parseall(SyntaxTree, text)
# 3. Using the current file and line number, dig into the re-parsed tree and
# discover the piece of AST which should be returned.
ex = _find_SyntaxTree_macro(full_ex, __source__.line)
isnothing(ex) && error("_find_SyntaxTree_macro failed")
# 4. Do the first step of JuliaLowering's syntax lowering to get
# syntax interpolations to work
_, ex1 = expand_forms_1(__module__, ex, false, Base.tls_world_age())
@assert kind(ex1) == K"call" && ex1[1].value == interpolate_ast
Expr(:call, :interpolate_ast, SyntaxTree, ex1[3][1],
map(e->_scope_layer_1_to_esc!(Expr(e)), ex1[4:end])...)
end
) seems too hacky to rely on as-is though, I agree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler:lowering Syntax lowering (compiler front end, 2nd stage)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants