Skip to content

Commit bcd1514

Browse files
authored
Recurse rewrite_generic into :if and :block (#303)
1 parent bc97807 commit bcd1514

2 files changed

Lines changed: 113 additions & 1 deletion

File tree

src/rewrite_generic.jl

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,53 @@ function _is_kwarg(expr, kwarg::Symbol)
5555
return Meta.isexpr(expr, :kw) && expr.args[1] == kwarg
5656
end
5757

58+
function _rewrite_elseif!(if_expr, expr::Any)
59+
if expr isa Expr && Meta.isexpr(expr, :elseif)
60+
new_ifelse_expr = Expr(:elseif, esc(expr.args[1]))
61+
push!(if_expr.args, new_ifelse_expr)
62+
@assert 2 <= length(expr.args) <= 3
63+
return mapreduce(&, 2:length(expr.args)) do i
64+
return _rewrite_elseif!(new_ifelse_expr, expr.args[i])
65+
end
66+
end
67+
stack = quote end
68+
root, is_mutable = _rewrite_generic(stack, expr)
69+
push!(stack.args, root)
70+
push!(if_expr.args, stack)
71+
return is_mutable
72+
end
73+
74+
_rewrite_generic(stack::Expr, expr::LineNumberNode) = expr, false
75+
5876
"""
5977
_rewrite_generic(stack::Expr, expr::Expr)
6078
6179
This method is the heart of the rewrite logic. It converts `expr` into a mutable
6280
equivalent.
6381
"""
6482
function _rewrite_generic(stack::Expr, expr::Expr)
65-
if !Meta.isexpr(expr, :call)
83+
if Meta.isexpr(expr, :block)
84+
new_stack = quote end
85+
for arg in expr.args
86+
root, _ = _rewrite_generic(new_stack, arg)
87+
push!(new_stack.args, root)
88+
end
89+
root = gensym()
90+
push!(stack.args, :($root = $new_stack))
91+
return root, false
92+
elseif Meta.isexpr(expr, :if)
93+
# `if` blocks are special, because we can't lift the computation inside
94+
# them into the stack; the values might be defined only if the branch is
95+
# true.
96+
if_expr = Expr(:if, esc(expr.args[1]))
97+
@assert 2 <= length(expr.args) <= 3
98+
is_mutable = mapreduce(&, 2:length(expr.args)) do i
99+
return _rewrite_elseif!(if_expr, expr.args[i])
100+
end
101+
root = gensym()
102+
push!(stack.args, :($root = $if_expr))
103+
return root, is_mutable
104+
elseif !Meta.isexpr(expr, :call)
66105
# In situations like `x[i]`, we do not attempt to rewrite. Return `expr`
67106
# and don't let future callers mutate.
68107
return esc(expr), false

test/rewrite_generic.jl

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,79 @@ function test_rewrite_generic_sum_dims()
360360
return
361361
end
362362

363+
function test_rewrite_block()
364+
@test_rewrite begin
365+
x = 1
366+
y = x + 2
367+
z = 3 * y
368+
end
369+
@test_rewrite begin
370+
x = [1]
371+
y = x + [2]
372+
z = 3 * y
373+
end
374+
return
375+
end
376+
377+
function test_rewrite_ifelse()
378+
@test_rewrite begin
379+
x = -1
380+
y = [3.0]
381+
if x < 1
382+
y .+ x
383+
else
384+
2 * x
385+
end
386+
end
387+
@test_rewrite begin
388+
x = 2
389+
y = [3.0]
390+
if x < 1
391+
y .+ x
392+
else
393+
2 * x
394+
end
395+
end
396+
@test_rewrite begin
397+
x = 2
398+
y = [3.0, 4.0]
399+
if x < 1
400+
y .+ x
401+
elseif length(y) == 2
402+
0.0
403+
else
404+
2 * x
405+
end
406+
end
407+
@test_rewrite begin
408+
x = 2
409+
y = Float64[]
410+
if x < 1
411+
y .+ x
412+
elseif length(y) == 2
413+
0.0
414+
elseif isempty(y)
415+
-1.0
416+
else
417+
2 * x
418+
end
419+
end
420+
@test_rewrite begin
421+
x = 2
422+
y = Float64[1.0]
423+
if x < 1
424+
1.0
425+
elseif length(y) == 2
426+
2.0
427+
elseif isempty(y)
428+
3.0
429+
else
430+
4.0
431+
end
432+
end
433+
return
434+
end
435+
363436
end # module
364437

365438
TestRewriteGeneric.runtests()

0 commit comments

Comments
 (0)