Skip to content

Commit

Permalink
add macroexpand1 function and macro (#21662)
Browse files Browse the repository at this point in the history
`@macroexpand1` is a non recursive variant of `@macroexpand`

The `macroexpand` function now also takes an keyword argument `recursive` to indicate whether to expand one level of macros or all macros recursively.
  • Loading branch information
jw3126 authored and vtjnash committed Jul 13, 2017
1 parent 9c1d1b8 commit a7f24c4
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 14 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ Library improvements
`ntuple`, `Base.literal_pow`, `sqrtm`, `lufact`, `lufact!`, `qrfact`, `qrfact!`,
`cholfact`, `cholfact!`, `_broadcast!`, `reshape`, `cat` and `cat_t`.

* A new `@macroexpand1` macro for non recursive macro expansion ([#21662]).

Compiler/Runtime improvements
-----------------------------

Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ export
expand,
gensym,
macroexpand,
@macroexpand1,
@macroexpand,
parse,

Expand Down
55 changes: 47 additions & 8 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,51 @@ See also [`code_lowered`](@ref).
expand(m::Module, x::ANY) = ccall(:jl_expand, Any, (Any, Any), x, m)

"""
macroexpand(m, x)
macroexpand(m::Module, x; recursive=true)
Takes the expression `x` and returns an equivalent expression with all macros removed (expanded)
for executing in module `m`.
The `recursive` keyword controls whether deeper levels of nested macros are also expanded.
This is demonstrated in the example below:
```julia-repl
julia> module M
macro m1()
42
end
macro m2()
:(@m1())
end
end
M
julia> macroexpand(M, :(@m2()), recursive=true)
42
julia> macroexpand(M, :(@m2()), recursive=false)
:(#= REPL[16]:6 =# M.@m1)
```
"""
macroexpand(m::Module, x::ANY) = ccall(:jl_macroexpand, Any, (Any, Any), x, m)
function macroexpand(m::Module, x::ANY; recursive=true)
if recursive
ccall(:jl_macroexpand, Any, (Any, Any), x, m)
else
ccall(:jl_macroexpand1, Any, (Any, Any), x, m)
end
end

"""
@macroexpand
Return equivalent expression with all macros removed (expanded).
There is a difference between `@macroexpand` and `macroexpand` in that the `macroexpand` function
also takes a module where the expansion takes place.
This is best seen in the following example:
There are differences between `@macroexpand` and [`macroexpand`](@ref).
* While [`macroexpand`](@ref) takes a keyword argument `recursive`, `@macroexpand`
is always recursive. For a non recursive macro version, see [`@macroexpand1`](@ref).
* While [`macroexpand`](@ref) has an explicit `module` argument, `@macroexpand` always
expands with respect to the module in which it is called.
This is best seen in the following example:
```jldoctest
julia> module M
macro m()
Expand All @@ -93,11 +122,21 @@ julia> macro m()
julia> M.f()
(1, 1, 2)
```
With `@macroexpand` the expression expands where `@macroexpand` appears in the code (module
`M` in the example). With `macroexpand` the expression expands in the module given as the first argument.
With `@macroexpand` the expression expands where `@macroexpand` appears in the code (module `M` in the example).
With `macroexpand` the expression expands in the module given as the first argument.
"""
macro macroexpand(code)
return :(macroexpand($__module__, $(QuoteNode(code))))
return :(macroexpand($__module__, $(QuoteNode(code)), recursive=true))
end


"""
@macroexpand1
Non recursive version of [`@macroexpand`](@ref).
"""
macro macroexpand1(code)
return :(macroexpand($__module__, $(QuoteNode(code)), recursive=false))
end

## misc syntax ##
Expand Down
1 change: 1 addition & 0 deletions doc/src/stdlib/base.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ Base.gc
Base.gc_enable
Base.macroexpand
Base.@macroexpand
Base.@macroexpand1
Base.expand
Base.code_lowered
Base.@code_lowered
Expand Down
6 changes: 6 additions & 0 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,12 @@ JL_DLLEXPORT jl_value_t *jl_macroexpand(jl_value_t *expr, jl_module_t *inmodule)
return jl_call_scm_on_ast("jl-macroexpand", expr, inmodule);
}

JL_DLLEXPORT jl_value_t *jl_macroexpand1(jl_value_t *expr, jl_module_t *inmodule)
{
JL_TIMING(LOWERING);
return jl_call_scm_on_ast("jl-macroexpand-1", expr, inmodule);
}

// wrap expr in a thunk AST
jl_code_info_t *jl_wrap_expr(jl_value_t *expr)
{
Expand Down
5 changes: 5 additions & 0 deletions src/jlfrontend.scm
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@
(parser-wrap (lambda ()
(julia-expand-macros expr))))

(define (jl-macroexpand-1 expr)
(reset-gensyms)
(parser-wrap (lambda ()
(julia-expand-macros expr 1))))

; run whole frontend on a string. useful for testing.
(define (fe str)
(expand-toplevel-expr (julia-parse str)))
Expand Down
12 changes: 6 additions & 6 deletions src/macroexpand.scm
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,12 @@

;; macro expander entry point

(define (julia-expand-macros e)
(cond ((not (pair? e)) e)
(define (julia-expand-macros e (max-depth -1))
(cond ((= max-depth 0) e)
((not (pair? e)) e)
((eq? (car e) 'quote)
;; backquote is essentially a built-in macro at the moment
(julia-expand-macros (julia-bq-expand (cadr e) 0)))
(julia-expand-macros (julia-bq-expand (cadr e) 0) max-depth))
((eq? (car e) 'inert) e)
((eq? (car e) 'macrocall)
;; expand macro
Expand All @@ -483,8 +484,7 @@
(m (cdr form)))
;; m is the macro's def module
(rename-symbolic-labels
(julia-expand-macros
(resolve-expansion-vars form m))))))
(julia-expand-macros (resolve-expansion-vars form m) (- max-depth 1))))))
((eq? (car e) 'module) e)
(else
(map julia-expand-macros e))))
(map (lambda (ex) (julia-expand-macros ex max-depth)) e))))
26 changes: 26 additions & 0 deletions test/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,32 @@ let
@test (@macroexpand @seven_dollar 1+$x) == :(1 + $(Expr(:$, :x)))
end

macro nest1(code)
code
end

macro nest2(code)
:(@nest1 $code)
end

macro nest2b(code)
:(@nest1($code); @nest1($code))
end

@testset "@macroexpand1" begin
M = @__MODULE__
_macroexpand1(ex) = macroexpand(M, ex, recursive=false)
ex = :(@nest1 42)
@test _macroexpand1(ex) == macroexpand(M,ex)
ex = :(@nest2 42)
@test _macroexpand1(ex) != macroexpand(M,ex)
@test _macroexpand1(_macroexpand1(ex)) == macroexpand(M,ex)
ex = :(@nest2b 42)
@test _macroexpand1(ex) != macroexpand(M,ex)
@test _macroexpand1(_macroexpand1(ex)) == macroexpand(M, ex)
@test (@macroexpand1 @nest2b 42) == _macroexpand1(ex)
end

foo_9965(x::Float64; w=false) = x
foo_9965(x::Int) = 2x

Expand Down

0 comments on commit a7f24c4

Please sign in to comment.