Skip to content

Commit acd8238

Browse files
committed
Add the visitor method on reflection
1 parent 3ae6cf4 commit acd8238

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

Diff for: lib/syntax_tree/reflection.rb

+17-3
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,13 @@ def initialize(name, comment)
138138
# as a placeholder for collecting all of the various places that nodes are
139139
# used.
140140
class Node
141-
attr_reader :name, :comment, :attributes
141+
attr_reader :name, :comment, :attributes, :visitor_method
142142

143-
def initialize(name, comment, attributes)
143+
def initialize(name, comment, attributes, visitor_method)
144144
@name = name
145145
@comment = comment
146146
@attributes = attributes
147+
@visitor_method = visitor_method
147148
end
148149
end
149150

@@ -196,6 +197,10 @@ def parse_comments(statements, index)
196197
Attribute.new(:location, "[Location] the location of this node")
197198
}
198199

200+
# This is the name of the method tha gets called on the given visitor when
201+
# the accept method is called on this node.
202+
visitor_method = nil
203+
199204
statements = main_statement.bodystmt.statements.body
200205
statements.each_with_index do |statement, statement_index|
201206
case statement
@@ -225,16 +230,25 @@ def parse_comments(statements, index)
225230
end
226231

227232
attributes[attribute.name] = attribute
233+
when SyntaxTree::DefNode
234+
if statement.name.value == "accept"
235+
call_node = statement.bodystmt.statements.body.first
236+
visitor_method = call_node.message.value.to_sym
237+
end
228238
end
229239
end
230240

241+
# If we never found a visitor method, then we have an error.
242+
raise if visitor_method.nil?
243+
231244
# Finally, set it up in the hash of nodes so that we can use it later.
232245
comments = parse_comments(main_statements, main_statement_index)
233246
node =
234247
Node.new(
235248
main_statement.constant.constant.value.to_sym,
236249
"#{comments.join("\n")}\n",
237-
attributes
250+
attributes,
251+
visitor_method
238252
)
239253

240254
@nodes[node.name] = node

Diff for: tasks/sorbet.rake

+52
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@ module SyntaxTree
2020
generate_parent
2121
Reflection.nodes.sort.each { |(_, node)| generate_node(node) }
2222

23+
body << ClassDeclaration(
24+
ConstPathRef(VarRef(Const("SyntaxTree")), Const("BasicVisitor")),
25+
nil,
26+
BodyStmt(
27+
Statements(generate_visitor("overridable")), nil, nil, nil, nil
28+
),
29+
location
30+
)
31+
32+
body << ClassDeclaration(
33+
ConstPathRef(VarRef(Const("SyntaxTree")), Const("Visitor")),
34+
ConstPathRef(VarRef(Const("SyntaxTree")), Const("BasicVisitor")),
35+
BodyStmt(Statements(generate_visitor("override")), nil, nil, nil, nil),
36+
location
37+
)
38+
2339
Formatter.format(nil, Program(Statements(body)))
2440
end
2541

@@ -228,6 +244,42 @@ module SyntaxTree
228244
)
229245
end
230246

247+
def generate_visitor(override)
248+
body = []
249+
250+
Reflection.nodes.each do |name, node|
251+
body << sig_block do
252+
CallNode(
253+
CallNode(
254+
Ident(override),
255+
Period("."),
256+
sig_params do
257+
BareAssocHash([
258+
Assoc(Label("node:"),
259+
sig_type_for(SyntaxTree.const_get(name)))
260+
])
261+
end,
262+
nil
263+
),
264+
Period("."),
265+
sig_returns do
266+
CallNode(VarRef(Const("T")), Period("."), Ident("untyped"), nil)
267+
end,
268+
nil
269+
)
270+
end
271+
272+
body << generate_def_node(node.visitor_method, Paren(
273+
LParen("("),
274+
Params.new(requireds: [Ident("node")], location: location)
275+
))
276+
277+
@line += 2
278+
end
279+
280+
body
281+
end
282+
231283
def sig_block
232284
MethodAddBlock(
233285
CallNode(nil, nil, Ident("sig"), nil),

0 commit comments

Comments
 (0)