Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added @macroexpand #18660

Merged
merged 8 commits into from Sep 30, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions base/expr.jl
Expand Up @@ -65,6 +65,32 @@ macroexpand(x::ANY) = ccall(:jl_macroexpand, Any, (Any,), x)
@macroexpand

Return equivalent expression with all macros removed (expanded).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be documented that the expansion happens in the module where the @macroexpand macro is expanded (i.e. the same module if the expression is used directly) and not the current module when the returned code runs (which is the module if you call macroexpand) The difference is demonstrated below

julia> module M
       macro macroexpand(code)
           QuoteNode(macroexpand(code))
       end
       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)

This makes no difference when used in the REPL and as I said the current @macroexpand might be slightly better but this should still be documented.

Copy link
Contributor Author

@jw3126 jw3126 Sep 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give a usecase this would actually make a difference? And why is @macroexpand potentially better for interactive use?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give a usecase this would actually make a difference?

That's exactly what the code above is showing.

And why is @macroexpand potentially better for interactive use?

I said

This makes no difference when used in the REPL


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).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@macroexpand, macroexpand and M should be quoted. Otherwise 👍

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.
"""
macro macroexpand(code)
code_expanded = macroexpand(code)
Expand Down
24 changes: 24 additions & 0 deletions doc/stdlib/base.rst
Expand Up @@ -1523,6 +1523,30 @@ Internals

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
18 changes: 0 additions & 18 deletions test/expr.jl

This file was deleted.

19 changes: 19 additions & 0 deletions test/replutil.jl
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