diff --git a/Gemfile b/Gemfile index f4360f3a..f0862ec2 100644 --- a/Gemfile +++ b/Gemfile @@ -19,3 +19,5 @@ group :development do gem "ruby-lsp" gem "benchmark-ips" end + +gem "refract", github: "yippee-fun/refract" diff --git a/lib/phlex/compiler.rb b/lib/phlex/compiler.rb index 72c27c47..7bc9a01d 100644 --- a/lib/phlex/compiler.rb +++ b/lib/phlex/compiler.rb @@ -1,15 +1,28 @@ # frozen_string_literal: true require "prism" +require "refract" module Phlex::Compiler Error = Class.new(StandardError) + class BufferPush + def initialize(value, escape:) + @value = value + @escape = escape + freeze + end + + attr_reader :value, :escape + end + def self.compile(component) path, line = Object.const_source_location(component.name) return unless File.exist?(path) source = File.read(path) tree = Prism.parse(source).value - Compilation.new(component, path, line, source, tree).compile + refract = Refract::Converter.new.visit(tree) + + Compilation.new(component, path, line, source, refract).compile end end diff --git a/lib/phlex/compiler/class_compiler.rb b/lib/phlex/compiler/class_compiler.rb index 80050195..2ab0fafe 100644 --- a/lib/phlex/compiler/class_compiler.rb +++ b/lib/phlex/compiler/class_compiler.rb @@ -1,35 +1,35 @@ # frozen_string_literal: true -class Phlex::Compiler::ClassCompiler < Prism::Visitor +class Phlex::Compiler::ClassCompiler < Refract::Visitor def initialize(compiler) + super() @compiler = compiler end def compile(node) - visit_all(node.child_nodes) + visit(node.body) end - def visit_def_node(node) + visit Refract::DefNode do |node| return if node.name == :initialize return if node.receiver compiled_source = Phlex::Compiler::MethodCompiler.new(@compiler.component).compile(node) if compiled_source - # puts compiled_source - @compiler.redefine_method(compiled_source, node.location.start_line) + @compiler.redefine_method(compiled_source, node.start_line) end end - def visit_class_node(node) + visit Refract::ClassNode do |node| nil end - def visit_module_node(node) + visit Refract::ModuleNode do |node| nil end - def visit_block_node(node) + visit Refract::BlockNode do |node| nil end end diff --git a/lib/phlex/compiler/file_compiler.rb b/lib/phlex/compiler/file_compiler.rb index 43fc6f07..e9725e79 100644 --- a/lib/phlex/compiler/file_compiler.rb +++ b/lib/phlex/compiler/file_compiler.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true -class Phlex::Compiler::FileCompiler < Prism::Visitor +class Phlex::Compiler::FileCompiler < Refract::Visitor def initialize(compiler) + super() @compiler = compiler end @@ -9,8 +10,8 @@ def compile(node) visit(node) end - def visit_class_node(node) - if @compiler.line == node.location.start_line + visit Refract::ClassNode do |node| + if @compiler.line == node.start_line Phlex::Compiler::ClassCompiler.new(@compiler).compile(node) end end @@ -19,11 +20,11 @@ def visit_class_node(node) # super # end - def visit_def_node(node) + visit Refract::DefNode do |node| nil end - def visit_block_node(node) + visit Refract::BlockNode do |node| nil end end diff --git a/lib/phlex/compiler/formatter.rb b/lib/phlex/compiler/formatter.rb deleted file mode 100644 index 77506280..00000000 --- a/lib/phlex/compiler/formatter.rb +++ /dev/null @@ -1,126 +0,0 @@ -# frozen_string_literal: true - -module Phlex::Compiler - class Formatter < VerbatimFormatter - def visit(node) - case node - when nil - nil - when String - push node - when Array, Set - node.each { |n| visit(n) } - when Proc - visit node.call - when :new_line - new_line - when :space - space - else - super - end - end - - def format(node) - @buffer.clear - visit(node) - [@buffer.join, @source_map] - end - - def visit_each(nodes) - i, len = 0, nodes.length - if block_given? - while i < len - node = nodes[i] - i += 1 - if node - visit node - yield unless i == len - end - end - else - while i < len - visit nodes[i] - i += 1 - end - end - end - - def statement - new_line - yield - end - - def parens - push "(" - yield - push ")" - end - - def new_line - push "\n" - end - - def space - push " " - end - - def visit_block_node(node) - emit node.opening_loc - new_line - visit node.body - new_line - emit node.closing_loc - end - - def visit_call_node(node) - visit node.receiver - emit node.call_operator_loc - emit node.message_loc - if node.opening_loc - emit node.opening_loc - else - space - end - visit node.arguments - emit node.closing_loc - space - visit node.block - end - - def visit_def_node(node) - push "def" - space - push node.name - - if node.parameters - parens do - visit node.parameters - end - end - - new_line - visit node.body - - new_line - push "end" - end - - def visit_statements_node(node) - visit_each(node.compact_child_nodes) { new_line } - end - - def visit_interpolated_string_node(node) - push '"' - node.parts.each do |part| - case part - when Prism::StringNode - push part.unescaped.gsub('"', '\"') - when Prism::EmbeddedStatementsNode - visit(part) - end - end - push '"' - end - end -end diff --git a/lib/phlex/compiler/method_compiler.rb b/lib/phlex/compiler/method_compiler.rb index 43f0eea5..348e40ea 100644 --- a/lib/phlex/compiler/method_compiler.rb +++ b/lib/phlex/compiler/method_compiler.rb @@ -3,22 +3,57 @@ require "prism" module Phlex::Compiler - class MethodCompiler < Prism::MutationCompiler + class MethodCompiler < Refract::MutationVisitor def initialize(component) + super() @component = component @current_buffer = nil - @preamble = Set[] + @preamble = [] end def compile(node) result = visit(node) - result.body&.body&.unshift(@preamble, statement("nil")) - source, map = Phlex::Compiler::Formatter.new.format(result) - source + Refract::Formatter.new.format_node(result) end - def visit_call_node(node) + def around_visit(node) + result = super + + # We want to clear the buffer when there’s a node that isn’t a statements node, + # but we should ignore nils, which are usually other buffers. + clear_buffer unless result in Refract::StatementsNode | nil + + result + end + + visit Refract::ClassNode do |node| + node + end + + visit Refract::ModuleNode do |node| + node + end + + visit Refract::DefNode do |node| + if @stack.size == 1 + node.copy( + body: Refract::StatementsNode.new( + body: [ + Refract::StatementsNode.new( + body: @preamble + ), + Refract::NilNode.new, + visit(node.body), + ] + ) + ) + else + node + end + end + + visit Refract::CallNode do |node| if nil == node.receiver if (tag = standard_element?(node)) return compile_standard_element(node, tag) @@ -39,259 +74,375 @@ def visit_call_node(node) end end - clear_buffer - super - end - - def visit_class_node(node) - node + super(node) end - def visit_module_node(node) - node + visit Refract::BlockNode do |node| + node.copy( + body: compile_block_body_node( + node.body + ) + ) end def compile_standard_element(node, tag) - [ - [ + node => Refract::CallNode + + Refract::StatementsNode.new( + body: [ buffer("<#{tag}"), *( if node.arguments - visit_phlex_attributes(node.arguments) + compile_phlex_attributes(node.arguments) end ), buffer(">"), *( if node.block - [visit_phlex_block(node.block)] + compile_phlex_block(node.block) end ), buffer(""), - ], - ] + ] + ) end - def visit_phlex_attributes(node) - if node.arguments in [Prism::KeywordHashNode[elements: attributes]] + def compile_void_element(node, tag) + node => Refract::CallNode + + Refract::StatementsNode.new( + body: [ + buffer("<#{tag}"), + *( + if node.arguments + compile_phlex_attributes(node.arguments) + end + ), + buffer(">"), + ] + ) + end + + def compile_phlex_attributes(node) + arguments = node.arguments + + if arguments.size == 1 && Refract::KeywordHashNode === (first_argument = arguments[0]) + attributes = first_argument.elements literal_attributes = attributes.all? do |attribute| - Prism::AssocNode === attribute && static_attribute_value_literal?(attribute) + Refract::AssocNode === attribute && static_attribute_value_literal?(attribute) end if literal_attributes - return buffer(Phlex::SGML::Attributes.generate_attributes(eval("{#{node.slice}}"))) + return buffer( + Phlex::SGML::Attributes.generate_attributes( + eval( + "{#{Refract::Formatter.new.format_node(node)}}" + ) + ) + ) end + + clear_buffer + + Refract::CallNode.new( + name: :__render_attributes__, + arguments: Refract::ArgumentsNode.new( + arguments: [ + node, + ] + ) + ) end + end - [ - :new_line, - push("__render_attributes__("), - node, - push(")"), - ] - end - - def visit_phlex_block(node) - if Prism::BlockArgumentNode === node - [push("__yield_content__("), node, push(")")] - elsif output_block?(node) - visit(node.body) - elsif content_block?(node) - content = node.body.body.first - case content - when Prism::StringNode, Prism::SymbolNode - buffer(Phlex::Escape.html_escape(content.unescaped)) - when Prism::InterpolatedStringNode - compile_interpolated_string_node(content) - when Prism::NilNode - nil - else - raise + def compile_phlex_block(node) + case node + when Refract::BlockNode + if output_block?(node) + return visit(node.body) + elsif static_content_block?(node) + content = node.body.body.first + case content + when Refract::StringNode, Refract::SymbolNode + return buffer(Phlex::Escape.html_escape(content.unescaped)) + when Refract::InterpolatedStringNode + return compile_interpolated_string_node(content) + when Refract::NilNode + return nil + else + raise + end end - else - [ - statement("__yield_content__ do"), - [node.body], - statement("end"), - ] end - end - def visit_block_node(node) - node.copy( - body: compile_block_body_node(node.body) + clear_buffer + Refract::CallNode.new( + name: :__yield_content__, + block: node ) end def compile_block_body_node(node) - [ - statement("if #{self_local} == self"), - visit(node), - statement("else"), - [[node]], - statement("end"), - ] + node => Refract::StatementsNode + + Refract::StatementsNode.new( + body: [ + Refract::IfNode.new( + inline: false, + predicate: Refract::CallNode.new( + receiver: Refract::SelfNode.new, + name: :==, + arguments: Refract::ArgumentsNode.new( + arguments: [ + Refract::LocalVariableReadNode.new( + name: self_local + ), + ] + ) + ), + statements: Refract::StatementsNode.new( + body: node.body.map { |n| visit(n) } + ), + subsequent: Refract::ElseNode.new( + statements: node + ) + ), + ] + ) end def compile_interpolated_string_node(node) - node.parts.map do |part| - case part - when Prism::StringNode - buffer(Phlex::Escape.html_escape(part.unescaped)) - when Prism::EmbeddedVariableNode - [ - buffer('#{'), - buffer("::Phlex::Escape.html_escape(("), - buffer(part.variable.slice), - buffer(").to_s)}"), - ] - when Prism::EmbeddedStatementsNode - [ - buffer('#{'), - buffer("::Phlex::Escape.html_escape(("), - buffer(part.statements.slice, escape: false), - buffer(").to_s)}"), - ] - else - raise Phlex::Compiler::Error, "Unexpected node type in InterpolatedStringNode: #{part.class}" + node => Refract::InterpolatedStringNode + + Refract::StatementsNode.new( + body: node.parts.map do |part| + case part + when Refract::StringNode + buffer(Phlex::Escape.html_escape(part.unescaped)) + when Refract::EmbeddedVariableNode + interpolate(part.variable) + when Refract::EmbeddedStatementsNode + interpolate(part.statements) + else + raise Phlex::Compiler::Error, "Unexpected node type in InterpolatedStringNode: #{part.class}" + end end - end - end - - def compile_void_element(node, tag) - [ - [ - buffer("<#{tag}"), - *( - if node.arguments - visit_phlex_attributes(node.arguments) - end - ), - buffer(">"), - ], - ] + ) end def compile_whitespace_helper(node) + node => Refract::CallNode + if node.block - [ - buffer(" "), - visit_phlex_block(node.block), - buffer(" "), - ] + Refract::StatementsNode.new( + body: [ + buffer(" "), + compile_phlex_block(node.block), + buffer(" "), + ] + ) else - [ - buffer(" "), - ] + buffer(" ") end end def compile_doctype_helper(node) - [ - buffer(""), - ] + node => Refract::CallNode + + buffer("") end def compile_plain_helper(node) - if node.arguments in [Prism::StringNode] - [ - buffer(node.arguments.child_nodes.first.unescaped), - ] + node => Refract::CallNode + + if node.arguments in [Refract::StringNode] + buffer(node.arguments.arguments.first.unescaped) else - @current_buffer = nil node end end def compile_fragment_helper(node) + node => Refract::CallNode + node.copy( block: compile_fragment_helper_block(node.block) ) end def compile_fragment_helper_block(node) + node => Refract::BlockNode + node.copy( - body: [ - statement("__phlex_original_should_render__ = #{should_render_local}"), - statement("#{should_render_local} = #{state_local}.should_render?"), - visit(node.body), - statement("#{should_render_local} = __phlex_original_should_render__"), - ] + body: Refract::StatementsNode.new( + body: [ + Refract::LocalVariableWriteNode.new( + name: :__phlex_original_should_render__, + value: Refract::LocalVariableReadNode.new( + name: should_render_local + ) + ), + Refract::LocalVariableWriteNode.new( + name: should_render_local, + value: Refract::CallNode.new( + receiver: Refract::LocalVariableReadNode.new( + name: state_local + ), + name: :should_render? + ) + ), + visit(node.body), + Refract::LocalVariableWriteNode.new( + name: should_render_local, + value: Refract::LocalVariableReadNode.new( + name: :__phlex_original_should_render__ + ) + ), + ] + ) ) end def compile_comment_helper(node) - [ - buffer(""), - ] + node => Refract::CallNode + + Refract::StatementsNode.new( + body: [ + buffer(""), + ] + ) end def compile_raw_helper(node) - clear_buffer + node => Refract::CallNode + node end - private def statement(string) - clear_buffer - [ - :new_line, - string, - ";", - ] - end + private def buffer(value) + if @current_buffer + @current_buffer << Refract::StringNode.new( + unescaped: value + ) - private def push(value) - clear_buffer - value - end + nil + else + new_buffer = [ + Refract::StringNode.new( + unescaped: value + ), + ] - private def clear_buffer - @current_buffer = nil + @current_buffer = new_buffer + + Refract::IfNode.new( + inline: false, + predicate: Refract::LocalVariableReadNode.new( + name: should_render_local + ), + statements: Refract::StatementsNode.new( + body: [ + Refract::CallNode.new( + receiver: Refract::CallNode.new( + name: buffer_local, + ), + name: :<<, + arguments: Refract::ArgumentsNode.new( + arguments: [ + Refract::InterpolatedStringNode.new( + parts: new_buffer + ), + ] + ) + ), + ] + ) + ) + end end - private def buffer(value, escape: true) + private def interpolate(statements, escape: true) + embedded_statement = Refract::EmbeddedStatementsNode.new( + statements: Refract::StatementsNode.new( + body: [ + Refract::CallNode.new( + receiver: Refract::ConstantPathNode.new( + parent: Refract::ConstantPathNode.new( + name: "Phlex" + ), + name: "Escape" + ), + name: :html_escape, + arguments: Refract::ArgumentsNode.new( + arguments: [ + Refract::CallNode.new( + receiver: Refract::ParenthesesNode.new( + body: statements + ), + name: :to_s + ), + ] + ) + ), + ] + ) + ) + if @current_buffer - if escape - @current_buffer << value.gsub('"', '\\"') - else - @current_buffer << value - end + @current_buffer << embedded_statement + nil else - new_buffer = +"" + new_buffer = [embedded_statement] + @current_buffer = new_buffer - if escape - new_buffer << value.gsub('"', '\\"') - else - new_buffer << value - end - [ - :new_line, - "#{buffer_local} << \"", - new_buffer, - "\" if #{should_render_local}; nil;", - ] + Refract::IfNode.new( + predicate: Refract::LocalVariableReadNode.new( + name: should_render_local + ), + statements: Refract::StatementsNode.new( + body: [ + Refract::CallNode.new( + receiver: Refract::CallNode.new( + name: buffer_local, + ), + name: :<<, + arguments: Refract::ArgumentsNode.new( + arguments: [ + Refract::InterpolatedStringNode.new( + parts: new_buffer + ), + ] + ) + ), + ] + ) + ) end end - private def new_scope - original_in_scope = @in_scope - @in_scope = false - yield - @in_scope = original_in_scope + private def clear_buffer + @current_buffer = nil end private def output_block?(node) node.body.body.any? do |child| - Prism::CallNode === child && (standard_element?(child) || void_element?(child) || plain_helper?(child) || whitespace_helper?(child) || raw_helper?(child)) + Refract::CallNode === child && ( + standard_element?(child) || + void_element?(child) || + plain_helper?(child) || + whitespace_helper?(child) || + raw_helper?(child) + ) end end - private def content_block?(node) + private def static_content_block?(node) return false unless node.body.body.length == 1 - node.body.body.first in Prism::StringNode | Prism::InterpolatedStringNode | Prism::SymbolNode | Prism::NilNode + node.body.body.first in Refract::StringNode | Refract::InterpolatedStringNode | Refract::SymbolNode | Refract::NilNode end private def standard_element?(node) @@ -316,15 +467,15 @@ def compile_raw_helper(node) private def static_attribute_value_literal?(value) case value - when Prism::SymbolNode, Prism::StringNode, Prism::IntegerNode, Prism::FloatNode, Prism::TrueNode, Prism::FalseNode, Prism::NilNode + when Refract::SymbolNode, Refract::StringNode, Refract::IntegerNode, Refract::FloatNode, Refract::TrueNode, Refract::FalseNode, Refract::NilNode true - when Prism::ArrayNode + when Refract::ArrayNode value.elements.all? { |n| static_token_value_literal?(n) } - when Prism::HashNode + when Refract::HashNode value.elements.all? { |n| static_attribute_value_literal?(n) } - when Prism::AssocNode - (Prism::StringNode === value.key || Prism::SymbolNode === value.key) && static_attribute_value_literal?(value.value) - when Prism::CallNode + when Refract::AssocNode + (Refract::StringNode === value.key || Refract::SymbolNode === value.key) && static_attribute_value_literal?(value.value) + when Refract::CallNode if value in { receiver: Prism::ConstantReadNode[name: :Set]| Prism::ConstantPathNode[name: :Set, parent: nil], name: :[] } value.arguments.arguments.all? { |n| static_token_value_literal?(n) } else @@ -370,33 +521,73 @@ def compile_raw_helper(node) node.name == :raw && own_method_without_scope?(node) end - ALLOWED_OWNERS = [Phlex::SGML, Phlex::HTML, Phlex::SVG] + ALLOWED_OWNERS = Set[Phlex::SGML, Phlex::HTML, Phlex::SVG] private def own_method_without_scope?(node) ALLOWED_OWNERS.include?(@component.instance_method(node.name).owner) end - private def extract_kwargs_from_string(string) - eval("{#{string}}") - end - private def state_local - @preamble << [:new_line, "__phlex_state__ = @_state;"] - "__phlex_state__" + :__phlex_state__.tap do |local| + unless @state_local_set + @preamble << Refract::LocalVariableWriteNode.new( + name: local, + value: Refract::InstanceVariableReadNode.new( + name: :@_state + ) + ) + + @state_local_set = true + end + end end private def buffer_local - @preamble << [:new_line, "__phlex_buffer__ = #{state_local}.buffer;"] - "__phlex_buffer__" + :__phlex_buffer__.tap do |local| + unless @buffer_local_set + @preamble << Refract::LocalVariableWriteNode.new( + name: local, + value: Refract::CallNode.new( + receiver: Refract::LocalVariableReadNode.new( + name: state_local + ), + name: :buffer, + ) + ) + + @buffer_local_set = true + end + end end private def self_local - @preamble << [:new_line, "__phlex_self__ = self;"] - "__phlex_self__" + :__phlex_self__.tap do |local| + unless @self_local_set + @preamble << Refract::LocalVariableWriteNode.new( + name: local, + value: Refract::SelfNode.new + ) + + @self_local_set = true + end + end end private def should_render_local - @preamble << [:new_line, "__phlex_should_render__ = #{state_local}.should_render?;"] - "__phlex_should_render__" + :__phlex_should_render__.tap do |local| + unless @should_render_local_set + @preamble << Refract::LocalVariableWriteNode.new( + name: :__phlex_should_render__, + value: Refract::CallNode.new( + receiver: Refract::LocalVariableReadNode.new( + name: state_local + ), + name: :should_render? + ) + ) + + @should_render_local_set = true + end + end end end end diff --git a/lib/phlex/compiler/verbatim_formatter.rb b/lib/phlex/compiler/verbatim_formatter.rb deleted file mode 100644 index ed7bd3a4..00000000 --- a/lib/phlex/compiler/verbatim_formatter.rb +++ /dev/null @@ -1,644 +0,0 @@ -# frozen_string_literal: true - -module Phlex::Compiler - class VerbatimFormatter < Prism::BasicVisitor - def initialize - @buffer = [] - @source_map = [] - @current_line = 1 - end - - def push(value) - string = case value - when String - value - when Symbol - value.name - end - - @buffer << string - new_lines = string.count("\n") - @current_line += new_lines - end - - def emit(node) - return unless node - source_map = @source_map - current_line = @current_line - start_line = node.start_line - end_line = node.end_line - number_of_lines = end_line - start_line - i = 0 - while i <= number_of_lines - source_map[current_line + i] = start_line + i - i += 1 - end - - push node.slice - end - - def visit_alias_global_variable_node(node) - emit node - end - - def visit_alias_method_node(node) - emit node - end - - def visit_alternation_pattern_node(node) - emit node - end - - def visit_and_node(node) - emit node - end - - def visit_arguments_node(node) - emit node - end - - def visit_array_node(node) - emit node - end - - def visit_array_pattern_node(node) - emit node - end - - def visit_assoc_node(node) - emit node - end - - def visit_assoc_splat_node(node) - emit node - end - - def visit_back_reference_read_node(node) - emit node - end - - def visit_begin_node(node) - emit node - end - - def visit_block_argument_node(node) - emit node - end - - def visit_block_local_variable_node(node) - emit node - end - - def visit_block_node(node) - emit node - end - - def visit_block_parameter_node(node) - emit node - end - - def visit_block_parameters_node(node) - emit node - end - - def visit_break_node(node) - emit node - end - - def visit_call_and_write_node(node) - emit node - end - - def visit_call_node(node) - emit node - end - - def visit_call_operator_write_node(node) - emit node - end - - def visit_call_or_write_node(node) - emit node - end - - def visit_call_target_node(node) - emit node - end - - def visit_capture_pattern_node(node) - emit node - end - - def visit_case_match_node(node) - emit node - end - - def visit_case_node(node) - emit node - end - - def visit_class_node(node) - emit node - end - - def visit_class_variable_and_write_node(node) - emit node - end - - def visit_class_variable_operator_write_node(node) - emit node - end - - def visit_class_variable_or_write_node(node) - emit node - end - - def visit_class_variable_read_node(node) - emit node - end - - def visit_class_variable_target_node(node) - emit node - end - - def visit_class_variable_write_node(node) - emit node - end - - def visit_constant_and_write_node(node) - emit node - end - - def visit_constant_operator_write_node(node) - emit node - end - - def visit_constant_or_write_node(node) - emit node - end - - def visit_constant_path_and_write_node(node) - emit node - end - - def visit_constant_path_node(node) - emit node - end - - def visit_constant_path_operator_write_node(node) - emit node - end - - def visit_constant_path_or_write_node(node) - emit node - end - - def visit_constant_path_target_node(node) - emit node - end - - def visit_constant_path_write_node(node) - emit node - end - - def visit_constant_read_node(node) - emit node - end - - def visit_constant_target_node(node) - emit node - end - - def visit_constant_write_node(node) - emit node - end - - def visit_def_node(node) - emit node - end - - def visit_defined_node(node) - emit node - end - - def visit_else_node(node) - emit node - end - - def visit_embedded_statements_node(node) - emit node - end - - def visit_embedded_variable_node(node) - emit node - end - - def visit_ensure_node(node) - emit node - end - - def visit_false_node(node) - emit node - end - - def visit_find_pattern_node(node) - emit node - end - - def visit_flip_flop_node(node) - emit node - end - - def visit_float_node(node) - emit node - end - - def visit_for_node(node) - emit node - end - - def visit_forwarding_arguments_node(node) - emit node - end - - def visit_forwarding_parameter_node(node) - emit node - end - - def visit_forwarding_super_node(node) - emit node - end - - def visit_global_variable_and_write_node(node) - emit node - end - - def visit_global_variable_operator_write_node(node) - emit node - end - - def visit_global_variable_or_write_node(node) - emit node - end - - def visit_global_variable_read_node(node) - emit node - end - - def visit_global_variable_target_node(node) - emit node - end - - def visit_global_variable_write_node(node) - emit node - end - - def visit_hash_node(node) - emit node - end - - def visit_hash_pattern_node(node) - emit node - end - - def visit_if_node(node) - emit node - end - - def visit_imaginary_node(node) - emit node - end - - def visit_implicit_node(node) - emit node - end - - def visit_implicit_rest_node(node) - emit node - end - - def visit_in_node(node) - emit node - end - - def visit_index_and_write_node(node) - emit node - end - - def visit_index_operator_write_node(node) - emit node - end - - def visit_index_or_write_node(node) - emit node - end - - def visit_index_target_node(node) - emit node - end - - def visit_instance_variable_and_write_node(node) - emit node - end - - def visit_instance_variable_operator_write_node(node) - emit node - end - - def visit_instance_variable_or_write_node(node) - emit node - end - - def visit_instance_variable_read_node(node) - emit node - end - - def visit_instance_variable_target_node(node) - emit node - end - - def visit_instance_variable_write_node(node) - emit node - end - - def visit_integer_node(node) - emit node - end - - def visit_interpolated_match_last_line_node(node) - emit node - end - - def visit_interpolated_regular_expression_node(node) - emit node - end - - def visit_interpolated_string_node(node) - emit node - end - - def visit_interpolated_symbol_node(node) - emit node - end - - def visit_interpolated_x_string_node(node) - emit node - end - - def visit_it_local_variable_read_node(node) - emit node - end - - def visit_it_parameters_node(node) - emit node - end - - def visit_keyword_hash_node(node) - emit node - end - - def visit_keyword_rest_parameter_node(node) - emit node - end - - def visit_lambda_node(node) - emit node - end - - def visit_local_variable_and_write_node(node) - emit node - end - - def visit_local_variable_operator_write_node(node) - emit node - end - - def visit_local_variable_or_write_node(node) - emit node - end - - def visit_local_variable_read_node(node) - emit node - end - - def visit_local_variable_target_node(node) - emit node - end - - def visit_local_variable_write_node(node) - emit node - end - - def visit_match_last_line_node(node) - emit node - end - - def visit_match_predicate_node(node) - emit node - end - - def visit_match_required_node(node) - emit node - end - - def visit_match_write_node(node) - emit node - end - - def visit_missing_node(node) - emit node - end - - def visit_module_node(node) - emit node - end - - def visit_multi_target_node(node) - emit node - end - - def visit_multi_write_node(node) - emit node - end - - def visit_next_node(node) - emit node - end - - def visit_nil_node(node) - emit node - end - - def visit_no_keywords_parameter_node(node) - emit node - end - - def visit_numbered_parameters_node(node) - emit node - end - - def visit_numbered_reference_read_node(node) - emit node - end - - def visit_optional_keyword_parameter_node(node) - emit node - end - - def visit_optional_parameter_node(node) - emit node - end - - def visit_or_node(node) - emit node - end - - def visit_parameters_node(node) - emit node - end - - def visit_parentheses_node(node) - emit node - end - - def visit_pinned_expression_node(node) - emit node - end - - def visit_pinned_variable_node(node) - emit node - end - - def visit_post_execution_node(node) - emit node - end - - def visit_pre_execution_node(node) - emit node - end - - def visit_program_node(node) - emit node - end - - def visit_range_node(node) - emit node - end - - def visit_rational_node(node) - emit node - end - - def visit_redo_node(node) - emit node - end - - def visit_regular_expression_node(node) - emit node - end - - def visit_required_keyword_parameter_node(node) - emit node - end - - def visit_required_parameter_node(node) - emit node - end - - def visit_rescue_modifier_node(node) - emit node - end - - def visit_rescue_node(node) - emit node - end - - def visit_rest_parameter_node(node) - emit node - end - - def visit_retry_node(node) - emit node - end - - def visit_return_node(node) - emit node - end - - def visit_self_node(node) - emit node - end - - def visit_shareable_constant_node(node) - emit node - end - - def visit_singleton_class_node(node) - emit node - end - - def visit_source_encoding_node(node) - emit node - end - - def visit_source_file_node(node) - emit node - end - - def visit_source_line_node(node) - emit node - end - - def visit_splat_node(node) - emit node - end - - def visit_statements_node(node) - emit node - end - - def visit_string_node(node) - emit node - end - - def visit_super_node(node) - emit node - end - - def visit_symbol_node(node) - emit node - end - - def visit_true_node(node) - emit node - end - - def visit_undef_node(node) - emit node - end - - def visit_unless_node(node) - emit node - end - - def visit_until_node(node) - emit node - end - - def visit_when_node(node) - emit node - end - - def visit_while_node(node) - emit node - end - - def visit_x_string_node(node) - emit node - end - - def visit_yield_node(node) - emit node - end - end -end