Skip to content

Commit 81af71e

Browse files
committed
Tweaks for macros
1 parent e8dcfc7 commit 81af71e

File tree

2 files changed

+64
-22
lines changed

2 files changed

+64
-22
lines changed

src/compat.jl

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ the last seen LineNumberNode in the pre-order expr traversal).
1717
Last-resort option so that, for example, we can lower the output of old
1818
Expr-producing macros. Always prefer re-parsing source text over using this.
1919
20-
Does not support lowered exprs.
20+
Supports parsed and/or macro-expanded exprs, but not lowered exprs
2121
"""
2222
function expr_to_syntaxtree(@nospecialize(e), lnn::Union{LineNumberNode, Nothing}=nothing)
2323
graph = SyntaxGraph()
@@ -154,11 +154,11 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
154154
return (st_id, src)
155155
elseif e isa LineNumberNode
156156
return (nothing, e)
157-
elseif e isa QuoteNode
158-
st_id = _insert_tree_node(graph, K"quote", src)
159-
quote_child, _ = _insert_convert_expr(e.value, graph, src)
160-
setchildren!(graph, st_id, NodeId[quote_child])
161-
return (st_id, src)
157+
# elseif e isa QuoteNode
158+
# st_id = _insert_tree_node(graph, K"quote", src)
159+
# quote_child, _ = _insert_convert_expr(e.value, graph, src)
160+
# setchildren!(graph, st_id, NodeId[quote_child])
161+
# return (st_id, src)
162162
elseif e isa String
163163
st_id = _insert_tree_node(graph, K"string", src)
164164
id_inner = _insert_tree_node(graph, K"String", src)
@@ -211,9 +211,11 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
211211
end
212212
end
213213
elseif e.head === :macrocall
214-
@assert nargs >= 1
214+
@assert nargs >= 2
215215
a1 = e.args[1]
216-
child_exprs = collect_expr_parameters(e, 2)
216+
child_exprs = collect_expr_parameters(e, 3)
217+
# macrocall has a linenode "argument" here. should we set src?
218+
deleteat!(child_exprs, 2)
217219
if a1 isa Symbol
218220
child_exprs[1] = Expr(:MacroName, a1)
219221
elseif a1 isa Expr && a1.head === :(.) && a1.args[2] isa QuoteNode
@@ -227,12 +229,20 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
227229
elseif a1.name === Symbol("@int128_str")
228230
elseif a1.name === Symbol("@big_str")
229231
end
232+
elseif a1 isa Function
230233
else
231-
dump(e)
232-
error("Unknown macrocall form $e")
234+
error("Unknown macrocall form $(sprint(dump, e))")
233235
end
234236

235237
# TODO node->expr handles do blocks here?
238+
elseif e.head === :escape || e.head === Symbol("hygienic-scope")
239+
@assert nargs >= 1
240+
# Existing behaviour appears to just ignore any extra args
241+
return _insert_convert_expr(e.args[1], graph, src)
242+
elseif e.head === :meta
243+
@assert nargs <= 2
244+
@assert e.args[1] isa Symbol
245+
child_exprs[1] = Expr(:sym_not_identifier, e.args[1])
236246
elseif e.head === Symbol("'")
237247
@assert nargs === 1
238248
st_k = K"call"
@@ -359,13 +369,18 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
359369
st_id = _insert_tree_node(graph, K"Placeholder", src, st_flags)
360370
setattr!(graph, st_id, name_val="")
361371
return (st_id, src)
372+
elseif e.head === :sym_not_identifier
373+
estr = String(e.args[1])
374+
st_k = K"Symbol"
375+
st_id = _insert_tree_node(graph, st_k, src)
376+
setattr!(graph, st_id, name_val=estr)
377+
return (st_id, src)
362378
elseif e.head === :do_lambda
363379
st_k = K"do"
364380
end
365381

366382
if st_k === K"None"
367-
dump(e)
368-
error("no kind for $(e.head)")
383+
error("no kind for expr head `$(e.head)`\n$(sprint(dump, e))")
369384
end
370385

371386
st_flags |= JS.NON_TERMINAL_FLAG

src/macro_expansion.jl

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ function Base.showerror(io::IO, exc::MacroExpansionError)
110110
pos == :begin ? (fb:fb-1) :
111111
pos == :end ? (lb+1:lb) :
112112
error("Unknown position $pos")
113-
highlight(io, src.file, byterange, note=exc.msg)
113+
if isnothing(src.file)
114+
print(io, "(no source available) $src")
115+
else
116+
highlight(io, src.file, byterange, note=exc.msg)
117+
end
114118
end
115119

116120
function eval_macro_name(ctx, ex)
@@ -127,21 +131,40 @@ function eval_macro_name(ctx, ex)
127131
eval(mod, expr_form)
128132
end
129133

134+
function is_expr_macro(mac)
135+
# If `mac` is @-prefixed and has no method taking MacroContext, assume it's
136+
# an old-style macro. Prefer new macros where possible.
137+
return string(Base.nameof(mac))[1] === '@' &&
138+
!any(m -> length(m.sig.types) >= 2 && m.sig.types[2] == MacroContext,
139+
Base.methods(mac))
140+
end
141+
130142
function expand_macro(ctx, ex)
131143
@assert kind(ex) == K"macrocall"
132144

133145
macname = ex[1]
134146
macfunc = eval_macro_name(ctx, macname)
135-
# Macro call arguments may be either
136-
# * Unprocessed by the macro expansion pass
137-
# * Previously processed, but spliced into a further macro call emitted by
138-
# a macro expansion.
139-
# In either case, we need to set any unset scope layers before passing the
140-
# arguments to the macro call.
147+
use_compat = is_expr_macro(macfunc)
148+
macro_args = Any[]
141149
mctx = MacroContext(ctx.graph, ex, ctx.current_layer)
142-
macro_args = Any[mctx]
143-
for i in 2:numchildren(ex)
144-
push!(macro_args, set_scope_layer(ctx, ex[i], ctx.current_layer.id, false))
150+
if use_compat
151+
lnn = source_location(LineNumberNode, JS.sourcefile(ex), JuliaSyntax.first_byte(ex))
152+
push!(macro_args, lnn)
153+
push!(macro_args, ctx.current_layer.mod)
154+
for i in 2:numchildren(ex)
155+
push!(macro_args, Base.Expr(set_scope_layer(ctx, ex[i], ctx.current_layer.id, false)))
156+
end
157+
elseif !use_compat
158+
# Macro call arguments may be either
159+
# * Unprocessed by the macro expansion pass
160+
# * Previously processed, but spliced into a further macro call emitted by
161+
# a macro expansion.
162+
# In either case, we need to set any unset scope layers before passing the
163+
# arguments to the macro call.
164+
push!(macro_args, mctx)
165+
for i in 2:numchildren(ex)
166+
push!(macro_args, set_scope_layer(ctx, ex[i], ctx.current_layer.id, false))
167+
end
145168
end
146169
macro_invocation_world = Base.get_world_counter()
147170
expanded = try
@@ -157,6 +180,10 @@ function expand_macro(ctx, ex)
157180
end
158181
end
159182

183+
if expanded isa Expr
184+
expanded = expr_to_syntaxtree(expanded, lnn)
185+
end
186+
160187
if expanded isa SyntaxTree
161188
if !is_compatible_graph(ctx, expanded)
162189
# If the macro has produced syntax outside the macro context, copy it over.

0 commit comments

Comments
 (0)