-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
Copy pathexpr.jl
138 lines (119 loc) · 3.91 KB
/
expr.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
## symbols ##
symbol(s::Symbol) = s
symbol(s::ASCIIString) = symbol(s.data)
symbol(s::UTF8String) = symbol(s.data)
symbol(a::Array{Uint8,1}) =
ccall(:jl_symbol_n, Any, (Ptr{Uint8}, Int32), a, length(a))::Symbol
symbol(x::Char) = symbol(string(x))
gensym() = ccall(:jl_gensym, Any, ())::Symbol
gensym(s::ASCIIString) = gensym(s.data)
gensym(s::UTF8String) = gensym(s.data)
gensym(a::Array{Uint8,1}) =
ccall(:jl_tagged_gensym, Any, (Ptr{Uint8}, Int32), a, length(a))::Symbol
gensym(ss::Union(ASCIIString, UTF8String)...) = map(gensym, ss)
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 ##
splicedexpr(hd::Symbol, args::Array{Any,1}) = (e=Expr(hd); e.args=args; e)
copy(e::Expr) = (n = Expr(e.head);
n.args = astcopy(e.args);
n.typ = e.typ;
n)
copy(s::SymbolNode) = SymbolNode(s.name, s.typ)
copy(n::GetfieldNode) = GetfieldNode(n.value, n.name, n.typ)
# copy parts of an AST that the compiler mutates
astcopy(x::Union(SymbolNode,GetfieldNode,Expr)) = copy(x)
astcopy(x::Array{Any,1}) = Any[astcopy(a) for a in x]
astcopy(x) = x
==(x::Expr, y::Expr) = x.head === y.head && x.args == y.args
==(x::QuoteNode, y::QuoteNode) = x.value == y.value
function show(io::IO, tv::TypeVar)
if !is(tv.lb, Bottom)
show(io, tv.lb)
print(io, "<:")
end
print(io, tv.name)
if !is(tv.ub, Any)
print(io, "<:")
show(io, tv.ub)
end
end
expand(x) = ccall(:jl_expand, Any, (Any,), x)
macroexpand(x) = ccall(:jl_macroexpand, Any, (Any,), x)
## misc syntax ##
macro eval(x)
:($(esc(:eval))($(Expr(:quote,x))))
end
macro inline(ex)
esc(_inline(ex))
end
_inline(ex::Expr) = pushmeta!(ex, :inline)
_inline(arg) = arg
## some macro utilities ##
find_vars(e) = find_vars(e, {})
function find_vars(e, lst)
if isa(e,Symbol)
if current_module()===Main && isdefined(e)
# Main runs on process 1, so send globals from there, excluding
# things defined in Base.
if !isdefined(Base,e) || eval(Base,e)!==eval(current_module(),e)
push!(lst, e)
end
end
elseif isa(e,Expr) && e.head !== :quote && e.head !== :top
for x in e.args
find_vars(x,lst)
end
end
lst
end
# wrap an expression in "let a=a,b=b,..." for each var it references
localize_vars(expr) = localize_vars(expr, true)
function localize_vars(expr, esca)
v = find_vars(expr)
# requires a special feature of the front end that knows how to insert
# the correct variables. the list of free variables cannot be computed
# from a macro.
if esca
v = map(esc,v)
end
Expr(:localize, :(()->($expr)), v...)
end
function pushmeta!(ex::Expr, sym::Symbol)
if ex.head == :function
body::Expr = ex.args[2]
if !isempty(body.args) && isa(body.args[1], Expr) && (body.args[1]::Expr).head == :meta
push!((body.args[1]::Expr).args, sym)
else
unshift!(body.args, Expr(:meta, sym))
end
elseif (ex.head == :(=) && typeof(ex.args[1]) == Expr && ex.args[1].head == :call)
ex = Expr(:function, ex.args[1], Expr(:block, Expr(:meta, sym), ex.args[2]))
# else
# ex = Expr(:withmeta, ex, sym)
end
ex
end
function popmeta!(body::Expr, sym::Symbol)
if isa(body.args[1],Expr) && (body.args[1]::Expr).head === :meta
metaargs = (body.args[1]::Expr).args
for i = 1:length(metaargs)
if metaargs[i] == sym
if length(metaargs) == 1
shift!(body.args) # get rid of :meta Expr
else
deleteat!(metaargs, i) # delete this portion of the metadata
end
return true
end
end
end
false
end
popmeta!(arg, sym) = false