Skip to content

Commit

Permalink
added at-macroexpand (#18660)
Browse files Browse the repository at this point in the history
Fix #18240
  • Loading branch information
jw3126 authored and yuyichao committed Sep 30, 2016
1 parent c40090f commit 759ac10
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 0 deletions.
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,7 @@ export
expand,
gensym,
macroexpand,
@macroexpand,
parse,

# help and reflection
Expand Down
36 changes: 36 additions & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,42 @@ Takes the expression `x` and returns an equivalent expression with all macros re
"""
macroexpand(x::ANY) = ccall(:jl_macroexpand, Any, (Any,), x)

"""
@macroexpand
Return equivalent expression with all macros removed (expanded).
There is a subtle difference between `@macroexpand` and `macroexpand` in that expansion takes place in
different contexts. This is best seen in the following example:
```jldoctest
julia> module M
macro m()
1
end
function f()
(@macroexpand(@m), macroexpand(:(@m)))
end
end
M
julia> macro m()
2
end
@m (macro with 1 method)
julia> M.f()
(1,2)
```
With `@macroexpand` the expression expands where `@macroexpand` appears in the code (module `M`).
With `macroexpand` the expressions expands in the current module where the code was finally called (REPL).
Note that when calling `macroexpand` or `@macroexpand` directly from the REPL, both of these contexts coincide, hence there is no difference.
"""
macro macroexpand(code)
code_expanded = macroexpand(code)
QuoteNode(code_expanded)
end

## misc syntax ##

"""
Expand Down
30 changes: 30 additions & 0 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,36 @@ Internals
Takes the expression ``x`` and returns an equivalent expression with all macros removed (expanded).

.. function:: @macroexpand

.. Docstring generated from Julia source
Return equivalent expression with all macros removed (expanded).

There is a subtle difference between ``@macroexpand`` and ``macroexpand`` in that expansion takes place in different contexts. This is best seen in the following example:

.. doctest::

julia> module M
macro m()
1
end
function f()
(@macroexpand(@m), macroexpand(:(@m)))
end
end
M

julia> macro m()
2
end
@m (macro with 1 method)

julia> M.f()
(1,2)

With @macroexpand the expression expands where @macroexpand appears in the code (module M). With macroexpand the expressions expands in the current module where the code was finally called. Note that when calling macroexpand or @macroexpand directly from the REPL, both of these contexts coincide, hence there is no difference.

.. function:: expand(x)

.. Docstring generated from Julia source
Expand Down
1 change: 1 addition & 0 deletions doc/stdlib/io-network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1078,3 +1078,4 @@ Network I/O
.. Docstring generated from Julia source
The 32-bit byte-order-mark indicates the native byte order of the host machine. Little-endian machines will contain the value ``0x04030201``\ . Big-endian machines will contain the value ``0x01020304``\ .

19 changes: 19 additions & 0 deletions test/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,22 @@ let d = Dict(1 => 2, 3 => 45)
@test contains(replace(result, " ", ""), string(el))
end
end


# @macroexpand tests
macro seven_dollar(ex)
# simonbyrne example 18240
isa(ex,Expr) && ex.head == :$ ? 7 : ex
end

let
@test (@macroexpand @macroexpand x) == macroexpand(:(@macroexpand x))
@test (@macroexpand :(1+$y) ) == macroexpand(:( :(1+ $y)))
@test (@macroexpand @fastmath 1+2 ) == :(Base.FastMath.add_fast(1,2))
@test (@macroexpand @fastmath + ) == :(Base.FastMath.add_fast)
@test (@macroexpand @fastmath min(1) ) == :(Base.FastMath.min_fast(1))
@test (@macroexpand @doc "" f() = @x) == Expr(:error, UndefVarError(Symbol("@x")))
@test (@macroexpand @seven_dollar $bar) == 7
x = 2
@test (@macroexpand @seven_dollar 1+$x) == :(1 + $(Expr(:$, :x)))
end

0 comments on commit 759ac10

Please sign in to comment.