@@ -333,25 +333,32 @@ should transform to
333333 A[B[endof(B)]]
334334
335335"""
336- function replace_ref_end! (ex,withex= nothing )
336+ replace_ref_end! (ex) = replace_ref_end_! (ex, nothing )[1 ]
337+ # replace_ref_end_!(ex,withex) returns (new ex, whether withex was used)
338+ function replace_ref_end_! (ex, withex)
339+ used_withex = false
337340 if isa (ex,Symbol) && ex == :end
338341 withex === nothing && error (" Invalid use of end" )
339- return withex
342+ return withex, true
340343 elseif isa (ex,Expr)
341344 if ex. head == :ref
342- S = ex. args[1 ] = replace_ref_end! (ex. args[1 ],withex)
345+ ex. args[1 ], used_withex = replace_ref_end_! (ex. args[1 ],withex)
346+ S = isa (ex. args[1 ],Symbol) ? ex. args[1 ]:: Symbol : gensym (:S ) # temp var to cache ex.args[1] if needed
347+ used_S = false # whether we actually need S
343348 # new :ref, so redefine withex
344349 nargs = length (ex. args)- 1
345350 if nargs == 0
346- return ex
351+ return ex, used_withex
347352 elseif nargs == 1
348353 # replace with endof(S)
349- ex. args[2 ] = replace_ref_end ! (ex. args[2 ],:(Base . endof ($ S)))
354+ ex. args[2 ], used_S = replace_ref_end_ ! (ex. args[2 ],:($ endof ($ S)))
350355 else
351356 n = 1
352357 J = endof (ex. args)
353358 for j = 2 : J- 1
354- exj = ex. args[j] = replace_ref_end! (ex. args[j],:(Base. size ($ S,$ n)))
359+ exj, used = replace_ref_end_! (ex. args[j],:($ size ($ S,$ n)))
360+ used_S |= used
361+ ex. args[j] = exj
355362 if isa (exj,Expr) && exj. head == :...
356363 # splatted object
357364 exjs = exj. args[1 ]
@@ -364,16 +371,23 @@ function replace_ref_end!(ex,withex=nothing)
364371 n += 1
365372 end
366373 end
367- ex. args[J] = replace_ref_end! (ex. args[J],:(Base. trailingsize ($ S,$ n)))
374+ ex. args[J], used = replace_ref_end_! (ex. args[J],:($ trailingsize ($ S,$ n)))
375+ used_S |= used
376+ end
377+ if used_S && S != = ex. args[1 ]
378+ S0 = ex. args[1 ]
379+ ex. args[1 ] = S
380+ ex = Expr (:let , ex, :($ S = $ S0))
368381 end
369382 else
370383 # recursive search
371384 for i = eachindex (ex. args)
372- ex. args[i] = replace_ref_end! (ex. args[i],withex)
385+ ex. args[i], used = replace_ref_end_! (ex. args[i],withex)
386+ used_withex |= used
373387 end
374388 end
375389 end
376- ex
390+ ex, used_withex
377391end
378392
379393"""
@@ -385,9 +399,15 @@ an assignment (e.g. `@view(A[1,2:end]) = ...`). See also [`@views`](@ref)
385399to switch an entire block of code to use views for slicing.
386400"""
387401macro view (ex)
388- if isa (ex, Expr) && ex . head == :ref
402+ if Meta . isexpr (ex, :ref )
389403 ex = replace_ref_end! (ex)
390- Expr (:&& , true , esc (Expr (:call ,:(Base. view),ex. args... )))
404+ if Meta. isexpr (ex, :ref )
405+ ex = Expr (:call , view, ex. args... )
406+ else # ex replaced by let ...; foo[...]; end
407+ assert (Meta. isexpr (ex, :let ) && Meta. isexpr (ex. args[1 ], :ref ))
408+ ex. args[1 ] = Expr (:call , view, ex. args[1 ]. args... )
409+ end
410+ Expr (:&& , true , esc (ex))
391411 else
392412 throw (ArgumentError (" Invalid use of @view macro: argument must be a reference expression A[...]." ))
393413 end
0 commit comments