forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmeta.jl
146 lines (118 loc) · 3.27 KB
/
meta.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
139
140
141
142
143
144
145
146
# This file is a part of Julia. License is MIT: https://julialang.org/license
# test meta-expressions that annotate blocks of code
const inlining_on = Base.JLOptions().can_inline != 0
function f(x)
y = x+5
z = y*y
q = z/y
m = q-3
end
@inline function f_inlined(x)
y = x+5
z = y*y
q = z/y
m = q-3
end
g(x) = f(2x)
g_inlined(x) = f_inlined(2x)
@test g(3) == g_inlined(3)
@test f(3) == f_inlined(3)
f() = backtrace()
@inline g_inlined() = f()
@noinline g_noinlined() = f()
h_inlined() = g_inlined()
h_noinlined() = g_noinlined()
function foundfunc(bt, funcname)
for b in bt
for lkup in StackTraces.lookup(b)
if lkup.func == funcname
return true
end
end
end
false
end
if inlining_on
@test !foundfunc(h_inlined(), :g_inlined)
end
@test foundfunc(h_noinlined(), :g_noinlined)
using Base.pushmeta!, Base.popmeta!
macro attach(val, ex)
esc(_attach(val, ex))
end
_attach(val, ex) = pushmeta!(ex, :test, val)
@attach 42 function dummy()
false
end
asts = code_lowered(dummy, Tuple{})
@test length(asts) == 1
ast = asts[1]
body = Expr(:block)
body.args = ast.code
@test popmeta!(body, :test) == (true, [42])
@test popmeta!(body, :nonexistent) == (false, [])
# Simple popmeta!() tests
ex1 = quote
$(Expr(:meta, :foo))
x*x+1
end
@test popmeta!(ex1, :foo)[1]
@test !popmeta!(ex1, :foo)[1]
@test !popmeta!(ex1, :bar)[1]
@test !(popmeta!(:(x*x+1), :foo)[1])
# Find and pop meta information from general ast locations
multi_meta = quote
$(Expr(:meta, :foo1))
y = x
$(Expr(:meta, :foo2, :foo3))
begin
$(Expr(:meta, :foo4, Expr(:foo5, 1, 2)))
end
x*x+1
end
@test popmeta!(deepcopy(multi_meta), :foo1) == (true, [])
@test popmeta!(deepcopy(multi_meta), :foo2) == (true, [])
@test popmeta!(deepcopy(multi_meta), :foo3) == (true, [])
@test popmeta!(deepcopy(multi_meta), :foo4) == (true, [])
@test popmeta!(deepcopy(multi_meta), :foo5) == (true, [1,2])
@test popmeta!(deepcopy(multi_meta), :bar) == (false, [])
# Test that popmeta!() removes meta blocks entirely when they become empty.
for m in [:foo1, :foo2, :foo3, :foo4, :foo5]
@test popmeta!(multi_meta, m)[1]
end
@test Base.findmeta(multi_meta.args)[1] == 0
# Test that pushmeta! can push across other macros,
# in the case multiple pushmeta!-based macros are combined
@attach 40 @attach 41 @attach 42 dummy_multi() = return nothing
asts = code_lowered(dummy_multi, Tuple{})
@test length(asts) == 1
ast = asts[1]
body = Expr(:block)
body.args = ast.code
@test popmeta!(body, :test) == (true, [40])
@test popmeta!(body, :test) == (true, [41])
@test popmeta!(body, :test) == (true, [42])
@test popmeta!(body, :nonexistent) == (false, [])
# tests to fully cover functions in base/meta.jl
using Base.Meta
@test isexpr(:(1+1),Set([:call]))
@test isexpr(:(1+1),Vector([:call]))
@test isexpr(:(1+1),(:call,))
@test isexpr(1,:call)==false
@test isexpr(:(1+1),:call,3)
ioB = IOBuffer()
show_sexpr(ioB,:(1+1))
show_sexpr(ioB,QuoteNode(1),1)
@test Base.Distributed.extract_imports(:(begin; import Foo, Bar; let; using Baz; end; end)) ==
[:Foo, :Bar, :Baz]
# test base/expr.jl
baremodule B
eval = 0
x = 1
module M; x = 2; end
import Base
@Base.eval x = 3
@Base.eval M x = 4
end
@test B.x == 3
@test B.M.x == 4