-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathrequire.jl
84 lines (73 loc) · 1.87 KB
/
require.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
using Base: PkgId, loaded_modules, package_callbacks, @get!
using Base.Meta: isexpr
export @require
isprecompiling() = ccall(:jl_generating_output, Cint, ()) == 1
@init begin
push!(package_callbacks, loadpkg)
end
loaded(pkg) = haskey(Base.loaded_modules, pkg)
const _callbacks = Dict{PkgId, Vector{Function}}()
callbacks(pkg) = @get!(_callbacks, pkg, [])
listenpkg(f, pkg) =
loaded(pkg) ? f() : push!(callbacks(pkg), f)
function loadpkg(pkg)
fs = callbacks(pkg)
delete!(_callbacks, pkg)
map(f->Base.invokelatest(f), fs)
end
function withpath(f, path)
tls = task_local_storage()
hassource = haskey(tls, :SOURCE_PATH)
hassource && (path′ = tls[:SOURCE_PATH])
tls[:SOURCE_PATH] = path
try
return f()
finally
hassource ?
(tls[:SOURCE_PATH] = path′) :
delete!(tls, :SOURCE_PATH)
end
end
function err(f, listener, mod)
try
f()
catch e
@warn """
Error requiring $mod from $listener:
$(sprint(showerror, e, catch_backtrace()))
"""
end
end
function parsepkg(ex)
isexpr(ex, :(=)) || @goto fail
mod, id = ex.args
(mod isa Symbol && id isa String) || @goto fail
return Base.PkgId(Base.UUID(id), String(mod))
@label fail
error("Requires syntax is: `@require Pkg=\"uuid\"`")
end
macro require(pkg, expr)
pkg isa Symbol &&
return Expr(:macrocall, Symbol("@warn"), __source__,
"Requires now needs a UUID: `@require $pkg=\"uuid\"`")
pkg = parsepkg(pkg)
ex = quote
listenpkg($pkg) do
withpath(@__FILE__) do
err($__module__, $(pkg.name)) do
$(esc(:(eval($(Expr(:quote, Expr(:block,
:(const $(Symbol(pkg.name)) = Base.require($pkg)),
expr)))))))
end
end
end
end
quote
if isprecompiling()
@init @guard $(ex)
else
$(ex)
end
nothing
end
end