Skip to content

Commit e12c683

Browse files
update to JuliaSyntax 1.0 (#661)
* update to JuliaSyntax 1.0 * update to JuliaSyntax@1 * fix * Adjust to `nothing` representing no children instead of an empty vector * Import Core: Const to avoid having to qualify Core.Const * Adjust handling of infix operators JuliaSyntax now emits `op=` nodes, with functions as `Identifier` nodes, which are no longer detectable with `is_operator` for e.g. `+` in `a += b` * Fix remaining test failures * Fix UInt/Int discrepancy * More fixes for Cthulhu * Don't attempt to retrieve definition for kwcall from base/boot.jl * Fixes for 32-bit * Minor comment fix * Reapply fix for 32-bit * Bump versions for Cthulhu and TypedSyntax * Try testing on 1.12.0-rc2 * Try on 1.12.0-rc1 * Revert back to testing SnoopCompile on 1.12-nightly --------- Co-authored-by: serenity4 <[email protected]>
1 parent f1490f5 commit e12c683

File tree

10 files changed

+234
-228
lines changed

10 files changed

+234
-228
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
authors = ["Valentin Churavy <[email protected]> and contributors"]
22
name = "Cthulhu"
33
uuid = "f68482b8-f384-11e8-15f7-abe071a5a75f"
4-
version = "2.17.6"
4+
version = "2.17.7"
55

66
[compat]
77
CodeTracking = "0.5, 1, 2"
88
Compiler = "0.1"
99
FoldingTrees = "1"
1010
InteractiveUtils = "1.9"
11-
JuliaSyntax = "0.4"
11+
JuliaSyntax = "1"
1212
PrecompileTools = "1"
1313
Preferences = "1"
1414
REPL = "1.9"

TypedSyntax/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
name = "TypedSyntax"
22
uuid = "d265eb64-f81a-44ad-a842-4247ee1503de"
33
authors = ["Tim Holy <[email protected]> and contributors"]
4-
version = "1.5.0"
4+
version = "1.5.1"
55

66
[deps]
77
CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
88
JuliaSyntax = "70703baa-626e-46a2-a12c-08ffd08c73b4"
99

1010
[compat]
1111
CodeTracking = "1.3, 2"
12-
JuliaSyntax = "0.4"
12+
JuliaSyntax = "1"
1313
julia = "1.12"
1414

1515
[extras]

TypedSyntax/src/TypedSyntax.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module TypedSyntax
22

33
using Core: CodeInfo, MethodInstance, SlotNumber, SSAValue
44
using JuliaSyntax: JuliaSyntax, AbstractSyntaxData, SyntaxData, SyntaxNode, GreenNode, AbstractSyntaxNode, SyntaxHead, SourceFile,
5-
head, kind, child, children, haschildren, untokenize, first_byte, last_byte, source_line, source_location,
5+
head, kind, children, is_leaf, untokenize, first_byte, last_byte, source_line, source_location,
66
sourcetext, @K_str, @KSet_str, is_infix_op_call, is_prefix_op_call, is_prec_assignment, is_operator, is_literal
77
using Base.Meta: isexpr
88
using CodeTracking

TypedSyntax/src/node.jl

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,22 @@ end
8686

8787
# Recursive construction of the TypedSyntaxNode tree from the SyntaxNodeTree
8888
function addchildren!(tparent, parent, src::CodeInfo, node2ssa, symtyps, mappings)
89-
if haschildren(parent) && tparent.children === nothing
90-
tparent.children = TypedSyntaxNode[]
91-
end
92-
for child in children(parent)
93-
tnode = TypedSyntaxNode(tparent, nothing, TypedSyntaxData(child.data::SyntaxData, src, gettyp(node2ssa, child, src)))
94-
if tnode.typ === nothing && (#=is_literal(child) ||=# kind(child) == K"Identifier")
95-
tnode.typ = get(symtyps, child, nothing)
89+
if !is_leaf(parent)
90+
if tparent.children === nothing
91+
tparent.children = TypedSyntaxNode[]
92+
end
93+
for child in children(parent)
94+
typ = gettyp(node2ssa, child, src)
95+
tnode = TypedSyntaxNode(tparent, nothing, TypedSyntaxData(child.data::SyntaxData, src, typ))
96+
if tnode.typ === nothing && (#=is_literal(child) ||=# kind(child) == K"Identifier")
97+
tnode.typ = get(symtyps, child, nothing)
98+
end
99+
push!(tparent, tnode)
100+
addchildren!(tnode, child, src, node2ssa, symtyps, mappings)
96101
end
97-
push!(tparent, tnode)
98-
addchildren!(tnode, child, src, node2ssa, symtyps, mappings)
99102
end
100103
# In `return f(args..)`, copy any types assigned to `f(args...)` up to the `[return]` node
101-
if kind(tparent) == K"return" && haschildren(tparent)
104+
if kind(tparent) == K"return" && !is_leaf(tparent)
102105
childs = children(tparent)
103106
tparent.typ = isempty(childs) ? Nothing : only(childs).typ
104107
end
@@ -121,33 +124,31 @@ function map_signature!(sig::TypedSyntaxNode, slotnames::Vector{Symbol}, slottyp
121124
nchildren = length(children(arg))
122125
nchildren == 1 && return nothing, defaultval
123126
@assert nchildren == 2
124-
arg = child(arg, 1)
127+
arg = arg[1]
125128
end
126129
if kind(arg) == K"$"
127130
return nothing, defaultval
128131
end
129132
if kind(arg) == K"."
130133
arg = last(children(arg))
131-
if kind(arg) == K"inert"
132-
@assert kind(only(children(arg))) == K"$"
133-
return nothing, defaultval
134+
if kind(arg) != K"Identifier"
135+
@assert kind(arg) in KSet"quote $"
136+
arg = only(children(arg))
134137
end
135-
@assert kind(arg) == K"quote"
136-
arg = only(children(arg))
137138
end
138139
if kind(arg) == K"curly"
139140
arg = first(children(arg))
140141
end
141142
if kind(arg) == K"var"
142-
arg = child(arg, 1)
143+
arg = arg[1]
143144
end
144145
kind(arg) == K"tuple" && return nothing, defaultval # FIXME? see extrema2 test
145146
@assert kind(arg) == K"Identifier" || is_operator(arg)
146147
return arg, defaultval
147148
end
148149

149150
while kind(sig) KSet"where ::" # handle MyType{T}(args...) and return-type annotations
150-
sig = child(sig, 1)
151+
sig = sig[1]
151152
end
152153
@assert kind(sig) == K"call"
153154
# First, match named args, since those have to be unique
@@ -241,14 +242,14 @@ function map_signature!(sig::TypedSyntaxNode, slotnames::Vector{Symbol}, slottyp
241242
end
242243
idx == 0 && continue
243244
if kind(arg) == K"::" && length(children(arg)) == 2
244-
arg = child(arg, 1)
245+
arg = arg[1]
245246
end
246247
arg.typ = slottypes[idx]
247248
end
248249

249250
# It's annoying to print the signature as `foo::typeof(foo)(a::Int)`
250251
# Strip the type annotation from the function name
251-
arg, _ = argidentifier(child(sig, 1))
252+
arg, _ = argidentifier(sig[1])
252253
if arg !== nothing
253254
arg.typ = nothing
254255
end
@@ -264,8 +265,8 @@ function striparg(arg)
264265
arg = only(children(arg))
265266
end
266267
if kind(arg) == K"="
267-
defaultval = child(arg, 2)
268-
arg = child(arg, 1)
268+
defaultval = arg[2]
269+
arg = arg[1]
269270
end
270271
if kind(arg) == K"macrocall"
271272
arg = last(children(arg)) # FIXME: is the variable always the final argument?
@@ -351,10 +352,10 @@ end
351352

352353
function is_function_def(node) # this is not `Base.is_function_def`
353354
kind(node) == K"function" && return true
354-
if kind(node) == K"=" && length(children(node)) >= 1
355-
sig = child(node, 1)
355+
if kind(node) == K"=" && !is_leaf(node)
356+
sig = node[1]
356357
while(kind(sig) KSet"where ::") # allow MyType{T}(args...) and return-type annotations
357-
sig = child(sig, 1)
358+
sig = sig[1]
358359
end
359360
kind(sig) == K"call" && return true
360361
end
@@ -366,7 +367,7 @@ function get_function_def(rootnode)
366367
while kind(rootnode) KSet"macrocall global local const"
367368
idx = findlast(node -> is_function_def(node) || kind(node) == K"macrocall", children(rootnode))
368369
idx === nothing && break
369-
rootnode = child(rootnode, idx)
370+
rootnode = rootnode[idx]
370371
end
371372
return rootnode
372373
end
@@ -375,7 +376,7 @@ function num_positional_args(tsn::AbstractSyntaxNode)
375376
TypedSyntax.is_function_def(tsn) || return 0
376377
sig, _ = children(tsn)
377378
while kind(sig) KSet"where ::"
378-
sig = child(sig, 1)
379+
sig = sig[1]
379380
end
380381
@assert kind(sig) == K"call"
381382
for (i, node) in enumerate(children(sig))
@@ -392,7 +393,7 @@ function collect_symbol_nodes(rootnode)
392393
rootnode = get_function_def(rootnode)
393394
is_function_def(rootnode) || error("expected function definition, got ", sourcetext(rootnode))
394395
symlocs = Dict{Any,Vector{typeof(rootnode)}}()
395-
return collect_symbol_nodes!(symlocs, child(rootnode, 2))
396+
return collect_symbol_nodes!(symlocs, rootnode[2])
396397
end
397398

398399
function collect_symbol_nodes!(symlocs::AbstractDict, node)
@@ -409,10 +410,10 @@ function collect_symbol_nodes!(symlocs::AbstractDict, node)
409410
locs = get!(Vector{typeof(node)}, symlocs, node.val)
410411
push!(locs, node)
411412
end
412-
if haschildren(node)
413+
if !is_leaf(node)
413414
if kind(node) == K"do"
414415
# process only `g(args...)` in `g(args...) do ... end`
415-
collect_symbol_nodes!(symlocs, child(node, 1))
416+
collect_symbol_nodes!(symlocs, node[1])
416417
elseif kind(node) == K"generator"
417418
for c in Iterators.drop(children(node), 1)
418419
collect_symbol_nodes!(symlocs, c)
@@ -560,7 +561,7 @@ function map_ssas_to_source(src::CodeInfo, mi::MethodInstance, rootnode::SyntaxN
560561
argnode = p
561562
p = argnode.parent::MaybeTypedSyntaxNode
562563
end
563-
is_prec_assignment(p) && argnode == child(p, 1 + is_rhs) # is it the correct side of an assignment?
564+
is_prec_assignment(p) && argnode == p[1 + is_rhs] # is it the correct side of an assignment?
564565
end
565566
return targets
566567
end
@@ -719,7 +720,7 @@ function map_ssas_to_source(src::CodeInfo, mi::MethodInstance, rootnode::SyntaxN
719720
while !is_prec_assignment(lhsnode) && (lhsparent = lhsnode.parent; lhsparent !== nothing)
720721
lhsnode = lhsparent
721722
end
722-
lhsnode, found = find_identifier_or_tuplechild(child(lhsnode, 1), sym)
723+
lhsnode, found = find_identifier_or_tuplechild(lhsnode[1], sym)
723724
if found
724725
symtyps[lhsnode] = ssavaluetypes[i]
725726
end
@@ -750,7 +751,7 @@ function map_ssas_to_source(src::CodeInfo, mi::MethodInstance, rootnode::SyntaxN
750751
for t in itr
751752
haskey(symtyps, t) && continue
752753
if skipped_parent(t) == node
753-
is_prec_assignment(node) && t == child(node, 1) && continue
754+
is_prec_assignment(node) && t == node[1] && continue
754755
symtyps[t] = if j > 0
755756
ssavaluetypes[j]
756757
elseif have_slottypes
@@ -861,6 +862,7 @@ function skipped_parent(node::SyntaxNode)
861862
pnode = node.parent
862863
pnode === nothing && return node
863864
ppnode = pnode.parent
865+
kind(pnode) == K"in" && kind(ppnode) == K"iteration" && return ppnode
864866
if ppnode !== nothing && kind(pnode) KSet"... quote" # might need to add more things here
865867
if kind(node) == K"Identifier" && kind(pnode) == K"quote" && kind(ppnode) == K"." && sourcetext(node) == "materialize"
866868
return ppnode.parent

TypedSyntax/src/show.jl

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ function JuliaSyntax._show_syntax_node(io, current_filename, node::TypedSyntaxNo
1212
posstr *= "$(lpad(first_byte(node),6)):$(rpad(last_byte(node),6))"
1313
end
1414
val = node.val
15-
nodestr = haschildren(node) ? "[$(untokenize(head(node)))]" :
15+
nodestr = !is_leaf(node) ? "[$(untokenize(head(node)))]" :
1616
isa(val, Symbol) ? string(val) : repr(val)
1717
treestr = string(indent, nodestr)
1818
if node.typ !== nothing
1919
treestr = string(rpad(treestr, 40), "$(node.typ)")
2020
end
2121
println(io, posstr, treestr)
22-
if haschildren(node)
22+
if !is_leaf(node)
2323
new_indent = indent*" "
2424
for n in children(node)
2525
JuliaSyntax._show_syntax_node(io, current_filename, n, new_indent, show_byte_offsets)
@@ -36,7 +36,7 @@ function Base.printstyled(io::IO, rootnode::MaybeTypedSyntaxNode;
3636
rt = gettyp(rootnode)
3737
nd = with_linenumber ? ndigits_linenumbers(rootnode, idxend) : 0
3838
rootnode = get_function_def(rootnode)
39-
position = first_byte(rootnode) - 1
39+
position = Int(first_byte(rootnode) - 1)
4040
with_linenumber && print_linenumber(io, rootnode, position + 1, nd)
4141
if is_function_def(rootnode)
4242
# We're printing a MethodInstance
@@ -66,21 +66,18 @@ end
6666
function show_src_expr(io::IO, node::MaybeTypedSyntaxNode, position::Int, pre::String, pre2::String; type_annotations::Bool=true, iswarn::Bool=false, hide_type_stable::Bool=false, nd::Int)
6767
_lastidx = last_byte(node)
6868
position = catchup(io, node, position, nd)
69-
if haschildren(node)
70-
cs = children(node)
71-
if !isempty(cs) # `haschildren(node)` returns `true` as long as the node has the *capacity* to store children
72-
position = catchup(io, first(children(node)), position, nd)
73-
end
69+
if !is_leaf(node)
70+
position = catchup(io, first(children(node)), position, nd)
7471
end
7572
_print(io, pre, node.source, position)
76-
for (i, child) in enumerate(children(node))
73+
!is_leaf(node) && for (i, child) in enumerate(children(node))
7774
i == 2 && _print(io, pre2, node.source, position)
7875
cT = gettyp(child)
7976
ctype_annotate, cpre, cpre2, cpost = type_annotation_mode(child, cT; type_annotations, hide_type_stable)
8077
position = show_src_expr(io, child, position, cpre, cpre2; type_annotations, iswarn, hide_type_stable, nd)
8178
ctype_annotate && show_annotation(io, cT, cpost, node.source, position; iswarn)
8279
end
83-
return Int(catchup(io, node, position, nd, _lastidx+1))
80+
return catchup(io, node, position, nd, _lastidx+1)
8481
end
8582

8683
# should we print a type-annotation?
@@ -106,14 +103,17 @@ function is_callfunc(node::MaybeTypedSyntaxNode, @nospecialize(T))
106103
thisnode = pnode
107104
pnode = pnode.parent
108105
end
109-
if pnode !== nothing && kind(pnode) (K"call", K"curly") && ((is_infix_op_call(pnode) && is_operator(thisnode)) || thisnode === pnode.children[1])
110-
if isa(T, Core.Const)
111-
T = T.val
112-
end
113-
if isa(T, Type) || isa(T, Function)
114-
T === Colon() && sourcetext(node) == ":" && return true
115-
return is_type_transparent(node, T)
116-
end
106+
pnode === nothing && return false
107+
is_in_infix_context = kind(pnode) == K"op=" || kind(pnode) == K"call" && is_infix_op_call(pnode)
108+
is_caller_function = kind(pnode) == K"call" && thisnode === pnode.children[1]
109+
is_parametrized_type = kind(pnode) == K"curly" && thisnode === pnode.children[1]
110+
is_in_infix_context || is_caller_function || is_parametrized_type || return false
111+
if isa(T, Core.Const)
112+
T = T.val
113+
end
114+
if isa(T, Type) || isa(T, Function)
115+
T === Colon() && sourcetext(node) == ":" && return true
116+
return is_type_transparent(node, T)
117117
end
118118
return false
119119
end
@@ -173,15 +173,15 @@ print_linenumber(io::IO, ln::Int, nd::Int) = printstyled(io, lpad(ln, nd), " ";
173173

174174
# Do any "overdue" printing, generating a line number if needed. Mostly, this catches whitespace.
175175
# Printing occurs over indexes from `position:stop-1`.
176-
function catchup(io::IO, node::MaybeTypedSyntaxNode, position::Int, nd::Int, stop = first_byte(node))
176+
function catchup(io::IO, node::MaybeTypedSyntaxNode, position::Int, nd::Int, stop = Int(first_byte(node)))
177177
if position + 1 < stop
178178
for (i, c) in pairs(node.source[position+1:stop-1])
179179
print(io, c)
180180
if c == '\n' && nd > 0
181181
print_linenumber(io, node, position + i + 1, nd)
182182
end
183183
end
184-
position = stop - 1
184+
position = Int(stop - 1)
185185
end
186186
return position
187187
end

TypedSyntax/test/exhaustive.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const goodmis = Core.MethodInstance[]
1414
m = mi.def::Method
1515
isdefined(m, :generator) && continue # code_typed can't handle this
1616
m missingmethods && continue # we tried before and couldn't find the source text
17+
m.name === :kwcall && mi.specTypes.parameters[3] === Type{Union{}} && continue # skip kwcall definition in base/boot.jl
1718
cis = Base.code_typed_by_type(mi.specTypes; debuginfo=:source, optimize=false)
1819
if length(cis) == 1
1920
src, rt = cis[1]

0 commit comments

Comments
 (0)