11const JS = JuliaSyntax
22
3- function _insert_tree_node (graph:: SyntaxGraph , k:: JS. Kind , src:: SourceAttrType ,
3+ function _insert_tree_node (graph:: SyntaxGraph , k:: Kind , src:: SourceAttrType ,
44 flags:: UInt16 = 0x0000 ; attrs... )
55 id = newnode! (graph)
66 sethead! (graph, id, k)
7- setflags! (graph, id, flags)
7+ flags != = 0 && setflags! (graph, id, flags)
88 setattr! (graph, id; source= src, attrs... )
99 return id
1010end
@@ -19,21 +19,21 @@ Expr-producing macros. Always prefer re-parsing source text over using this.
1919
2020Supports parsed and/or macro-expanded exprs, but not lowered exprs
2121"""
22- function expr_to_syntaxtree (@nospecialize (e),
23- lnn :: Union{LineNumberNode, Nothing} = nothing ,
24- ctx = nothing )
25- graph = if isnothing (ctx)
26- ensure_attributes! ( SyntaxGraph () ,
27- kind = Kind, syntax_flags = UInt16,
28- source = SourceAttrType, var_id = Int, value = Any,
29- name_val = String, is_toplevel_thunk = Bool)
30- else
31- syntax_graph (ctx )
32- end
22+ function expr_to_syntaxtree (@nospecialize (e), lnn :: Union{LineNumberNode, Nothing} = nothing )
23+ graph = ensure_attributes! (
24+ SyntaxGraph (),
25+ kind = Kind, syntax_flags = UInt16,
26+ source = SourceAttrType, var_id = Int, value = Any ,
27+ name_val = String, is_toplevel_thunk = Bool)
28+ expr_to_syntaxtree (graph, e, lnn)
29+ end
30+
31+ function expr_to_syntaxtree (ctx, @nospecialize (e), lnn :: Union{LineNumberNode, Nothing} )
32+ graph = syntax_graph (ctx)
3333 toplevel_src = if isnothing (lnn)
3434 # Provenance sinkhole for all nodes until we hit a linenode
3535 dummy_src = SourceRef (
36- SourceFile (" No source for expression $e " ),
36+ SourceFile (" No source for expression: $e " ),
3737 1 , JS. GreenNode (K " None" , 0 ))
3838 _insert_tree_node (graph, K " None" , dummy_src)
3939 else
@@ -56,14 +56,14 @@ function _expr_replace!(@nospecialize(e), replace_pred::Function, replacer!::Fun
5656 end
5757end
5858
59- function _to_iterspec (exs:: Vector )
59+ function _to_iterspec (exs:: Vector , is_generator :: Bool )
6060 if length (exs) === 1 && exs[1 ]. head === :filter
6161 @assert length (exs[1 ]. args) >= 2
62- return Expr (:filter , _to_iterspec (exs[1 ]. args[2 : end ]), exs[1 ]. args[1 ])
62+ return Expr (:filter , _to_iterspec (exs[1 ]. args[2 : end ], true ), exs[1 ]. args[1 ])
6363 end
6464 outex = Expr (:iteration )
6565 for e in exs
66- if e. head === :block
66+ if e. head === :block && ! is_generator
6767 for iter in e. args
6868 push! (outex. args, Expr (:in , iter. args... ))
6969 end
@@ -109,15 +109,23 @@ function expr_parameters(p::Expr, pos::Int)
109109 return nothing
110110end
111111
112- " Unwrap (usually block) if it has only one non-linenode child"
113- function maybe_strip_block (b:: Expr )
112+ """
113+ If `b` (usually a block) has exactly one non-LineNumberNode argument, unwrap it.
114+ """
115+ function maybe_unwrap_arg (b:: Expr )
114116 e1 = findfirst (c -> ! isa (c, LineNumberNode), b. args)
115117 isnothing (e1) && return b
116118 e2 = findfirst (c -> ! isa (c, LineNumberNode), b. args[e1+ 1 : end ])
117119 ! isnothing (e2) && return b
118120 return b. args[e1]
119121end
120122
123+ function maybe_extract_lnn (b, default)
124+ ! (b isa Expr) && return b
125+ lnn_i = findfirst (a-> isa (a, LineNumberNode), b. args)
126+ return isnothing (lnn_i) ? default : b. args[lnn_i]
127+ end
128+
121129# Get kind by string if exists. TODO relies on internals
122130function find_kind (s:: String )
123131 out = get (JS. _kind_str_to_int, s, nothing )
@@ -130,19 +138,9 @@ function is_dotted_operator(s::AbstractString)
130138 JS. is_operator (something (find_kind (s[2 : end ]), K " None" ))
131139end
132140
133- # Expr doesn't record whether or not var"x" was used on x, so just assume one
134- # was used for any invalid identifier, but lose the information otherwise.
135- function _insert_var_str (child:: NodeId , graph:: SyntaxGraph , src:: SourceAttrType )
136- var_id = _insert_tree_node (graph, K " var" , src)
137- setchildren! (graph, var_id, [child])
138- setflags! (graph, child, JS. RAW_STRING_FLAG)
139- setflags! (graph, var_id, JS. NON_TERMINAL_FLAG)
140- return (var_id, src)
141- end
142-
143- function is_call_expr (e)
141+ function is_eventually_call (e)
144142 return e isa Expr && (e. head === :call ||
145- e. head in (:where , :(:: )) && is_call_expr (e. args[1 ]))
143+ e. head in (:where , :(:: )) && is_eventually_call (e. args[1 ]))
146144end
147145
148146"""
@@ -160,12 +158,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
160158 return st_id, src
161159 elseif e isa Symbol
162160 st_id = _insert_tree_node (graph, K " Identifier" , src; name_val= String (e))
163- if ! Base. isoperator (e) && ! Base. is_valid_identifier (e)
164- return _insert_var_str (st_id, graph, src)
165- end
166161 return st_id, src
167- elseif e isa LineNumberNode
168- return nothing , e
169162 elseif e isa QuoteNode && e. value isa Symbol
170163 # Undo special handling from st->expr
171164 return _insert_convert_expr (Expr (:quote , e. value), graph, src)
@@ -175,7 +168,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
175168 # setchildren!(graph, st_id, NodeId[quote_child])
176169 # return st_id, src
177170 elseif e isa String
178- st_id = _insert_tree_node (graph, K " string" , src, JS . NON_TERMINAL_FLAG )
171+ st_id = _insert_tree_node (graph, K " string" , src)
179172 id_inner = _insert_tree_node (graph, K " String" , src; value= e)
180173 setchildren! (graph, st_id, [id_inner])
181174 return st_id, src
@@ -192,6 +185,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
192185 # - guess that the kind name is the same as the expr head
193186 # - add no syntax flags or attrs
194187 # - map e.args to syntax tree children one-to-one
188+ e:: Expr
195189 nargs = length (e. args)
196190 maybe_kind = find_kind (string (e. head))
197191 st_k = isnothing (maybe_kind) ? K " None" : maybe_kind
@@ -200,8 +194,8 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
200194 # Note that SyntaxTree/Node differentiate 0-child non-terminals and leaves
201195 child_exprs:: Union{Nothing, Vector{Any}} = copy (e. args)
202196
203- # However, the following are (many) special cases where the kind, flags, or
204- # children are different from what we guessed above
197+ # However, the following are (many) special cases where the kind, flags,
198+ # children, or attributes are different from what we guessed above
205199 if Base. isoperator (e. head) && st_k === K " None"
206200 # e.head is an updating assignment operator (+=, .-=, etc). Non-=
207201 # dotted ops are wrapped in a call, so we don't reach this.
@@ -214,7 +208,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
214208 st_k = K " op="
215209 op = s[1 : end - 1 ]
216210 end
217- child_exprs = [e. args[1 ], Symbol (op), e. args[2 ]]
211+ child_exprs = Any [e. args[1 ], Symbol (op), e. args[2 ]]
218212 elseif e. head === :comparison
219213 for i = 2 : 2 : length (child_exprs)
220214 op = child_exprs[i]
@@ -228,7 +222,9 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
228222 @assert nargs >= 2
229223 a1 = e. args[1 ]
230224 child_exprs = collect_expr_parameters (e, 3 )
231- # macrocall has a linenode "argument" here. should we set src?
225+ if child_exprs[2 ] isa LineNumberNode
226+ src = child_exprs[2 ]
227+ end
232228 deleteat! (child_exprs, 2 )
233229 if a1 isa Symbol
234230 child_exprs[1 ] = Expr (:MacroName , a1)
@@ -244,13 +240,15 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
244240 elseif a1. name === Symbol (" @big_str" )
245241 end
246242 elseif a1 isa Function
243+ # pass
247244 else
248245 error (" Unknown macrocall form $(sprint (dump, e)) " )
246+ @assert false
249247 end
250248 elseif e. head === Symbol (" '" )
251249 @assert nargs === 1
252250 st_k = K " call"
253- child_exprs = [e. head, e. args[1 ]]
251+ child_exprs = Any [e. head, e. args[1 ]]
254252 elseif e. head === :. && nargs === 2
255253 a2 = e. args[2 ]
256254 if a2 isa Expr && a2. head === :tuple
@@ -265,11 +263,11 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
265263 end
266264 elseif e. head === :for
267265 @assert nargs === 2
268- child_exprs = Expr [_to_iterspec (Any[e. args[1 ]]), e. args[2 ]]
266+ child_exprs = Any [_to_iterspec (Any[e. args[1 ]], false ), e. args[2 ]]
269267 elseif e. head === :where
270268 @assert nargs >= 2
271269 if ! (e. args[2 ] isa Expr && e. args[2 ]. head === :braces )
272- child_exprs = [e. args[1 ], Expr (:braces , e. args[2 : end ]. .. )]
270+ child_exprs = Any [e. args[1 ], Expr (:braces , e. args[2 : end ]. .. )]
273271 end
274272 elseif e. head in (:tuple , :vect , :braces )
275273 child_exprs = collect_expr_parameters (e, 1 )
@@ -304,15 +302,15 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
304302 next = e
305303 while next. head === :flatten
306304 @assert next. args[1 ]. head === :generator
307- push! (child_exprs, _to_iterspec (next. args[1 ]. args[2 : end ]))
305+ push! (child_exprs, _to_iterspec (next. args[1 ]. args[2 : end ], true ))
308306 next = next. args[1 ]. args[1 ]
309307 end
310308 @assert next. head === :generator
311- push! (child_exprs, _to_iterspec (next. args[2 : end ]))
309+ push! (child_exprs, _to_iterspec (next. args[2 : end ], true ))
312310 pushfirst! (child_exprs, next. args[1 ])
313311 elseif e. head === :ncat || e. head === :nrow
314- st_flags |= JS . set_numeric_flags (e . args[ 1 ] )
315- child_exprs = child_exprs[ 2 : end ]
312+ dim = popfirst! (child_exprs )
313+ st_flags |= JS . set_numeric_flags (dim)
316314 elseif e. head === :typed_ncat
317315 st_flags |= JS. set_numeric_flags (e. args[2 ])
318316 deleteat! (child_exprs, 2 )
@@ -330,7 +328,8 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
330328 elseif ! (e. args[1 ] isa Expr && (e. args[1 ]. head in (:tuple , :where )))
331329 child_exprs[1 ] = Expr (:tuple , e. args[1 ])
332330 end
333- child_exprs[2 ] = maybe_strip_block (e. args[2 ])
331+ src = maybe_extract_lnn (e. args[2 ], src)
332+ child_exprs[2 ] = maybe_unwrap_arg (e. args[2 ])
334333 elseif e. head === :call
335334 child_exprs = collect_expr_parameters (e, 2 )
336335 a1 = child_exprs[1 ]
@@ -342,32 +341,37 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
342341 child_exprs[1 ] = Symbol (a1s[2 : end ])
343342 end
344343 end
344+ elseif e. head === :function
345+ if nargs >= 2
346+ src = maybe_extract_lnn (e. args[2 ], src)
347+ end
345348 elseif e. head === :(= )
346- if is_call_expr (e. args[1 ])
349+ if is_eventually_call (e. args[1 ])
347350 st_k = K " function"
348351 st_flags |= JS. SHORT_FORM_FUNCTION_FLAG
349- child_exprs[2 ] = maybe_strip_block (child_exprs[2 ])
352+ src = maybe_extract_lnn (e. args[2 ], src)
353+ child_exprs[2 ] = maybe_unwrap_arg (e. args[2 ])
350354 end
351355 elseif e. head === :module
352356 @assert nargs === 3
353357 if ! e. args[1 ]
354358 st_flags |= JS. BARE_MODULE_FLAG
355359 end
356- child_exprs = [e. args[2 ], e. args[3 ]]
360+ child_exprs = Any [e. args[2 ], e. args[3 ]]
357361 elseif e. head === :do
358362 # Expr:
359363 # (do (call f args...) (-> (tuple lam_args...) (block ...)))
360364 # SyntaxTree:
361365 # (call f args... (do (tuple lam_args...) (block ...)))
362366 callargs = collect_expr_parameters (e. args[1 ], 2 )
363367 fname = string (callargs[1 ])
364- if fname [1 ] === ' @ '
368+ if e . args [1 ]. head === :macrocall
365369 st_k = K " macrocall"
366370 callargs[1 ] = Expr (:MacroName , callargs[1 ])
367371 else
368372 st_k = K " call"
369373 end
370- child_exprs = [callargs... , Expr (:do_lambda , e. args[2 ]. args... )]
374+ child_exprs = Any [callargs... , Expr (:do_lambda , e. args[2 ]. args... )]
371375 elseif e. head === :let
372376 if nargs >= 1 && ! (e. args[1 ] isa Expr && e. args[1 ]. head === :block )
373377 child_exprs[1 ] = Expr (:block , e. args[1 ])
@@ -384,7 +388,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
384388 st_k = K " ="
385389 elseif e. head in (:local , :global ) && nargs > 1
386390 # Possible normalization
387- # child_exprs = [Expr(:tuple, child_exprs...)]
391+ # child_exprs = Any [Expr(:tuple, child_exprs...)]
388392 elseif e. head === :error
389393 # Zero-child errors from parsing are leaf nodes. We could change this
390394 # upstream for consistency.
@@ -417,7 +421,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
417421 end
418422 else
419423 @assert nargs === 1
420- child_exprs[1 ] = Expr (:sym_not_identifier , e. args[1 ])
424+ child_exprs[1 ] = Expr (:quoted_symbol , e. args[1 ])
421425 end
422426 elseif e. head === :symbolicgoto || e. head === :symboliclabel
423427 @assert nargs === 1
@@ -427,15 +431,16 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
427431 elseif e. head === :inline || e. head === :noinline
428432 @assert nargs === 1 && e. args[1 ] isa Bool
429433 # TODO : JuliaLowering doesn't accept this (non-:meta) form yet
430- return nothing , src
434+ st_k = K " TOMBSTONE"
435+ child_exprs = nothing
431436 elseif e. head === :core
432437 @assert nargs === 1
433438 @assert e. args[1 ] isa Symbol
434439 st_attrs[:name_val ] = string (e. args[1 ])
435440 child_exprs = nothing
436441 elseif e. head === :islocal || e. head === :isglobal
437442 st_k = K " extension"
438- child_exprs = [Expr (:sym_not_identifier , e. head), e. args[1 ]]
443+ child_exprs = [Expr (:quoted_symbol , e. head), e. args[1 ]]
439444 elseif e. head === :block && nargs >= 1 &&
440445 e. args[1 ] isa Expr && e. args[1 ]. head === :softscope
441446 # (block (softscope true) ex) produced with every REPL prompt.
@@ -454,15 +459,12 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
454459 mac_name = string (e. args[1 ])
455460 mac_name = mac_name == " @__dot__" ? " @." : mac_name
456461 st_id = _insert_tree_node (graph, K " MacroName" , src, st_flags; name_val= mac_name)
457- if ! Base. is_valid_identifier (mac_name[2 : end ])
458- return _insert_var_str (st_id, graph, src)
459- end
460462 return st_id, src
461463 elseif e. head === :catch_var_placeholder
462464 st_k = K " Placeholder"
463465 st_attrs[:name_val ] = " "
464466 child_exprs = nothing
465- elseif e. head === :sym_not_identifier
467+ elseif e. head === :quoted_symbol
466468 st_k = K " Symbol"
467469 st_attrs[:name_val ] = String (e. args[1 ])
468470 child_exprs = nothing
@@ -484,7 +486,6 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
484486 if isnothing (child_exprs)
485487 return st_id, src
486488 else
487- st_flags |= JS. NON_TERMINAL_FLAG
488489 setflags! (graph, st_id, st_flags)
489490 st_child_ids, last_src = _insert_child_expr (child_exprs, graph, src)
490491 setchildren! (graph, st_id, st_child_ids)
@@ -493,13 +494,17 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
493494end
494495
495496function _insert_child_expr (child_exprs:: Vector{Any} , graph:: SyntaxGraph ,
496- src:: SourceAttrType )
497+ src:: SourceAttrType )
497498 st_child_ids = NodeId[]
498499 last_src = src
499500 for c in child_exprs
500- (c_id, c_src) = _insert_convert_expr (c, graph, last_src)
501- isnothing (c_id) || push! (st_child_ids, c_id)
502- last_src = something (c_src, src)
501+ if c isa LineNumberNode
502+ last_src = c
503+ else
504+ (c_id, c_src) = _insert_convert_expr (c, graph, last_src)
505+ push! (st_child_ids, c_id)
506+ last_src = something (c_src, src)
507+ end
503508 end
504509 return st_child_ids, last_src
505510end
0 commit comments