Skip to content

Commit d0fceca

Browse files
mlechuc42f
andcommitted
Suggestions from code review
Co-authored-by: Claire Foster <[email protected]>
1 parent a3b60ed commit d0fceca

File tree

3 files changed

+391
-345
lines changed

3 files changed

+391
-345
lines changed

src/compat.jl

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
const 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
1010
end
@@ -19,21 +19,21 @@ Expr-producing macros. Always prefer re-parsing source text over using this.
1919
2020
Supports 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
5757
end
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
110110
end
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]
119121
end
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
122130
function 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"))
131139
end
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]))
146144
end
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
493494
end
494495

495496
function _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
505510
end

src/syntax_graph.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,7 @@ function sethead!(graph, id::NodeId, k::Kind)
146146
end
147147

148148
function setflags!(graph, id::NodeId, f::UInt16)
149-
if f != 0
150-
graph.syntax_flags[id] = f
151-
end
149+
graph.syntax_flags[id] = f
152150
end
153151

154152
function _convert_nodes(graph::SyntaxGraph, node::SyntaxNode)

0 commit comments

Comments
 (0)