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,17 +19,17 @@ 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 (
@@ -39,7 +39,7 @@ function expr_to_syntaxtree(@nospecialize(e),
3939 else
4040 lnn
4141 end
42- st_id, _ = _insert_convert_expr (e, graph, toplevel_src)
42+ st_id = _insert_convert_expr (e, graph, toplevel_src)
4343 out = SyntaxTree (graph, st_id)
4444 return out
4545end
@@ -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"""
@@ -157,15 +155,10 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
157155 # Non-expr types
158156 if isnothing (e)
159157 st_id = _insert_tree_node (graph, K " core" , src; name_val= " nothing" )
160- return st_id, src
158+ return st_id
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
166- return st_id, src
167- elseif e isa LineNumberNode
168- return nothing , e
161+ return st_id
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,23 +168,24 @@ 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])
181- return st_id, src
174+ return st_id
182175 elseif ! (e isa Expr)
183176 # There are other kinds we could potentially back-convert (e.g. Float),
184177 # but Value should work fine.
185178 st_k = e isa Integer ? K " Integer" : find_kind (string (typeof (e)))
186179 st_id = _insert_tree_node (graph, isnothing (st_k) ? K " Value" : st_k, src; value= e)
187- return st_id, src
180+ return st_id
188181 end
189182
190183 # ---------------------------------------------------------------------------
191184 # `e` is an expr. In many cases, it suffices to
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
@@ -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 ]]), 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 )
@@ -311,8 +309,8 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
311309 push! (child_exprs, _to_iterspec (next. args[2 : end ]))
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.
@@ -411,13 +415,13 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
411415 # Kick the can down the road (should only be simple atoms?)
412416 child_exprs = map (c-> Expr (:meta , :nospecialize , c), child_exprs[2 : end ])
413417 else
414- st_id, src = _insert_convert_expr (e. args[2 ], graph, src)
418+ st_id = _insert_convert_expr (e. args[2 ], graph, src)
415419 setmeta! (SyntaxTree (graph, st_id); nospecialize= true )
416- return st_id, src
420+ return st_id
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
460- return st_id, src
462+ return st_id
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
@@ -482,24 +484,25 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA
482484 # child_exprs === nothing means we want a leaf. Note that setchildren! with
483485 # an empty list makes a node non-leaf.
484486 if isnothing (child_exprs)
485- return st_id, src
487+ return st_id
486488 else
487- st_flags |= JS. NON_TERMINAL_FLAG
488489 setflags! (graph, st_id, st_flags)
489- st_child_ids, last_src = _insert_child_expr (child_exprs, graph, src)
490+ st_child_ids = _insert_child_expr (child_exprs, graph, src)
490491 setchildren! (graph, st_id, st_child_ids)
491- return st_id, last_src
492+ return st_id
492493 end
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+ push! (st_child_ids, _insert_convert_expr (c, graph, last_src))
505+ end
503506 end
504- return st_child_ids, last_src
507+ return st_child_ids
505508end
0 commit comments