@@ -55,14 +55,53 @@ function _is_kwarg(expr, kwarg::Symbol)
5555 return Meta. isexpr (expr, :kw ) && expr. args[1 ] == kwarg
5656end
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
6179This method is the heart of the rewrite logic. It converts `expr` into a mutable
6280equivalent.
6381"""
6482function _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
0 commit comments