Skip to content

Commit 13de283

Browse files
aviateskc42f
andauthored
Add error handling for macro name resolution (#25)
Wrap `eval()` call in try-catch to throw `MacroExpansionError` when macro name evaluation fails, providing clearer error messages for undefined macro names. --- Co-authored-by: Claire Foster <[email protected]>
1 parent cfa6901 commit 13de283

File tree

3 files changed

+24
-4
lines changed

3 files changed

+24
-4
lines changed

src/macro_expansion.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ function Base.showerror(io::IO, exc::MacroExpansionError)
113113
highlight(io, src.file, byterange, note=exc.msg)
114114
end
115115

116-
function eval_macro_name(ctx::MacroExpansionContext, ex::SyntaxTree)
116+
function eval_macro_name(ctx::MacroExpansionContext, mctx::MacroContext, ex::SyntaxTree)
117117
# `ex1` might contain a nontrivial mix of scope layers so we can't just
118118
# `eval()` it, as it's already been partially lowered by this point.
119119
# Instead, we repeat the latter parts of `lower()` here.
@@ -124,21 +124,25 @@ function eval_macro_name(ctx::MacroExpansionContext, ex::SyntaxTree)
124124
ctx5, ex5 = linearize_ir(ctx4, ex4)
125125
mod = ctx.current_layer.mod
126126
expr_form = to_lowered_expr(mod, ex5)
127-
eval(mod, expr_form)
127+
try
128+
eval(mod, expr_form)
129+
catch
130+
throw(MacroExpansionError(mctx, ex, "Macro not found", :all))
131+
end
128132
end
129133

130134
function expand_macro(ctx::MacroExpansionContext, ex::SyntaxTree)
131135
@assert kind(ex) == K"macrocall"
132136

133137
macname = ex[1]
134-
macfunc = eval_macro_name(ctx, macname)
138+
mctx = MacroContext(ctx.graph, ex, ctx.current_layer)
139+
macfunc = eval_macro_name(ctx, mctx, macname)
135140
# Macro call arguments may be either
136141
# * Unprocessed by the macro expansion pass
137142
# * Previously processed, but spliced into a further macro call emitted by
138143
# a macro expansion.
139144
# In either case, we need to set any unset scope layers before passing the
140145
# arguments to the macro call.
141-
mctx = MacroContext(ctx.graph, ex, ctx.current_layer)
142146
macro_args = Any[mctx]
143147
for i in 2:numchildren(ex)
144148
push!(macro_args, set_scope_layer(ctx, ex[i], ctx.current_layer.id, false))

test/macros.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ let (err, st) = try
161161
@test any(sf->sf.func===Symbol("@m_throw"), st)
162162
end
163163

164+
let res = try
165+
JuliaLowering.include_string(test_mod, "_never_exist = @m_not_exist 42")
166+
catch e
167+
e
168+
end
169+
@test res isa JuliaLowering.MacroExpansionError
170+
@test res.msg == "Macro not found"
171+
end
172+
164173
include("ccall_demo.jl")
165174
@test JuliaLowering.include_string(CCall, "@ccall strlen(\"foo\"::Cstring)::Csize_t") == 3
166175
let (err, st) = try

test/macros_ir.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,10 @@ function f()
125125
#─────┘ ── macro is only allowed in global scope
126126
end
127127

128+
########################################
129+
# Error: Macros not found
130+
_never_exist = @m_not_exist 42
131+
#---------------------
132+
MacroExpansionError while expanding @m_not_exist in module Main.TestMod:
133+
_never_exist = @m_not_exist 42
134+
# └─────────┘ ── Macro not found

0 commit comments

Comments
 (0)