Skip to content

Commit

Permalink
Define @qq
Browse files Browse the repository at this point in the history
  • Loading branch information
cstjean committed Dec 24, 2023
1 parent 6b3034a commit 9db5a11
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/src/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ MacroTools.combinearg

```@docs
MacroTools.@q
MacroTools.@qq
MacroTools.isexpr
MacroTools.rmlines
MacroTools.unblock
Expand Down
23 changes: 23 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ macro q(ex)
esc(Expr(:quote, striplines(ex)))
end

struct Flag end

to_flag(ex) = MacroTools.prewalk(x->x isa LineNumberNode ? Flag() : x, ex)
to_line(l::LineNumberNode, ex) = MacroTools.prewalk(x->x isa Flag ? l : x, ex)

"""
@qq [expression]
Like the `quote` keyword but replace construction site line numbers with __source__.
Line numbers of interpolated expressions are preserved. The result is that line numbers will be
attributed to the macro usage site, instead of the macro source code.
Only works inside of a macro definition.
See also: [`@q`](@ref)
"""
macro qq(ex)
# This was a difficult macro to write; the round-trip to Flag appears to be necessary.
# Crucially, we want interpolated expressions to preserve their line numbers.
esc(:($MacroTools.to_line(__source__, $(Expr(:quote, to_flag(ex))))))
end


"""
isexpr(x, ts...)
Expand Down
16 changes: 15 additions & 1 deletion test/utils.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MacroTools: isdef, flatten, striplines
using MacroTools: isdef, flatten, striplines, @qq

@testset "utils" begin
ex1 = :(function foo(a) return a; end)
Expand Down Expand Up @@ -45,3 +45,17 @@ end
@test flatten(ex) |> striplines == ex |> striplines
end
end

## Test for @qq

macro my_fff_def(a)
@qq function fff() $a end
end

@my_fff_def begin # line where fff() is defined
function g() # line where fff()() is defined
22
end
end

@test which(fff,()).line == which(fff(),()).line - 1

0 comments on commit 9db5a11

Please sign in to comment.