@@ -34,7 +34,7 @@ function expr_to_syntaxtree(ctx, @nospecialize(e), lnn::Union{LineNumberNode, No
3434 toplevel_src = if isnothing (lnn)
3535 # Provenance sinkhole for all nodes until we hit a linenode
3636 dummy_src = SourceRef (
37- SourceFile (" No source for expression: $e " ),
37+ SourceFile (" No source for expression" ),
3838 1 , JS. GreenNode (K " None" , 0 ))
3939 _insert_tree_node (graph, K " None" , dummy_src)
4040 else
@@ -91,29 +91,34 @@ function collect_expr_parameters(e::Expr, pos::Int)
9191 args = Any[e. args[1 : pos- 1 ]. .. , e. args[pos+ 1 : end ]. .. ]
9292 return _flatten_params! (args, params)
9393end
94- function _flatten_params! (out:: Vector{Any} , p:: Expr )
94+ function _flatten_params! (out:: Vector{Any} , params:: Expr )
95+ p,p_esc = unwrap_esc (params)
9596 p1 = expr_parameters (p, 1 )
9697 if ! isnothing (p1)
97- push! (out, Expr (:parameters , p. args[2 : end ]. .. ))
98- _flatten_params! (out, p1 )
98+ push! (out, p_esc ( Expr (:parameters , p. args[2 : end ]. .. ) ))
99+ _flatten_params! (out, p_esc (p1) )
99100 else
100- push! (out, p :: Any )
101+ push! (out, params :: Any )
101102 end
102103 return out
103104end
104105function expr_parameters (p:: Expr , pos:: Int )
105- if length (p. args) >= pos &&
106- p. args[pos] isa Expr &&
107- p. args[pos]. head === :parameters
108- return p. args[pos]
106+ if pos <= length (p. args)
107+ e,_ = unwrap_esc (p. args[pos])
108+ if e isa Expr && e. head === :parameters
109+ return p. args[pos]
110+ end
109111 end
110112 return nothing
111113end
112114
113115"""
114116If `b` (usually a block) has exactly one non-LineNumberNode argument, unwrap it.
115117"""
116- function maybe_unwrap_arg (b:: Expr )
118+ function maybe_unwrap_arg (b)
119+ if ! (b isa Expr)
120+ return b
121+ end
117122 e1 = findfirst (c -> ! isa (c, LineNumberNode), b. args)
118123 isnothing (e1) && return b
119124 e2 = findfirst (c -> ! isa (c, LineNumberNode), b. args[e1+ 1 : end ])
@@ -122,7 +127,7 @@ function maybe_unwrap_arg(b::Expr)
122127end
123128
124129function maybe_extract_lnn (b, default)
125- ! (b isa Expr) && return b
130+ ! (b isa Expr) && return default
126131 lnn_i = findfirst (a-> isa (a, LineNumberNode), b. args)
127132 return isnothing (lnn_i) ? default : b. args[lnn_i]
128133end
141146
142147function is_eventually_call (e)
143148 return e isa Expr && (e. head === :call ||
144- e. head in (:where , :(:: )) && is_eventually_call (e. args[1 ]))
149+ e. head in (:escape , :where , :(:: )) && is_eventually_call (e. args[1 ]))
150+ end
151+
152+ function rewrap_escapes (hyg, ex)
153+ if hyg isa Expr && hyg. head in (:escape , :var"hygienic-scope" )
154+ ex = Expr (hyg. head, rewrap_escapes (hyg. args[1 ], ex))
155+ if hyg. head === :var"hygienic-scope"
156+ append! (ex. args, @view hyg. args[2 : end ])
157+ end
158+ end
159+ return ex
160+ end
161+
162+ # Unwrap Expr(:escape) and Expr(:hygienic-scope). Return the unwrapped
163+ # expression and a function which will rewrap a derived expression in the
164+ # correct hygiene wrapper.
165+ function unwrap_esc (ex)
166+ orig_ex = ex
167+ while ex isa Expr && ex. head in (:escape , :var"hygienic-scope" )
168+ @assert length (ex. args) >= 1
169+ ex = ex. args[1 ]
170+ end
171+ return ex, e-> rewrap_escapes (orig_ex, e)
172+ end
173+
174+ function unwrap_esc_ (e)
175+ unwrap_esc (e)[1 ]
145176end
146177
147178"""
@@ -212,59 +243,61 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
212243 child_exprs = Any[e. args[1 ], Symbol (op), e. args[2 ]]
213244 elseif e. head === :comparison
214245 for i = 2 : 2 : length (child_exprs)
215- op = child_exprs[i]
246+ op,op_esc = unwrap_esc ( child_exprs[i])
216247 @assert op isa Symbol
217248 op_s = string (op)
218249 if is_dotted_operator (op_s)
219- child_exprs[i] = Expr (:., Symbol (op_s[2 : end ]))
250+ child_exprs[i] = Expr (:., op_esc ( Symbol (op_s[2 : end ]) ))
220251 end
221252 end
222253 elseif e. head === :macrocall
223254 @assert nargs >= 2
224- a1 = e. args[1 ]
255+ a1,a1_esc = unwrap_esc ( e. args[1 ])
225256 child_exprs = collect_expr_parameters (e, 3 )
226257 if child_exprs[2 ] isa LineNumberNode
227258 src = child_exprs[2 ]
228259 end
229260 deleteat! (child_exprs, 2 )
230261 if a1 isa Symbol
231- child_exprs[1 ] = Expr (:MacroName , a1)
232- elseif a1 isa Expr && a1. head === :(.) && a1. args[2 ] isa QuoteNode
233- child_exprs[1 ] = Expr (:(.), a1. args[1 ], Expr (:MacroName , a1. args[2 ]. value))
234- elseif a1 isa GlobalRef
262+ child_exprs[1 ] = a1_esc (Expr (:MacroName , a1))
263+ elseif a1 isa Expr && a1. head === :(.)
264+ a12,a12_esc = unwrap_esc (a1. args[2 ])
265+ if a12 isa QuoteNode
266+ child_exprs[1 ] = a1_esc (Expr (:(.), a1. args[1 ],
267+ Expr (:MacroName , a12_esc (a12. value))))
268+ end
269+ elseif a1 isa GlobalRef && a1. mod === Core
235270 # TODO (maybe): syntax-introduced macrocalls are listed here for
236271 # reference. We probably don't need to convert these.
237272 if a1. name === Symbol (" @cmd" )
238273 elseif a1. name === Symbol (" @doc" )
274+ st_k = K " doc"
275+ child_exprs = child_exprs[2 : end ]
239276 elseif a1. name === Symbol (" @int128_str" )
240277 elseif a1. name === Symbol (" @int128_str" )
241278 elseif a1. name === Symbol (" @big_str" )
242279 end
243- elseif a1 isa Function
244- # pass
245- else
246- error (" Unknown macrocall form at $src : $(sprint (dump, e)) " )
247- @assert false
248280 end
249281 elseif e. head === Symbol (" '" )
250282 @assert nargs === 1
251283 st_k = K " call"
252284 child_exprs = Any[e. head, e. args[1 ]]
253285 elseif e. head === :. && nargs === 2
254- a2 = e. args[2 ]
286+ a2, a2_esc = unwrap_esc ( e. args[2 ])
255287 if a2 isa Expr && a2. head === :tuple
256288 st_k = K " dotcall"
257- tuple_exprs = collect_expr_parameters (a2 , 1 )
289+ tuple_exprs = collect_expr_parameters (a2_esc (a2) , 1 )
258290 child_exprs = pushfirst! (tuple_exprs, e. args[1 ])
259291 elseif a2 isa QuoteNode
260- child_exprs[2 ] = a2. value
292+ child_exprs[2 ] = a2_esc ( a2. value)
261293 end
262294 elseif e. head === :for
263295 @assert nargs === 2
264296 child_exprs = Any[_to_iterspec (Any[e. args[1 ]], false ), e. args[2 ]]
265297 elseif e. head === :where
266298 @assert nargs >= 2
267- if ! (e. args[2 ] isa Expr && e. args[2 ]. head === :braces )
299+ e2,_ = unwrap_esc (e. args[2 ])
300+ if ! (e2 isa Expr && e2. head === :braces )
268301 child_exprs = Any[e. args[1 ], Expr (:braces , e. args[2 : end ]. .. )]
269302 end
270303 elseif e. head in (:tuple , :vect , :braces )
@@ -281,18 +314,19 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
281314 # [catch var (block ...)]
282315 # [else (block ...)]
283316 # [finally (block ...)])
284- if e. args[2 ] != false || e. args[3 ] != false
317+ e2 = unwrap_esc_ (e. args[2 ])
318+ e3 = unwrap_esc_ (e. args[3 ])
319+ if e2 != = false || e3 != = false
285320 push! (child_exprs,
286321 Expr (:catch ,
287- e . args[ 2 ] === false ? Expr (:catch_var_placeholder ) : e. args[2 ],
288- e . args[ 3 ] === false ? nothing : e. args[3 ]))
322+ e2 === false ? Expr (:catch_var_placeholder ) : e. args[2 ],
323+ e3 === false ? nothing : e. args[3 ]))
289324 end
290325 if nargs >= 5
291326 push! (child_exprs, Expr (:else , e. args[5 ]))
292327 end
293- if nargs >= 4
294- push! (child_exprs,
295- Expr (:finally , e. args[4 ] === false ? nothing : e. args[4 ]))
328+ if nargs >= 4 && unwrap_esc_ (e. args[4 ]) != = false
329+ push! (child_exprs, Expr (:finally , e. args[4 ]))
296330 end
297331 elseif e. head === :flatten || e. head === :generator
298332 st_k = K " generator"
@@ -307,36 +341,37 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
307341 push! (child_exprs, _to_iterspec (next. args[2 : end ], true ))
308342 pushfirst! (child_exprs, next. args[1 ])
309343 elseif e. head === :ncat || e. head === :nrow
310- dim = popfirst! (child_exprs)
344+ dim = unwrap_esc_ ( popfirst! (child_exprs) )
311345 st_flags |= JS. set_numeric_flags (dim)
312346 elseif e. head === :typed_ncat
313- st_flags |= JS. set_numeric_flags (e. args[2 ])
347+ st_flags |= JS. set_numeric_flags (unwrap_esc_ ( e. args[2 ]) )
314348 deleteat! (child_exprs, 2 )
315349 elseif e. head === :(-> )
316350 @assert nargs === 2
317- if e. args[1 ] isa Expr && e. args[1 ]. head === :block
351+ a1, a1_esc = unwrap_esc (e. args[1 ])
352+ if a1 isa Expr && a1. head === :block
318353 # Expr parsing fails to make :parameters here...
319354 lam_args = Any[]
320355 lam_eqs = Any[]
321- for a in e . args[ 1 ] . args
356+ for a in a1 . args
322357 a isa Expr && a. head === :(= ) ? push! (lam_eqs, a) : push! (lam_args, a)
323358 end
324359 ! isempty (lam_eqs) && push! (lam_args, Expr (:parameters , lam_eqs... ))
325- child_exprs[1 ] = Expr (:tuple , lam_args... )
326- elseif ! (e . args[ 1 ] isa Expr && (e . args[ 1 ] . head in (:tuple , :where )))
327- child_exprs[1 ] = Expr (:tuple , e . args[ 1 ] )
360+ child_exprs[1 ] = a1_esc ( Expr (:tuple , lam_args... ) )
361+ elseif ! (a1 isa Expr && (a1 . head in (:tuple , :where )))
362+ child_exprs[1 ] = a1_esc ( Expr (:tuple , a1) )
328363 end
329364 src = maybe_extract_lnn (e. args[2 ], src)
330365 child_exprs[2 ] = maybe_unwrap_arg (e. args[2 ])
331366 elseif e. head === :call
332367 child_exprs = collect_expr_parameters (e, 2 )
333- a1 = child_exprs[1 ]
368+ a1,a1_esc = unwrap_esc ( child_exprs[1 ])
334369 if a1 isa Symbol
335370 a1s = string (a1)
336371 if is_dotted_operator (a1s)
337372 # non-assigning dotop like .+ or .==
338373 st_k = K " dotcall"
339- child_exprs[1 ] = Symbol (a1s[2 : end ])
374+ child_exprs[1 ] = a1_esc ( Symbol (a1s[2 : end ]) )
340375 end
341376 end
342377 elseif e. head === :function
@@ -362,17 +397,20 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
362397 # SyntaxTree:
363398 # (call f args... (do (tuple lam_args...) (block ...)))
364399 callargs = collect_expr_parameters (e. args[1 ], 2 )
365- fname = string (callargs[1 ])
366400 if e. args[1 ]. head === :macrocall
367401 st_k = K " macrocall"
368- callargs[1 ] = Expr (:MacroName , callargs[1 ])
402+ c1,c1_esc = unwrap_esc (callargs[1 ])
403+ callargs[1 ] = c1_esc (Expr (:MacroName , c1))
369404 else
370405 st_k = K " call"
371406 end
372407 child_exprs = Any[callargs... , Expr (:do_lambda , e. args[2 ]. args... )]
373408 elseif e. head === :let
374- if nargs >= 1 && ! (e. args[1 ] isa Expr && e. args[1 ]. head === :block )
375- child_exprs[1 ] = Expr (:block , e. args[1 ])
409+ if nargs >= 1
410+ a1,_ = unwrap_esc (e. args[1 ])
411+ if ! (a1 isa Expr && a1. head === :block )
412+ child_exprs[1 ] = Expr (:block , e. args[1 ])
413+ end
376414 end
377415 elseif e. head === :struct
378416 e. args[1 ] && (st_flags |= JS. MUTABLE_FLAG)
@@ -404,6 +442,12 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
404442 st_k = K " latestworld_if_toplevel"
405443 elseif e. head === Symbol (" hygienic-scope" )
406444 st_k = K " hygienic_scope"
445+ elseif e. head === :escape
446+ if length (e. args) == 1 && unwrap_esc_ (e. args[1 ]) isa LineNumberNode
447+ # escape containing only a LineNumberNode will become empty and
448+ # thus must be removed before lowering sees it.
449+ st_k = K " TOMBSTONE"
450+ end
407451 elseif e. head === :meta
408452 # Messy and undocumented. Only sometimes we want a K"meta".
409453 @assert e. args[1 ] isa Symbol
@@ -490,10 +534,12 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
490534 end
491535
492536 # ---------------------------------------------------------------------------
493- # Throw if this script isn't complete. Finally, insert a new node into the
537+ # Throw if this function isn't complete. Finally, insert a new node into the
494538 # graph and recurse on child_exprs
495539 if st_k === K " None"
496540 error (" Unknown expr head at $src : `$(e. head) `\n $(sprint (dump, e)) " )
541+ elseif st_k === K " TOMBSTONE"
542+ return nothing , src
497543 end
498544
499545 st_id = _insert_tree_node (graph, st_k, src, st_flags; st_attrs... )
@@ -503,7 +549,6 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
503549 if isnothing (child_exprs)
504550 return st_id, src
505551 else
506- setflags! (graph, st_id, st_flags)
507552 st_child_ids, last_src = _insert_child_exprs (child_exprs, graph, src)
508553 setchildren! (graph, st_id, st_child_ids)
509554 return st_id, last_src
@@ -519,7 +564,9 @@ function _insert_child_exprs(child_exprs::Vector{Any}, graph::SyntaxGraph,
519564 last_src = c
520565 else
521566 (c_id, c_src) = _insert_convert_expr (c, graph, last_src)
522- push! (st_child_ids, c_id)
567+ if ! isnothing (c_id)
568+ push! (st_child_ids, c_id)
569+ end
523570 last_src = something (c_src, src)
524571 end
525572 end
0 commit comments