@@ -25,6 +25,81 @@ function replace_ref_begin_end_!(__module__::Module, ex, withex, in_quote_contex
2525 end
2626 return ex
2727 end
28+ function handle_refexpr! (__module__:: Module , ref_ex:: Expr , main_ex:: Expr , withex, in_quote_context, escs:: Int )
29+ @assert ! in_quote_context
30+ local used_withex
31+ ref_ex. args[1 ], used_withex = replace_ref_begin_end_! (__module__, ref_ex. args[1 ], withex, in_quote_context, escs)
32+ S = gensym (:S ) # temp var to cache ex.args[1] if needed. if S is a global or expression, then it has side effects to use
33+ assignments = []
34+ used_S = false # whether we actually need S
35+ # new :ref, so redefine withex
36+ nargs = length (ref_ex. args) - 1
37+ if nargs == 0
38+ return main_ex, used_withex
39+ elseif nargs == 1
40+ # replace with lastindex(S)
41+ ref_ex. args[2 ], used_S = replace_ref_begin_end_! (__module__, ref_ex. args[2 ], (:($ firstindex ($ S)),:($ lastindex ($ S))), in_quote_context, escs)
42+ else
43+ ni = 1
44+ nx = 0
45+ J = nargs + 1
46+ need_temps = false # whether any arg needs temporaries
47+
48+ # First pass: determine if any argument will needs temporaries
49+ for j = 2 : J
50+ exj = ref_ex. args[j]
51+ if isexpr (exj, :... )
52+ need_temps = true
53+ break
54+ end
55+ end
56+
57+ # Second pass: if any need temps, create temps for all args
58+ temp_vars = Tuple{Int,Symbol}[]
59+ for j = 2 : J
60+ n = nx === 0 ? ni : :($ nx + $ ni)
61+ exj, used = replace_ref_begin_end_! (__module__, ref_ex. args[j], (:($ firstindex ($ S,$ n)),:($ lastindex ($ S,$ n))), in_quote_context, escs)
62+ used_S |= used
63+ ref_ex. args[j] = exj
64+ ni += 1
65+ if need_temps
66+ isva = isexpr (exj, :... ) # implied need_temps
67+ if isva
68+ exj = exj. args[1 ]
69+ end
70+ if isa_ast_node (exj) # create temp to preserve evaluation order and count in case `used` gets set later
71+ exj = gensym (:arg )
72+ push! (temp_vars, (j, exj))
73+ end
74+ if isva
75+ ni -= 1
76+ nx = nx === 0 ? :(length ($ exj)) : :($ nx + length ($ exj))
77+ end
78+ end
79+ end
80+
81+ # Third pass: if `used`, need to actually make those temp assignments now
82+ if used_S
83+ for (j, temp_var) in temp_vars
84+ exj = ref_ex. args[j]
85+ isva = isexpr (exj, :... ) # implied need_temps
86+ if isva
87+ exj = exj. args[1 ]
88+ end
89+ push! (assignments, :(local $ temp_var = $ exj))
90+ ref_ex. args[j] = isva ? Expr (:... , temp_var) : temp_var
91+ end
92+ end
93+ end
94+
95+ if used_S
96+ S0 = ref_ex. args[1 ]
97+ S = escapes (S, escs)
98+ ref_ex. args[1 ] = S
99+ main_ex = :(local $ S = $ S0; $ (assignments... ); $ main_ex)
100+ end
101+ return main_ex, used_withex
102+ end
28103 if ex isa Expr && ex. head === :macrocall
29104 # Blithly modifying the arguments to another macro is unwise, so call
30105 # macroexpand first on it.
@@ -46,77 +121,7 @@ function replace_ref_begin_end_!(__module__::Module, ex, withex, in_quote_contex
46121 end
47122 elseif isa (ex,Expr)
48123 if ! in_quote_context && ex. head === :ref # n.b. macroexpand.scm design is incapable of tracking :begin and :end scope, so emulate that here too and ignore escs
49- ex. args[1 ], used_withex = replace_ref_begin_end_! (__module__, ex. args[1 ], withex, in_quote_context, escs)
50- S = gensym (:S ) # temp var to cache ex.args[1] if needed. if S is a global or expression, then it has side effects to use
51- assignments = []
52- used_S = false # whether we actually need S
53- # new :ref, so redefine withex
54- nargs = length (ex. args)- 1
55- if nargs == 0
56- return ex, used_withex
57- elseif nargs == 1
58- # replace with lastindex(S)
59- ex. args[2 ], used_S = replace_ref_begin_end_! (__module__, ex. args[2 ], (:($ firstindex ($ S)),:($ lastindex ($ S))), in_quote_context, escs)
60- else
61- ni = 1
62- nx = 0
63- J = lastindex (ex. args)
64- need_temps = false # whether any arg needs temporaries
65-
66- # First pass: determine if any argument will needs temporaries
67- for j = 2 : J
68- exj = ex. args[j]
69- if isexpr (exj, :... )
70- need_temps = true
71- break
72- end
73- end
74-
75- # Second pass: if any need temps, create temps for all args
76- temp_vars = Tuple{Int,Symbol}[]
77- for j = 2 : J
78- n = nx === 0 ? ni : :($ nx + $ ni)
79- exj, used = replace_ref_begin_end_! (__module__, ex. args[j], (:($ firstindex ($ S,$ n)),:($ lastindex ($ S,$ n))), in_quote_context, escs)
80- used_S |= used
81- ex. args[j] = exj
82- ni += 1
83- if need_temps
84- isva = isexpr (exj, :... ) # implied need_temps
85- if isva
86- exj = exj. args[1 ]
87- end
88- if isa_ast_node (exj) # create temp to preserve evaluation order and count in case `used` gets set later
89- exj = gensym (:arg )
90- push! (temp_vars, (j, exj))
91- end
92- if isva
93- ni -= 1
94- nx = nx === 0 ? :(length ($ exj)) : :($ nx + length ($ exj))
95- end
96- end
97- end
98-
99- # Third pass: if `used`, need to actually make those temp assignments now
100- if used_S
101- for (j, temp_var) in temp_vars
102- exj = ex. args[j]
103- isva = isexpr (exj, :... ) # implied need_temps
104- if isva
105- exj = exj. args[1 ]
106- end
107- push! (assignments, :(local $ temp_var = $ exj))
108- ex. args[j] = isva ? Expr (:... , temp_var) : temp_var
109- end
110- end
111- end
112-
113- if used_S
114- S0 = ex. args[1 ]
115- S = escapes (S, escs)
116- ex. args[1 ] = S
117- ex = :(local $ S = $ S0; $ (assignments... ); $ ex)
118- end
119- return ex, used_withex
124+ return handle_refexpr! (__module__, ex, ex, withex, in_quote_context, escs)
120125 elseif ex. head === :$
121126 # no longer an executable expression (handle all equivalent forms of :inert, :quote, and QuoteNode the same way)
122127 in_quote_context = false
@@ -132,6 +137,18 @@ function replace_ref_begin_end_!(__module__::Module, ex, withex, in_quote_contex
132137 escs -= 1
133138 elseif ex. head === :meta || ex. head === :inert
134139 return ex, used_withex
140+ elseif ! in_quote_context && last (string (ex. head)) == ' =' && Meta. isexpr (ex. args[1 ], :ref )
141+ for i = eachindex (ex. args)
142+ if i == 1
143+ # we'll deal with the ref expression later
144+ continue
145+ end
146+ ex. args[i], used = replace_ref_begin_end_! (__module__, ex. args[i], withex, in_quote_context, escs)
147+ used_withex |= used
148+ end
149+ ex, used = handle_refexpr! (__module__, ex. args[1 ]:: Expr , ex, withex, in_quote_context, escs)
150+ used_withex |= used
151+ return ex, used_withex
135152 end
136153 # recursive search
137154 for i = eachindex (ex. args)
0 commit comments