diff --git a/Project.toml b/Project.toml index 72362a64..256ebf76 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,9 @@ version = "1.0.0-DEV" [deps] JuliaSyntax = "70703baa-626e-46a2-a12c-08ffd08c73b4" +[sources] +JuliaSyntax = {rev = "e02f29f", url = "https://github.com/JuliaLang/JuliaSyntax.jl"} + [compat] julia = "1" diff --git a/src/macro_expansion.jl b/src/macro_expansion.jl index 1e4ac756..473dab2c 100644 --- a/src/macro_expansion.jl +++ b/src/macro_expansion.jl @@ -113,7 +113,7 @@ function Base.showerror(io::IO, exc::MacroExpansionError) highlight(io, src.file, byterange, note=exc.msg) end -function eval_macro_name(ctx, ex) +function eval_macro_name(ctx::MacroExpansionContext, ex::SyntaxTree) # `ex1` might contain a nontrivial mix of scope layers so we can't just # `eval()` it, as it's already been partially lowered by this point. # Instead, we repeat the latter parts of `lower()` here. @@ -127,7 +127,7 @@ function eval_macro_name(ctx, ex) eval(mod, expr_form) end -function expand_macro(ctx, ex) +function expand_macro(ctx::MacroExpansionContext, ex::SyntaxTree) @assert kind(ex) == K"macrocall" macname = ex[1] @@ -148,12 +148,13 @@ function expand_macro(ctx, ex) # TODO: Allow invoking old-style macros for compat invokelatest(macfunc, macro_args...) catch exc + # TODO: Using rethrow() is kinda ugh. Is there a way to avoid it? + # NOTE: Although currently rethrow() is necessary to allow outside catchers to access full stacktrace information if exc isa MacroExpansionError # Add context to the error. - # TODO: Using rethrow() is kinda ugh. Is there a way to avoid it? rethrow(MacroExpansionError(mctx, exc.ex, exc.msg, exc.position)) else - throw(MacroExpansionError(mctx, ex, "Error expanding macro", :all)) + rethrow(MacroExpansionError(mctx, ex, "Error expanding macro", :all)) end end @@ -237,7 +238,7 @@ function expand_forms_1(ctx::MacroExpansionContext, ex::SyntaxTree) @chk numchildren(ex) == 1 # TODO: Upstream should set a general flag for detecting parenthesized # expressions so we don't need to dig into `green_tree` here. Ugh! - plain_symbol = has_flags(ex, JuliaSyntax.COLON_QUOTE) && + plain_symbol = has_flags(ex, JuliaSyntax.COLON_QUOTE) && kind(ex[1]) == K"Identifier" && (sr = sourceref(ex); sr isa SourceRef && kind(sr.green_tree[2]) != K"parens") if plain_symbol @@ -337,4 +338,3 @@ function expand_forms_1(mod::Module, ex::SyntaxTree) ctx.current_layer) return ctx2, reparent(ctx2, ex2) end - diff --git a/test/ccall_demo.jl b/test/ccall_demo.jl index 0d7b784c..f5e2e987 100644 --- a/test/ccall_demo.jl +++ b/test/ccall_demo.jl @@ -105,7 +105,7 @@ function ccall_macro_lower(ex, convention, func, rettype, types, args, num_varar push!(roots, argi) push!(cargs, ast":(Base.unsafe_convert($type, $argi))") end - push!(statements, + push!(statements, @ast ex ex [K"foreigncall" func rettype @@ -126,5 +126,4 @@ function var"@ccall"(ctx::JuliaLowering.MacroContext, ex) ccall_macro_lower(ex, "ccall", ccall_macro_parse(ex)...) end -end - +end # module CCall diff --git a/test/macros.jl b/test/macros.jl index 6e25c326..c6c44c41 100644 --- a/test/macros.jl +++ b/test/macros.jl @@ -1,6 +1,8 @@ -@testset "macros" begin +module macros -test_mod = Module() +using JuliaLowering, Test + +module test_mod end JuliaLowering.include_string(test_mod, """ module M @@ -75,7 +77,7 @@ end """) @test JuliaLowering.include_string(test_mod, """ -let +let x = "`x` from outer scope" M.@foo x end @@ -89,7 +91,7 @@ end @test !isdefined(test_mod.M, :a_global) @test JuliaLowering.include_string(test_mod, """ -begin +begin M.@set_a_global 42 M.a_global end @@ -133,13 +135,43 @@ M.@recursive 3 """) == (3, (2, (1, 0))) @test let - ex = parsestmt(SyntaxTree, "M.@outer()", filename="foo.jl") + ex = JuliaLowering.parsestmt(JuliaLowering.SyntaxTree, "M.@outer()", filename="foo.jl") expanded = JuliaLowering.macroexpand(test_mod, ex) - sourcetext.(flattened_provenance(expanded[2])) + JuliaLowering.sourcetext.(JuliaLowering.flattened_provenance(expanded[2])) end == [ "M.@outer()" "@inner" "2" ] +JuliaLowering.include_string(test_mod, """ +f_throw(x) = throw(x) +macro m_throw(x) + :(\$(f_throw(x))) +end +""") +let (err, st) = try + JuliaLowering.include_string(test_mod, "_never_exist = @m_throw 42") + catch e + e, stacktrace(catch_backtrace()) + end + @test err isa JuliaLowering.MacroExpansionError + # Check that `catch_backtrace` can capture the stacktrace of the macro functions + @test any(sf->sf.func===:f_throw, st) + @test any(sf->sf.func===Symbol("@m_throw"), st) end + +include("ccall_demo.jl") +@test JuliaLowering.include_string(CCall, "@ccall strlen(\"foo\"::Cstring)::Csize_t") == 3 +let (err, st) = try + JuliaLowering.include_string(CCall, "@ccall strlen(\"foo\"::Cstring)") + catch e + e, stacktrace(catch_backtrace()) + end + @test err isa JuliaLowering.MacroExpansionError + @test err.msg == "Expected a return type annotation like `::T`" + # Check that `catch_backtrace` can capture the stacktrace of the macro function + @test any(sf->sf.func===:ccall_macro_parse, st) +end + +end # module macros diff --git a/test/runtests.jl b/test/runtests.jl index f8a76bae..d628fde0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,7 +3,6 @@ using Test include("utils.jl") @testset "JuliaLowering.jl" begin - include("syntax_graph.jl") include("ir_tests.jl") @@ -20,11 +19,10 @@ include("utils.jl") include("generators.jl") include("import.jl") include("loops.jl") - include("macros.jl") + @testset "macros" include("macros.jl") include("misc.jl") include("modules.jl") include("quoting.jl") include("scopes.jl") include("typedefs.jl") - end