1
1
# -------------------------------------------------------------------------------
2
2
# AST interface, built on top of raw tree
3
3
4
- """
5
- Design options:
6
- * rust-analyzer treats their version of an untyped syntax node as a cursor into
7
- the green tree. They deallocate aggressively.
8
- """
9
- mutable struct SyntaxNode
4
+ abstract type AbstractSyntaxData end
5
+
6
+ mutable struct TreeNode{NodeData} # ? prevent others from using this with NodeData <: AbstractSyntaxData?
7
+ parent:: Union{Nothing,TreeNode{NodeData}}
8
+ children:: Union{Nothing,Vector{TreeNode{NodeData}}}
9
+ data:: Union{Nothing,NodeData}
10
+ end
11
+
12
+ # Implement "pass-through" semantics for field access: access fields of `data`
13
+ # as if they were part of `TreeNode`
14
+ function Base. getproperty (node:: TreeNode , name:: Symbol )
15
+ name === :parent && return getfield (node, :parent )
16
+ name === :children && return getfield (node, :children )
17
+ d = getfield (node, :data )
18
+ name === :data && return d
19
+ return getproperty (d, name)
20
+ end
21
+
22
+ function Base. setproperty! (node:: TreeNode , name:: Symbol , x)
23
+ name === :parent && return setfield! (node, :parent , x)
24
+ name === :children && return setfield! (node, :children , x)
25
+ name === :data && return setfield! (node, :data , x)
26
+ d = getfield (node, :data )
27
+ return setfield! (d, name, x)
28
+ end
29
+
30
+ const AbstractSyntaxNode = TreeNode{<: AbstractSyntaxData }
31
+
32
+ struct SyntaxData <: AbstractSyntaxData
10
33
source:: SourceFile
11
34
raw:: GreenNode{SyntaxHead}
12
35
position:: Int
13
- parent:: Union{Nothing,SyntaxNode}
14
- is_leaf:: Bool
15
36
val:: Any
16
37
end
17
38
39
+ const SyntaxNode = TreeNode{SyntaxData}
40
+
18
41
# Value of an error node with no children
19
42
struct ErrorVal
20
43
end
@@ -106,7 +129,7 @@ function SyntaxNode(source::SourceFile, raw::GreenNode{SyntaxHead}, position::In
106
129
@debug " Leaf node of kind $k unknown to SyntaxNode"
107
130
ErrorVal ()
108
131
end
109
- return SyntaxNode (source, raw, position, nothing , true , val)
132
+ return SyntaxNode (nothing , nothing , SyntaxData (source, raw, position , val) )
110
133
else
111
134
cs = SyntaxNode[]
112
135
pos = position
@@ -117,30 +140,31 @@ function SyntaxNode(source::SourceFile, raw::GreenNode{SyntaxHead}, position::In
117
140
end
118
141
pos += rawchild. span
119
142
end
120
- node = SyntaxNode (source, raw, position, nothing , false , cs )
143
+ node = SyntaxNode (nothing , cs, SyntaxData (source, raw, position, nothing ) )
121
144
for c in cs
122
145
c. parent = node
123
146
end
124
147
return node
125
148
end
126
149
end
127
150
128
- head (node:: SyntaxNode ) = head (node. raw)
151
+ haschildren (node:: TreeNode ) = node. children != = nothing
152
+ children (node:: TreeNode ) = (c = node. children; return c === nothing ? () : c)
153
+
129
154
130
- haschildren (node:: SyntaxNode ) = ! node. is_leaf
131
- children (node:: SyntaxNode ) = haschildren (node) ? node. val:: Vector{SyntaxNode} : ()
155
+ head (node:: SyntaxNode ) = head (node. raw)
132
156
133
157
span (node:: SyntaxNode ) = span (node. raw)
134
158
135
- first_byte (node:: SyntaxNode ) = node. position
136
- last_byte (node:: SyntaxNode ) = node. position + span (node) - 1
159
+ first_byte (node:: AbstractSyntaxNode ) = node. position
160
+ last_byte (node:: AbstractSyntaxNode ) = node. position + span (node) - 1
137
161
138
162
"""
139
163
sourcetext(node)
140
164
141
165
Get the full source text of a node.
142
166
"""
143
- function sourcetext (node:: SyntaxNode )
167
+ function sourcetext (node:: AbstractSyntaxNode )
144
168
val_range = (node. position- 1 ) .+ (1 : span (node))
145
169
view (node. source, val_range)
146
170
end
@@ -150,7 +174,7 @@ function interpolate_literal(node::SyntaxNode, val)
150
174
SyntaxNode (node. source, node. raw, node. position, node. parent, true , val)
151
175
end
152
176
153
- function _show_syntax_node (io, current_filename, node:: SyntaxNode , indent)
177
+ function _show_syntax_node (io, current_filename, node:: AbstractSyntaxNode , indent)
154
178
fname = node. source. filename
155
179
line, col = source_location (node. source, node. position)
156
180
posstr = " $(lpad (line, 4 )) :$(rpad (col,3 )) │$(lpad (first_byte (node),6 )) :$(rpad (last_byte (node),6 )) │"
@@ -173,7 +197,7 @@ function _show_syntax_node(io, current_filename, node::SyntaxNode, indent)
173
197
end
174
198
end
175
199
176
- function _show_syntax_node_sexpr (io, node:: SyntaxNode )
200
+ function _show_syntax_node_sexpr (io, node:: AbstractSyntaxNode )
177
201
if ! haschildren (node)
178
202
if is_error (node)
179
203
print (io, " (" , untokenize (head (node)), " )" )
@@ -193,24 +217,24 @@ function _show_syntax_node_sexpr(io, node::SyntaxNode)
193
217
end
194
218
end
195
219
196
- function Base. show (io:: IO , :: MIME"text/plain" , node:: SyntaxNode )
220
+ function Base. show (io:: IO , :: MIME"text/plain" , node:: AbstractSyntaxNode )
197
221
println (io, " line:col│ byte_range │ tree │ file_name" )
198
222
_show_syntax_node (io, Ref {Union{Nothing,String}} (nothing ), node, " " )
199
223
end
200
224
201
- function Base. show (io:: IO , :: MIME"text/x.sexpression" , node:: SyntaxNode )
225
+ function Base. show (io:: IO , :: MIME"text/x.sexpression" , node:: AbstractSyntaxNode )
202
226
_show_syntax_node_sexpr (io, node)
203
227
end
204
228
205
- function Base. show (io:: IO , node:: SyntaxNode )
229
+ function Base. show (io:: IO , node:: AbstractSyntaxNode )
206
230
_show_syntax_node_sexpr (io, node)
207
231
end
208
232
209
- function Base. push! (node:: SyntaxNode , child:: SyntaxNode )
233
+ function Base. push! (node:: SN , child:: SN ) where SN <: AbstractSyntaxNode
210
234
if ! haschildren (node)
211
235
error (" Cannot add children" )
212
236
end
213
- args = node. val :: Vector{SyntaxNode}
237
+ args = children ( node)
214
238
push! (args, child)
215
239
end
216
240
239
263
240
264
function setchild! (node:: SyntaxNode , path, x)
241
265
n1 = child (node, path[1 : end - 1 ]. .. )
242
- n1. val [path[end ]] = x
266
+ n1. children [path[end ]] = x
243
267
end
244
268
245
269
# We can overload multidimensional Base.getindex / Base.setindex! for node
0 commit comments