/
macro.jl
62 lines (51 loc) · 1.33 KB
/
macro.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
"""
@! expr
Convert all supported mutating calls to double bang equivalent.
# Examples
```jldoctest
julia> using BangBang
julia> @! push!(empty!((0, 1)), 2, 3)
(2, 3)
julia> y = [1, 2];
julia> @! y .= 2 .* y
y
2-element Vector{Int64}:
2
4
julia> y = (1, 2);
julia> @! y .= 2 .* y
y
(2, 4)
```
"""
macro !(expr)
foldexpr(macroexpand(__module__, expr)) do x
if Meta.isexpr(x, :call)
isdotoperator(x.args[1]) && return x
return Expr(:call, Expr(:call, _maybb, x.args[1]), x.args[2:end]...)
elseif Meta.isexpr(x, :.=) && x.args[1] isa Symbol
@assert length(x.args) == 2
lhs, rhs = x.args
return :($lhs = $materialize!!(
$Base.@isdefined($lhs) ? $lhs : $(Undefined()),
$air.($rhs),
))
end
return x
end |> esc
end
foldexpr(f, x) = x
foldexpr(f, ex::Expr) = f(Expr(ex.head, foldexpr.(f, ex.args)...))
isdotoperator(x::Symbol) = undotoperator(x) !== nothing
function undotoperator(x::Symbol)
startswith(string(x), ".") || return nothing
op = Symbol(string(x)[2:end])
Base.isoperator(op) || return nothing
return op
end
function air end
struct Aired{T}
value::T
end
@inline Broadcast.broadcasted(::typeof(air), x) = Aired(x)
@inline Broadcast.materialize(x::Aired) = x.value