diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index b146c6b4..b41cbc0a 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -58,27 +58,8 @@ class Node # [Location] the location of this node attr_reader :location - def self.inherited(child) - child.class_eval(<<~EOS, __FILE__, __LINE__ + 1) - def accept(visitor) - visitor.#{child.visit_method_name}(self) - end - EOS - - Visitor.class_eval(<<~EOS, __FILE__, __LINE__ + 1) - def #{child.visit_method_name}(node) - visit_all(node.child_nodes) - end - EOS - end - - def self.visit_method_name - method_suffix = name.split("::").last - method_suffix.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2') - method_suffix.gsub!(/([a-z\d])([A-Z])/, '\1_\2') - method_suffix.tr!("-", "_") - method_suffix.downcase! - "visit_#{method_suffix}" + def accept(visitor) + raise NotImplementedError end def child_nodes @@ -132,6 +113,10 @@ def initialize(lbrace:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_BEGIN(self) + end + def child_nodes [lbrace, statements] end @@ -201,6 +186,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_CHAR(self) + end + def child_nodes [] end @@ -265,6 +254,10 @@ def initialize(lbrace:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_END(self) + end + def child_nodes [lbrace, statements] end @@ -337,6 +330,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit___end__(self) + end + def child_nodes [] end @@ -426,6 +423,10 @@ def initialize(left:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_alias(self) + end + def child_nodes [left, right] end @@ -507,6 +508,10 @@ def initialize(collection:, index:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_aref(self) + end + def child_nodes [collection, index] end @@ -588,6 +593,10 @@ def initialize(collection:, index:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_aref_field(self) + end + def child_nodes [collection, index] end @@ -670,6 +679,10 @@ def initialize(arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_arg_paren(self) + end + def child_nodes [arguments] end @@ -734,6 +747,10 @@ def initialize(parts:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_args(self) + end + def child_nodes parts end @@ -783,6 +800,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_arg_block(self) + end + def child_nodes [value] end @@ -835,6 +856,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_arg_star(self) + end + def child_nodes [value] end @@ -898,6 +923,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_args_forward(self) + end + def child_nodes [] end @@ -1027,6 +1056,10 @@ def initialize(lbracket:, contents:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_array(self) + end + def child_nodes [lbracket, contents] end @@ -1199,6 +1232,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_aryptn(self) + end + def child_nodes [constant, *requireds, rest, *posts] end @@ -1326,6 +1363,10 @@ def initialize(target:, value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_assign(self) + end + def child_nodes [target, value] end @@ -1408,6 +1449,10 @@ def initialize(key:, value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_assoc(self) + end + def child_nodes [key, value] end @@ -1488,6 +1533,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_assoc_splat(self) + end + def child_nodes [value] end @@ -1542,6 +1591,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_backref(self) + end + def child_nodes [] end @@ -1590,6 +1643,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_backtick(self) + end + def child_nodes [] end @@ -1704,6 +1761,10 @@ def initialize(assocs:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_bare_assoc_hash(self) + end + def child_nodes assocs end @@ -1762,6 +1823,10 @@ def initialize(bodystmt:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_begin(self) + end + def child_nodes [bodystmt] end @@ -1826,6 +1891,10 @@ def initialize(statement:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_pinned_begin(self) + end + def child_nodes [statement] end @@ -1871,7 +1940,6 @@ def to_json(*opts) end end - # Binary represents any expression that involves two sub-expressions with an # operator in between. This can be something that looks like a mathematical # operation: @@ -1903,6 +1971,10 @@ def initialize(left:, operator:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_binary(self) + end + def child_nodes [left, right] end @@ -2036,6 +2108,10 @@ def initialize(params:, locals:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_block_var(self) + end + def child_nodes [params, *locals] end @@ -2102,6 +2178,10 @@ def initialize(name:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_block_arg(self) + end + def child_nodes [name] end @@ -2203,6 +2283,10 @@ def empty? statements.empty? && !rescue_clause && !else_clause && !ensure_clause end + def accept(visitor) + visitor.visit_bodystmt(self) + end + def child_nodes [statements, rescue_clause, else_clause, ensure_clause] end @@ -2472,6 +2556,10 @@ def initialize(lbrace:, block_var:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_brace_block(self) + end + def child_nodes [lbrace, block_var, statements] end @@ -2592,6 +2680,10 @@ def initialize(arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_break(self) + end + def child_nodes [arguments] end @@ -2683,6 +2775,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_call(self) + end + def child_nodes [ receiver, @@ -2800,6 +2896,10 @@ def initialize(keyword:, value:, consequent:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_case(self) + end + def child_nodes [keyword, value, consequent] end @@ -2890,6 +2990,10 @@ def initialize(value:, operator:, pattern:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_rassign(self) + end + def child_nodes [value, operator, pattern] end @@ -3003,6 +3107,10 @@ def initialize(constant:, superclass:, bodystmt:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_class(self) + end + def child_nodes [constant, superclass, bodystmt] end @@ -3089,6 +3197,10 @@ class Comma < Node # [String] the comma in the string attr_reader :value + def accept(visitor) + visitor.visit_comma(self) + end + def initialize(value:, location:) @value = value @location = location @@ -3118,6 +3230,10 @@ def initialize(message:, arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_command(self) + end + def child_nodes [message, arguments] end @@ -3203,6 +3319,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_command_call(self) + end + def child_nodes [receiver, message, arguments] end @@ -3382,6 +3502,10 @@ def comments [] end + def accept(visitor) + visitor.visit_comment(self) + end + def child_nodes [] end @@ -3442,6 +3566,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_const(self) + end + def child_nodes [] end @@ -3497,6 +3625,10 @@ def initialize(parent:, constant:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_const_path_field(self) + end + def child_nodes [parent, constant] end @@ -3564,6 +3696,10 @@ def initialize(parent:, constant:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_const_path_ref(self) + end + def child_nodes [parent, constant] end @@ -3629,6 +3765,10 @@ def initialize(constant:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_const_ref(self) + end + def child_nodes [constant] end @@ -3681,6 +3821,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_cvar(self) + end + def child_nodes [] end @@ -3738,6 +3882,10 @@ def initialize(name:, params:, bodystmt:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_def(self) + end + def child_nodes [name, params, bodystmt] end @@ -3844,6 +3992,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_def_endless(self) + end + def child_nodes [target, operator, name, paren, statement] end @@ -3946,6 +4098,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_defined(self) + end + def child_nodes [value] end @@ -4025,6 +4181,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_defs(self) + end + def child_nodes [target, operator, name, params, bodystmt] end @@ -4129,6 +4289,10 @@ def initialize(keyword:, block_var:, bodystmt:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_do_block(self) + end + def child_nodes [keyword, block_var, bodystmt] end @@ -4232,6 +4396,10 @@ def initialize(left:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_dot2(self) + end + def child_nodes [left, right] end @@ -4304,6 +4472,10 @@ def initialize(left:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_dot3(self) + end + def child_nodes [left, right] end @@ -4415,6 +4587,10 @@ def initialize(parts:, quote:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_dyna_symbol(self) + end + def child_nodes parts end @@ -4523,6 +4699,10 @@ def initialize(statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_else(self) + end + def child_nodes [statements] end @@ -4597,6 +4777,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_elsif(self) + end + def child_nodes [predicate, statements, consequent] end @@ -4695,6 +4879,10 @@ def comments [] end + def accept(visitor) + visitor.visit_embdoc(self) + end + def child_nodes [] end @@ -4734,6 +4922,10 @@ class EmbExprBeg < Node # [String] the #{ used in the string attr_reader :value + def accept(visitor) + visitor.visit_embexpr_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -4750,6 +4942,10 @@ class EmbExprEnd < Node # [String] the } used in the string attr_reader :value + def accept(visitor) + visitor.visit_embexpr_end(self) + end + def initialize(value:, location:) @value = value @location = location @@ -4768,6 +4964,10 @@ class EmbVar < Node # [String] the # used in the string attr_reader :value + def accept(visitor) + visitor.visit_embvar(self) + end + def initialize(value:, location:) @value = value @location = location @@ -4798,6 +4998,10 @@ def initialize(keyword:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_ensure(self) + end + def child_nodes [keyword, statements] end @@ -4869,6 +5073,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_excessed_comma(self) + end + def child_nodes [] end @@ -4928,6 +5136,10 @@ def initialize(value:, arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_fcall(self) + end + def child_nodes [value, arguments] end @@ -5001,6 +5213,10 @@ def initialize(parent:, operator:, name:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_field(self) + end + def child_nodes [parent, (operator if operator != :"::"), name] end @@ -5071,6 +5287,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_float(self) + end + def child_nodes [] end @@ -5136,6 +5356,10 @@ def initialize(constant:, left:, values:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_fndptn(self) + end + def child_nodes [constant, left, *values, right] end @@ -5230,6 +5454,10 @@ def initialize(index:, collection:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_for(self) + end + def child_nodes [index, collection, statements] end @@ -5311,6 +5539,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_gvar(self) + end + def child_nodes [] end @@ -5364,6 +5596,10 @@ def initialize(lbrace:, assocs:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_hash(self) + end + def child_nodes [lbrace] + assocs end @@ -5452,6 +5688,10 @@ def initialize(beginning:, ending: nil, parts: [], location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_heredoc(self) + end + def child_nodes [beginning, *parts] end @@ -5542,6 +5782,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_heredoc_beg(self) + end + def child_nodes [] end @@ -5650,6 +5894,10 @@ def initialize(constant:, keywords:, keyword_rest:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_hshptn(self) + end + def child_nodes [constant, *keywords.flatten(1), keyword_rest] end @@ -5757,6 +6005,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_ident(self) + end + def child_nodes [] end @@ -5902,6 +6154,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_if(self) + end + def child_nodes [predicate, statements, consequent] end @@ -5978,6 +6234,10 @@ def initialize(predicate:, truthy:, falsy:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_if_op(self) + end + def child_nodes [predicate, truthy, falsy] end @@ -6140,6 +6400,10 @@ def initialize(statement:, predicate:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_if_mod(self) + end + def child_nodes [statement, predicate] end @@ -6201,6 +6465,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_imaginary(self) + end + def child_nodes [] end @@ -6261,6 +6529,10 @@ def initialize(pattern:, statements:, consequent:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_in(self) + end + def child_nodes [pattern, statements, consequent] end @@ -6346,6 +6618,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_int(self) + end + def child_nodes [] end @@ -6401,6 +6677,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_ivar(self) + end + def child_nodes [] end @@ -6459,6 +6739,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_kw(self) + end + def child_nodes [] end @@ -6507,6 +6791,10 @@ def initialize(name:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_kwrest_param(self) + end + def child_nodes [name] end @@ -6569,6 +6857,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_label(self) + end + def child_nodes [] end @@ -6613,6 +6905,10 @@ class LabelEnd < Node # [String] the end of the label attr_reader :value + def accept(visitor) + visitor.visit_label_end(self) + end + def initialize(value:, location:) @value = value @location = location @@ -6640,6 +6936,10 @@ def initialize(params:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_lambda(self) + end + def child_nodes [params, statements] end @@ -6729,6 +7029,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_lbrace(self) + end + def child_nodes [] end @@ -6775,6 +7079,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_lbracket(self) + end + def child_nodes [] end @@ -6821,6 +7129,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_lparen(self) + end + def child_nodes [] end @@ -6884,6 +7196,10 @@ def initialize(target:, value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_massign(self) + end + def child_nodes [target, value] end @@ -6951,6 +7267,10 @@ def initialize(call:, block:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_method_add_block(self) + end + def child_nodes [call, block] end @@ -7016,6 +7336,10 @@ def initialize(parts:, comma: false, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_mlhs(self) + end + def child_nodes parts end @@ -7071,6 +7395,10 @@ def initialize(contents:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_mlhs_paren(self) + end + def child_nodes [contents] end @@ -7141,6 +7469,10 @@ def initialize(constant:, bodystmt:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_module(self) + end + def child_nodes [constant, bodystmt] end @@ -7228,6 +7560,10 @@ def initialize(parts:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_mrhs(self) + end + def child_nodes parts end @@ -7290,6 +7626,10 @@ def initialize(arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_next(self) + end + def child_nodes [arguments] end @@ -7340,6 +7680,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_op(self) + end + def child_nodes [] end @@ -7397,6 +7741,10 @@ def initialize(target:, operator:, value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_op_assign(self) + end + def child_nodes [target, operator, value] end @@ -7647,6 +7995,10 @@ def empty? keywords.empty? && !keyword_rest && !block end + def accept(visitor) + visitor.visit_params(self) + end + def child_nodes [ *requireds, @@ -7812,6 +8164,10 @@ def initialize(lparen:, contents:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_paren(self) + end + def child_nodes [lparen, contents] end @@ -7880,6 +8236,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_period(self) + end + def child_nodes [] end @@ -7926,6 +8286,10 @@ def initialize(statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_program(self) + end + def child_nodes [statements] end @@ -7988,6 +8352,10 @@ def initialize(beginning:, elements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_qsymbols(self) + end + def child_nodes [] end @@ -8054,6 +8422,10 @@ class QSymbolsBeg < Node # [String] the beginning of the array literal attr_reader :value + def accept(visitor) + visitor.visit_qsymbols_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8081,6 +8453,10 @@ def initialize(beginning:, elements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_qwords(self) + end + def child_nodes [] end @@ -8144,6 +8520,10 @@ class QWordsBeg < Node # [String] the beginning of the array literal attr_reader :value + def accept(visitor) + visitor.visit_qwords_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8167,6 +8547,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_rational(self) + end + def child_nodes [] end @@ -8204,6 +8588,10 @@ class RBrace < Node # [String] the right brace attr_reader :value + def accept(visitor) + visitor.visit_rbrace(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8215,6 +8603,10 @@ class RBracket < Node # [String] the right bracket attr_reader :value + def accept(visitor) + visitor.visit_rbracket(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8238,6 +8630,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_redo(self) + end + def child_nodes [] end @@ -8284,6 +8680,10 @@ class RegexpContent < Node # regular expression attr_reader :parts + def accept(visitor) + visitor.visit_regexp_content(self) + end + def initialize(beginning:, parts:, location:) @beginning = beginning @parts = parts @@ -8304,6 +8704,10 @@ class RegexpBeg < Node # [String] the beginning of the regular expression attr_reader :value + def accept(visitor) + visitor.visit_regexp_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8324,6 +8728,10 @@ class RegexpEnd < Node # [String] the end of the regular expression attr_reader :value + def accept(visitor) + visitor.visit_regexp_end(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8356,6 +8764,10 @@ def initialize(beginning:, ending:, parts:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_regexp_literal(self) + end + def child_nodes parts end @@ -8479,6 +8891,10 @@ def initialize(exceptions:, variable:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_rescue_ex(self) + end + def child_nodes [*exceptions, variable] end @@ -8583,6 +8999,10 @@ def bind_end(end_char) end end + def accept(visitor) + visitor.visit_rescue(self) + end + def child_nodes [exception, statements, consequent] end @@ -8677,6 +9097,10 @@ def initialize(statement:, value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_rescue_mod(self) + end + def child_nodes [statement, value] end @@ -8751,6 +9175,10 @@ def initialize(name:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_rest_param(self) + end + def child_nodes [name] end @@ -8801,6 +9229,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_retry(self) + end + def child_nodes [] end @@ -8850,6 +9282,10 @@ def initialize(arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_return(self) + end + def child_nodes [arguments] end @@ -8899,6 +9335,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_return0(self) + end + def child_nodes [] end @@ -8936,6 +9376,10 @@ class RParen < Node # [String] the parenthesis attr_reader :value + def accept(visitor) + visitor.visit_rparen(self) + end + def initialize(value:, location:) @value = value @location = location @@ -8966,6 +9410,10 @@ def initialize(target:, bodystmt:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_sclass(self) + end + def child_nodes [target, bodystmt] end @@ -9082,6 +9530,10 @@ def empty? end end + def accept(visitor) + visitor.visit_statements(self) + end + def child_nodes body end @@ -9204,6 +9656,10 @@ class StringContent < Node # string attr_reader :parts + def accept(visitor) + visitor.visit_string_content(self) + end + def initialize(parts:, location:) @parts = parts @location = location @@ -9233,6 +9689,10 @@ def initialize(left:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_string_concat(self) + end + def child_nodes [left, right] end @@ -9298,6 +9758,10 @@ def initialize(variable:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_string_dvar(self) + end + def child_nodes [variable] end @@ -9354,6 +9818,10 @@ def initialize(statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_string_embexpr(self) + end + def child_nodes [statements] end @@ -9428,6 +9896,10 @@ def initialize(parts:, quote:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_string_literal(self) + end + def child_nodes parts end @@ -9508,6 +9980,10 @@ def initialize(arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_super(self) + end + def child_nodes [arguments] end @@ -9569,6 +10045,10 @@ class SymBeg < Node # [String] the beginning of the symbol attr_reader :value + def accept(visitor) + visitor.visit_sym_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -9585,6 +10065,10 @@ class SymbolContent < Node # symbol attr_reader :value + def accept(visitor) + visitor.visit_symbol_content(self) + end + def initialize(value:, location:) @value = value @location = location @@ -9610,6 +10094,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_symbol_literal(self) + end + def child_nodes [value] end @@ -9667,6 +10155,10 @@ def initialize(beginning:, elements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_symbols(self) + end + def child_nodes [] end @@ -9734,6 +10226,10 @@ class SymbolsBeg < Node # [String] the beginning of the symbol literal array attr_reader :value + def accept(visitor) + visitor.visit_symbols_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -9749,6 +10245,10 @@ class TLambda < Node # [String] the beginning of the lambda literal attr_reader :value + def accept(visitor) + visitor.visit_tlambda(self) + end + def initialize(value:, location:) @value = value @location = location @@ -9765,6 +10265,10 @@ class TLamBeg < Node # [String] the beginning of the body of the lambda literal attr_reader :value + def accept(visitor) + visitor.visit_tlambeg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -9790,6 +10294,10 @@ def initialize(constant:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_top_const_field(self) + end + def child_nodes [constant] end @@ -9844,6 +10352,10 @@ def initialize(constant:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_top_const_ref(self) + end + def child_nodes [constant] end @@ -9894,6 +10406,10 @@ class TStringBeg < Node # [String] the beginning of the string attr_reader :value + def accept(visitor) + visitor.visit_tstring_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -9925,6 +10441,10 @@ def match?(pattern) value.match?(pattern) end + def accept(visitor) + visitor.visit_tstring_content(self) + end + def child_nodes [] end @@ -9974,6 +10494,10 @@ class TStringEnd < Node # [String] the end of the string attr_reader :value + def accept(visitor) + visitor.visit_tstring_end(self) + end + def initialize(value:, location:) @value = value @location = location @@ -10001,6 +10525,10 @@ def initialize(statement:, parentheses:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_not(self) + end + def child_nodes [statement] end @@ -10066,6 +10594,10 @@ def initialize(operator:, statement:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_unary(self) + end + def child_nodes [statement] end @@ -10149,6 +10681,10 @@ def initialize(symbols:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_undef(self) + end + def child_nodes symbols end @@ -10221,6 +10757,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_unless(self) + end + def child_nodes [predicate, statements, consequent] end @@ -10293,6 +10833,10 @@ def initialize(statement:, predicate:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_unless_mod(self) + end + def child_nodes [statement, predicate] end @@ -10408,6 +10952,10 @@ def initialize(predicate:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_until(self) + end + def child_nodes [predicate, statements] end @@ -10484,6 +11032,10 @@ def initialize(statement:, predicate:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_until_mod(self) + end + def child_nodes [statement, predicate] end @@ -10570,6 +11122,10 @@ def initialize(left:, right:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_var_alias(self) + end + def child_nodes [left, right] end @@ -10633,6 +11189,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_var_field(self) + end + def child_nodes [value] end @@ -10686,6 +11246,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_var_ref(self) + end + def child_nodes [value] end @@ -10740,6 +11304,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_pinned_var_ref(self) + end + def child_nodes [value] end @@ -10796,6 +11364,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_vcall(self) + end + def child_nodes [value] end @@ -10844,6 +11416,10 @@ def initialize(location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_void_stmt(self) + end + def child_nodes [] end @@ -10902,6 +11478,10 @@ def initialize( @comments = comments end + def accept(visitor) + visitor.visit_when(self) + end + def child_nodes [arguments, statements, consequent] end @@ -11009,6 +11589,10 @@ def initialize(predicate:, statements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_while(self) + end + def child_nodes [predicate, statements] end @@ -11085,6 +11669,10 @@ def initialize(statement:, predicate:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_while_mod(self) + end + def child_nodes [statement, predicate] end @@ -11174,6 +11762,10 @@ def match?(pattern) parts.any? { |part| part.is_a?(TStringContent) && part.match?(pattern) } end + def accept(visitor) + visitor.visit_word(self) + end + def child_nodes parts end @@ -11227,6 +11819,10 @@ def initialize(beginning:, elements:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_words(self) + end + def child_nodes [] end @@ -11291,6 +11887,10 @@ class WordsBeg < Node # [String] the start of the word literal array attr_reader :value + def accept(visitor) + visitor.visit_words_beg(self) + end + def initialize(value:, location:) @value = value @location = location @@ -11306,6 +11906,10 @@ class XString < Node # xstring attr_reader :parts + def accept(visitor) + visitor.visit_xstring(self) + end + def initialize(parts:, location:) @parts = parts @location = location @@ -11330,6 +11934,10 @@ def initialize(parts:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_xstring_literal(self) + end + def child_nodes parts end @@ -11384,6 +11992,10 @@ def initialize(arguments:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_yield(self) + end + def child_nodes [arguments] end @@ -11447,6 +12059,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_yield0(self) + end + def child_nodes [] end @@ -11496,6 +12112,10 @@ def initialize(value:, location:, comments: []) @comments = comments end + def accept(visitor) + visitor.visit_zsuper(self) + end + def child_nodes [] end diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index d1da8e3a..18e6f277 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -2,14 +2,542 @@ module SyntaxTree class Visitor - def visit_all(nodes) - nodes.each do |node| - visit(node) + # This is raised when you use the Visitor.visit_method method and it fails. + # It is correctable to through DidYouMean. + class VisitMethodError < StandardError + attr_reader :visit_method + + def initialize(visit_method) + @visit_method = visit_method + super("Invalid visit method: #{visit_method}") + end + end + + # This class is used by DidYouMean to offer corrections to invalid visit + # method names. + class VisitMethodChecker + attr_reader :visit_method + + def initialize(error) + @visit_method = error.visit_method + end + + def corrections + @corrections ||= + DidYouMean::SpellChecker.new(dictionary: Visitor.visit_methods).correct(visit_method) + end + + DidYouMean.correct_error(VisitMethodError, self) + end + + class << self + # This method is here to help folks write visitors. + # + # It's not always easy to ensure you're writing the correct method name in + # the visitor since it's perfectly valid to define methods that don't + # override these parent methods. + # + # If you use this method, you can ensure you're writing the correct method + # name. It will raise an error if the visit method you're defining isn't + # actually a method on the parent visitor. + def visit_method(method_name) + return if visit_methods.include?(method_name) + + raise VisitMethodError, method_name + end + + # This is the list of all of the valid visit methods. + def visit_methods + Visitor.instance_methods.grep(/^visit_(?!child_nodes)/) end end def visit(node) - node&.accept(self) + node.accept(self) end + + def visit_child_nodes(node) + node.child_nodes.each { |child_node| visit(child_node) if child_node } + end + + # Visit an ARef node. + alias visit_aref visit_child_nodes + + # Visit an ARefField node. + alias visit_aref_field visit_child_nodes + + # Visit an Alias node. + alias visit_alias visit_child_nodes + + # Visit an ArgBlock node. + alias visit_arg_block visit_child_nodes + + # Visit an ArgParen node. + alias visit_arg_paren visit_child_nodes + + # Visit an ArgStar node. + alias visit_arg_star visit_child_nodes + + # Visit an Args node. + alias visit_args visit_child_nodes + + # Visit an ArgsForward node. + alias visit_args_forward visit_child_nodes + + # Visit an ArrayLiteral node. + alias visit_array visit_child_nodes + + # Visit an AryPtn node. + alias visit_aryptn visit_child_nodes + + # Visit an Assign node. + alias visit_assign visit_child_nodes + + # Visit an Assoc node. + alias visit_assoc visit_child_nodes + + # Visit an AssocSplat node. + alias visit_assoc_splat visit_child_nodes + + # Visit a BEGINBlock node. + alias visit_BEGIN visit_child_nodes + + # Visit a Backref node. + alias visit_backref visit_child_nodes + + # Visit a Backtick node. + alias visit_backtick visit_child_nodes + + # Visit a BareAssocHash node. + alias visit_bare_assoc_hash visit_child_nodes + + # Visit a Begin node. + alias visit_begin visit_child_nodes + + # Visit a Binary node. + alias visit_binary visit_child_nodes + + # Visit a BlockArg node. + alias visit_block_arg visit_child_nodes + + # Visit a BlockVar node. + alias visit_block_var visit_child_nodes + + # Visit a BodyStmt node. + alias visit_bodystmt visit_child_nodes + + # Visit a BraceBlock node. + alias visit_brace_block visit_child_nodes + + # Visit a Break node. + alias visit_break visit_child_nodes + + # Visit a CHAR node. + alias visit_CHAR visit_child_nodes + + # Visit a CVar node. + alias visit_cvar visit_child_nodes + + # Visit a Call node. + alias visit_call visit_child_nodes + + # Visit a Case node. + alias visit_case visit_child_nodes + + # Visit a ClassDeclaration node. + alias visit_class visit_child_nodes + + # Visit a Comma node. + alias visit_comma visit_child_nodes + + # Visit a Command node. + alias visit_command visit_child_nodes + + # Visit a CommandCall node. + alias visit_command_call visit_child_nodes + + # Visit a Comment node. + alias visit_comment visit_child_nodes + + # Visit a Const node. + alias visit_const visit_child_nodes + + # Visit a ConstPathField node. + alias visit_const_path_field visit_child_nodes + + # Visit a ConstPathRef node. + alias visit_const_path_ref visit_child_nodes + + # Visit a ConstRef node. + alias visit_const_ref visit_child_nodes + + # Visit a Def node. + alias visit_def visit_child_nodes + + # Visit a DefEndless node. + alias visit_def_endless visit_child_nodes + + # Visit a Defined node. + alias visit_defined visit_child_nodes + + # Visit a Defs node. + alias visit_defs visit_child_nodes + + # Visit a DoBlock node. + alias visit_do_block visit_child_nodes + + # Visit a Dot2 node. + alias visit_dot2 visit_child_nodes + + # Visit a Dot3 node. + alias visit_dot3 visit_child_nodes + + # Visit a DynaSymbol node. + alias visit_dyna_symbol visit_child_nodes + + # Visit an ENDBlock node. + alias visit_END visit_child_nodes + + # Visit an Else node. + alias visit_else visit_child_nodes + + # Visit an Elsif node. + alias visit_elsif visit_child_nodes + + # Visit an EmbDoc node. + alias visit_embdoc visit_child_nodes + + # Visit an EmbExprBeg node. + alias visit_embexpr_beg visit_child_nodes + + # Visit an EmbExprEnd node. + alias visit_embexpr_end visit_child_nodes + + # Visit an EmbVar node. + alias visit_embvar visit_child_nodes + + # Visit an EndContent node. + alias visit___end__ visit_child_nodes + + # Visit an Ensure node. + alias visit_ensure visit_child_nodes + + # Visit an ExcessedComma node. + alias visit_excessed_comma visit_child_nodes + + # Visit a FCall node. + alias visit_fcall visit_child_nodes + + # Visit a Field node. + alias visit_field visit_child_nodes + + # Visit a FloatLiteral node. + alias visit_float visit_child_nodes + + # Visit a FndPtn node. + alias visit_fndptn visit_child_nodes + + # Visit a For node. + alias visit_for visit_child_nodes + + # Visit a GVar node. + alias visit_gvar visit_child_nodes + + # Visit a HashLiteral node. + alias visit_hash visit_child_nodes + + # Visit a Heredoc node. + alias visit_heredoc visit_child_nodes + + # Visit a HeredocBeg node. + alias visit_heredoc_beg visit_child_nodes + + # Visit a HshPtn node. + alias visit_hshptn visit_child_nodes + + # Visit an IVar node. + alias visit_ivar visit_child_nodes + + # Visit an Ident node. + alias visit_ident visit_child_nodes + + # Visit an If node. + alias visit_if visit_child_nodes + + # Visit an IfMod node. + alias visit_if_mod visit_child_nodes + + # Visit an IfOp node. + alias visit_if_op visit_child_nodes + + # Visit an Imaginary node. + alias visit_imaginary visit_child_nodes + + # Visit an In node. + alias visit_in visit_child_nodes + + # Visit an Int node. + alias visit_int visit_child_nodes + + # Visit a Kw node. + alias visit_kw visit_child_nodes + + # Visit a KwRestParam node. + alias visit_kwrest_param visit_child_nodes + + # Visit a LBrace node. + alias visit_lbrace visit_child_nodes + + # Visit a LBracket node. + alias visit_lbracket visit_child_nodes + + # Visit a LParen node. + alias visit_lparen visit_child_nodes + + # Visit a Label node. + alias visit_label visit_child_nodes + + # Visit a LabelEnd node. + alias visit_label_end visit_child_nodes + + # Visit a Lambda node. + alias visit_lambda visit_child_nodes + + # Visit a MAssign node. + alias visit_massign visit_child_nodes + + # Visit a MLHS node. + alias visit_mlhs visit_child_nodes + + # Visit a MLHSParen node. + alias visit_mlhs_paren visit_child_nodes + + # Visit a MRHS node. + alias visit_mrhs visit_child_nodes + + # Visit a MethodAddBlock node. + alias visit_method_add_block visit_child_nodes + + # Visit a ModuleDeclaration node. + alias visit_module visit_child_nodes + + # Visit a Next node. + alias visit_next visit_child_nodes + + # Visit a Not node. + alias visit_not visit_child_nodes + + # Visit an Op node. + alias visit_op visit_child_nodes + + # Visit an OpAssign node. + alias visit_op_assign visit_child_nodes + + # Visit a Params node. + alias visit_params visit_child_nodes + + # Visit a Paren node. + alias visit_paren visit_child_nodes + + # Visit a Period node. + alias visit_period visit_child_nodes + + # Visit a PinnedBegin node. + alias visit_pinned_begin visit_child_nodes + + # Visit a PinnedVarRef node. + alias visit_pinned_var_ref visit_child_nodes + + # Visit a Program node. + alias visit_program visit_child_nodes + + # Visit a QSymbols node. + alias visit_qsymbols visit_child_nodes + + # Visit a QSymbolsBeg node. + alias visit_qsymbols_beg visit_child_nodes + + # Visit a QWords node. + alias visit_qwords visit_child_nodes + + # Visit a QWordsBeg node. + alias visit_qwords_beg visit_child_nodes + + # Visit a RAssign node. + alias visit_rassign visit_child_nodes + + # Visit a RBrace node. + alias visit_rbrace visit_child_nodes + + # Visit a RBracket node. + alias visit_rbracket visit_child_nodes + + # Visit a RParen node. + alias visit_rparen visit_child_nodes + + # Visit a RationalLiteral node. + alias visit_rational visit_child_nodes + + # Visit a Redo node. + alias visit_redo visit_child_nodes + + # Visit a RegexpBeg node. + alias visit_regexp_beg visit_child_nodes + + # Visit a RegexpContent node. + alias visit_regexp_content visit_child_nodes + + # Visit a RegexpEnd node. + alias visit_regexp_end visit_child_nodes + + # Visit a RegexpLiteral node. + alias visit_regexp_literal visit_child_nodes + + # Visit a Rescue node. + alias visit_rescue visit_child_nodes + + # Visit a RescueEx node. + alias visit_rescue_ex visit_child_nodes + + # Visit a RescueMod node. + alias visit_rescue_mod visit_child_nodes + + # Visit a RestParam node. + alias visit_rest_param visit_child_nodes + + # Visit a Retry node. + alias visit_retry visit_child_nodes + + # Visit a Return node. + alias visit_return visit_child_nodes + + # Visit a Return0 node. + alias visit_return0 visit_child_nodes + + # Visit a SClass node. + alias visit_sclass visit_child_nodes + + # Visit a Statements node. + alias visit_statements visit_child_nodes + + # Visit a StringConcat node. + alias visit_string_concat visit_child_nodes + + # Visit a StringContent node. + alias visit_string_content visit_child_nodes + + # Visit a StringDVar node. + alias visit_string_dvar visit_child_nodes + + # Visit a StringEmbExpr node. + alias visit_string_embexpr visit_child_nodes + + # Visit a StringLiteral node. + alias visit_string_literal visit_child_nodes + + # Visit a Super node. + alias visit_super visit_child_nodes + + # Visit a SymBeg node. + alias visit_sym_beg visit_child_nodes + + # Visit a SymbolContent node. + alias visit_symbol_content visit_child_nodes + + # Visit a SymbolLiteral node. + alias visit_symbol_literal visit_child_nodes + + # Visit a Symbols node. + alias visit_symbols visit_child_nodes + + # Visit a SymbolsBeg node. + alias visit_symbols_beg visit_child_nodes + + # Visit a TLamBeg node. + alias visit_tlambeg visit_child_nodes + + # Visit a TLambda node. + alias visit_tlambda visit_child_nodes + + # Visit a TStringBeg node. + alias visit_tstring_beg visit_child_nodes + + # Visit a TStringContent node. + alias visit_tstring_content visit_child_nodes + + # Visit a TStringEnd node. + alias visit_tstring_end visit_child_nodes + + # Visit a TopConstField node. + alias visit_top_const_field visit_child_nodes + + # Visit a TopConstRef node. + alias visit_top_const_ref visit_child_nodes + + # Visit an Unary node. + alias visit_unary visit_child_nodes + + # Visit an Undef node. + alias visit_undef visit_child_nodes + + # Visit an Unless node. + alias visit_unless visit_child_nodes + + # Visit an UnlessMod node. + alias visit_unless_mod visit_child_nodes + + # Visit an Until node. + alias visit_until visit_child_nodes + + # Visit an UntilMod node. + alias visit_until_mod visit_child_nodes + + # Visit a VCall node. + alias visit_vcall visit_child_nodes + + # Visit a VarAlias node. + alias visit_var_alias visit_child_nodes + + # Visit a VarField node. + alias visit_var_field visit_child_nodes + + # Visit a VarRef node. + alias visit_var_ref visit_child_nodes + + # Visit a VoidStmt node. + alias visit_void_stmt visit_child_nodes + + # Visit a When node. + alias visit_when visit_child_nodes + + # Visit a While node. + alias visit_while visit_child_nodes + + # Visit a WhileMod node. + alias visit_while_mod visit_child_nodes + + # Visit a Word node. + alias visit_word visit_child_nodes + + # Visit a Words node. + alias visit_words visit_child_nodes + + # Visit a WordsBeg node. + alias visit_words_beg visit_child_nodes + + # Visit a XString node. + alias visit_xstring visit_child_nodes + + # Visit a XStringLiteral node. + alias visit_xstring_literal visit_child_nodes + + # Visit a Yield node. + alias visit_yield visit_child_nodes + + # Visit a Yield0 node. + alias visit_yield0 visit_child_nodes + + # Visit a ZSuper node. + alias visit_zsuper visit_child_nodes end end diff --git a/test/visitor_test.rb b/test/visitor_test.rb index de166948..95244c96 100644 --- a/test/visitor_test.rb +++ b/test/visitor_test.rb @@ -1,19 +1,22 @@ # frozen_string_literal: true require_relative "test_helper" -require "objspace" class VisitorTest < Minitest::Test - def test_can_visit_all_nodes + def test_visit_all_nodes visitor = SyntaxTree::Visitor.new - ObjectSpace.each_object(SyntaxTree::Node.singleton_class) - .reject { |node| node.singleton_class? || node == SyntaxTree::Node } - .each { |node| assert_respond_to(visitor, node.visit_method_name) } - end + filepath = File.expand_path("../lib/syntax_tree/node.rb", __dir__) + program = SyntaxTree.parse(SyntaxTree.read(filepath)) + + program.statements.body.last.bodystmt.statements.body.each do |node| + next unless node in SyntaxTree::ClassDeclaration[superclass: { value: { value: "Node" } }] - def test_node_visit_method_name - assert_equal("visit_t_string_end", SyntaxTree::TStringEnd.visit_method_name) + accept = node.bodystmt.statements.body.detect { |defm| defm in SyntaxTree::Def[name: { value: "accept" }] } + accept => { bodystmt: { statements: { body: [SyntaxTree::Call[message: { value: visit_method }]] } } } + + assert_respond_to(visitor, visit_method) + end end def test_visit_tree @@ -42,12 +45,12 @@ def initialize @visited_nodes = [] end - def visit_class_declaration(node) + visit_method def visit_class(node) @visited_nodes << node.constant.constant.value super end - def visit_def(node) + visit_method def visit_def(node) @visited_nodes << node.name.value end end