Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
284
julia-0.6.2/share/julia/base/expr.jl
Normal file
284
julia-0.6.2/share/julia/base/expr.jl
Normal file
@@ -0,0 +1,284 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
## symbols ##
|
||||
|
||||
"""
|
||||
gensym([tag])
|
||||
|
||||
Generates a symbol which will not conflict with other variable names.
|
||||
"""
|
||||
gensym() = ccall(:jl_gensym, Ref{Symbol}, ())
|
||||
|
||||
gensym(s::String) = ccall(:jl_tagged_gensym, Ref{Symbol}, (Ptr{UInt8}, Int32), s, sizeof(s))
|
||||
|
||||
gensym(ss::String...) = map(gensym, ss)
|
||||
gensym(s::Symbol) =
|
||||
ccall(:jl_tagged_gensym, Ref{Symbol}, (Ptr{UInt8}, Int32), s, ccall(:strlen, Csize_t, (Ptr{UInt8},), s))
|
||||
|
||||
"""
|
||||
@gensym
|
||||
|
||||
Generates a gensym symbol for a variable. For example, `@gensym x y` is transformed into
|
||||
`x = gensym("x"); y = gensym("y")`.
|
||||
"""
|
||||
macro gensym(names...)
|
||||
blk = Expr(:block)
|
||||
for name in names
|
||||
push!(blk.args, :($(esc(name)) = gensym($(string(name)))))
|
||||
end
|
||||
push!(blk.args, :nothing)
|
||||
return blk
|
||||
end
|
||||
|
||||
## expressions ##
|
||||
|
||||
copy(e::Expr) = (n = Expr(e.head);
|
||||
n.args = copy_exprargs(e.args);
|
||||
n.typ = e.typ;
|
||||
n)
|
||||
|
||||
# copy parts of an AST that the compiler mutates
|
||||
copy_exprs(x::Expr) = copy(x)
|
||||
copy_exprs(x::ANY) = x
|
||||
copy_exprargs(x::Array{Any,1}) = Any[copy_exprs(a) for a in x]
|
||||
|
||||
==(x::Expr, y::Expr) = x.head === y.head && isequal(x.args, y.args)
|
||||
==(x::QuoteNode, y::QuoteNode) = isequal(x.value, y.value)
|
||||
|
||||
"""
|
||||
expand(x)
|
||||
|
||||
Takes the expression `x` and returns an equivalent expression in lowered form.
|
||||
See also [`code_lowered`](@ref).
|
||||
"""
|
||||
expand(x::ANY) = ccall(:jl_expand, Any, (Any,), x)
|
||||
|
||||
"""
|
||||
macroexpand(x)
|
||||
|
||||
Takes the expression `x` and returns an equivalent expression with all macros removed (expanded).
|
||||
"""
|
||||
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` in the example). With `macroexpand` the expression expands in the current module where
|
||||
the code was finally called (REPL in the example).
|
||||
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 ##
|
||||
|
||||
"""
|
||||
eval([m::Module], expr::Expr)
|
||||
|
||||
Evaluate an expression in the given module and return the result. Every `Module` (except
|
||||
those defined with `baremodule`) has its own 1-argument definition of `eval`, which
|
||||
evaluates expressions in that module.
|
||||
"""
|
||||
Core.eval
|
||||
|
||||
"""
|
||||
@inline
|
||||
|
||||
Give a hint to the compiler that this function is worth inlining.
|
||||
|
||||
Small functions typically do not need the `@inline` annotation,
|
||||
as the compiler does it automatically. By using `@inline` on bigger functions,
|
||||
an extra nudge can be given to the compiler to inline it.
|
||||
This is shown in the following example:
|
||||
|
||||
```julia
|
||||
@inline function bigfunction(x)
|
||||
#=
|
||||
Function Definition
|
||||
=#
|
||||
end
|
||||
```
|
||||
"""
|
||||
macro inline(ex)
|
||||
esc(isa(ex, Expr) ? pushmeta!(ex, :inline) : ex)
|
||||
end
|
||||
|
||||
"""
|
||||
@noinline
|
||||
|
||||
Prevents the compiler from inlining a function.
|
||||
|
||||
Small functions are typically inlined automatically.
|
||||
By using `@noinline` on small functions, auto-inlining can be
|
||||
prevented. This is shown in the following example:
|
||||
|
||||
```julia
|
||||
@noinline function smallfunction(x)
|
||||
#=
|
||||
Function Definition
|
||||
=#
|
||||
end
|
||||
```
|
||||
"""
|
||||
macro noinline(ex)
|
||||
esc(isa(ex, Expr) ? pushmeta!(ex, :noinline) : ex)
|
||||
end
|
||||
|
||||
macro pure(ex)
|
||||
esc(isa(ex, Expr) ? pushmeta!(ex, :pure) : ex)
|
||||
end
|
||||
|
||||
"""
|
||||
@propagate_inbounds
|
||||
|
||||
Tells the compiler to inline a function while retaining the caller's inbounds context.
|
||||
"""
|
||||
macro propagate_inbounds(ex)
|
||||
if isa(ex, Expr)
|
||||
pushmeta!(ex, :inline)
|
||||
pushmeta!(ex, :propagate_inbounds)
|
||||
esc(ex)
|
||||
else
|
||||
esc(ex)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
@polly
|
||||
|
||||
Tells the compiler to apply the polyhedral optimizer Polly to a function.
|
||||
"""
|
||||
macro polly(ex)
|
||||
esc(isa(ex, Expr) ? pushmeta!(ex, :polly) : ex)
|
||||
end
|
||||
|
||||
## some macro utilities ##
|
||||
|
||||
function pushmeta!(ex::Expr, sym::Symbol, args::Any...)
|
||||
if isempty(args)
|
||||
tag = sym
|
||||
else
|
||||
tag = Expr(sym, args...)
|
||||
end
|
||||
|
||||
inner = ex
|
||||
while inner.head == :macrocall
|
||||
inner = inner.args[end]::Expr
|
||||
end
|
||||
|
||||
idx, exargs = findmeta(inner)
|
||||
if idx != 0
|
||||
push!(exargs[idx].args, tag)
|
||||
else
|
||||
body::Expr = inner.args[2]
|
||||
unshift!(body.args, Expr(:meta, tag))
|
||||
end
|
||||
ex
|
||||
end
|
||||
|
||||
function popmeta!(body::Expr, sym::Symbol)
|
||||
body.head == :block || return false, []
|
||||
popmeta!(body.args, sym)
|
||||
end
|
||||
popmeta!(arg, sym) = (false, [])
|
||||
function popmeta!(body::Array{Any,1}, sym::Symbol)
|
||||
idx, blockargs = findmeta_block(body, args -> findmetaarg(args,sym)!=0)
|
||||
if idx == 0
|
||||
return false, []
|
||||
end
|
||||
metaargs = blockargs[idx].args
|
||||
i = findmetaarg(blockargs[idx].args, sym)
|
||||
if i == 0
|
||||
return false, []
|
||||
end
|
||||
ret = isa(metaargs[i], Expr) ? (metaargs[i]::Expr).args : []
|
||||
deleteat!(metaargs, i)
|
||||
isempty(metaargs) && deleteat!(blockargs, idx)
|
||||
true, ret
|
||||
end
|
||||
|
||||
# Find index of `sym` in a meta expression argument list, or 0.
|
||||
function findmetaarg(metaargs, sym)
|
||||
for i = 1:length(metaargs)
|
||||
arg = metaargs[i]
|
||||
if (isa(arg, Symbol) && (arg::Symbol) == sym) ||
|
||||
(isa(arg, Expr) && (arg::Expr).head == sym)
|
||||
return i
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function is_short_function_def(ex)
|
||||
ex.head == :(=) || return false
|
||||
while length(ex.args) >= 1 && isa(ex.args[1], Expr)
|
||||
(ex.args[1].head == :call) && return true
|
||||
(ex.args[1].head == :where || ex.args[1].head == :(::)) || return false
|
||||
ex = ex.args[1]
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function findmeta(ex::Expr)
|
||||
if ex.head == :function || is_short_function_def(ex)
|
||||
body::Expr = ex.args[2]
|
||||
body.head == :block || error(body, " is not a block expression")
|
||||
return findmeta_block(ex.args)
|
||||
end
|
||||
error(ex, " is not a function expression")
|
||||
end
|
||||
|
||||
findmeta(ex::Array{Any,1}) = findmeta_block(ex)
|
||||
|
||||
function findmeta_block(exargs, argsmatch=args->true)
|
||||
for i = 1:length(exargs)
|
||||
a = exargs[i]
|
||||
if isa(a, Expr)
|
||||
if (a::Expr).head == :meta && argsmatch((a::Expr).args)
|
||||
return i, exargs
|
||||
elseif (a::Expr).head == :block
|
||||
idx, exa = findmeta_block(a.args, argsmatch)
|
||||
if idx != 0
|
||||
return idx, exa
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0, []
|
||||
end
|
||||
|
||||
remove_linenums!(ex) = ex
|
||||
function remove_linenums!(ex::Expr)
|
||||
filter!(x->!((isa(x,Expr) && x.head === :line) || isa(x,LineNumberNode)), ex.args)
|
||||
for subex in ex.args
|
||||
remove_linenums!(subex)
|
||||
end
|
||||
ex
|
||||
end
|
||||
Reference in New Issue
Block a user