123456789_123456789_123456789_123456789_123456789_

Class: Prism::ParseResult::Newlines

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: Prism::Visitor
Defined in: lib/prism/parse_result/newlines.rb

Overview

The :line tracepoint event gets fired whenever the Ruby VM encounters an expression on a new line. The types of expressions that can trigger this event are:

  • if statements
  • unless statements
  • nodes that are children of statements lists

In order to keep track of the newlines, we have a list of offsets that come back from the parser. We assign these offsets to the first nodes that we find in the tree that are on those lines.

Note that the logic in this file should be kept in sync with the Java MarkNewlinesVisitor, since that visitor is responsible for marking the newlines for JRuby/TruffleRuby.

This file is autoloaded only when #mark_newlines! is called, so the re-opening of the various nodes in this file will only be performed in that case. We do that to avoid storing the extra @newline instance variable on every node if we don't need it.

Class Method Summary

Instance Method Summary

::Prism::Visitor - Inherited

#visit_alias_global_variable_node
#visit_alias_method_node
#visit_alternation_pattern_node
#visit_and_node
#visit_arguments_node
#visit_array_node
#visit_array_pattern_node
#visit_assoc_node
#visit_assoc_splat_node
#visit_back_reference_read_node
#visit_begin_node
#visit_block_argument_node
#visit_block_local_variable_node
#visit_block_node
#visit_block_parameter_node
#visit_block_parameters_node
#visit_break_node
#visit_call_and_write_node
#visit_call_node
#visit_call_operator_write_node
#visit_call_or_write_node
#visit_call_target_node
#visit_capture_pattern_node
#visit_case_match_node
#visit_case_node
#visit_class_node
#visit_class_variable_and_write_node
#visit_class_variable_operator_write_node
#visit_class_variable_or_write_node
#visit_class_variable_read_node
#visit_class_variable_target_node
#visit_class_variable_write_node
#visit_constant_and_write_node
#visit_constant_operator_write_node
#visit_constant_or_write_node
#visit_constant_path_and_write_node
#visit_constant_path_node
#visit_constant_path_operator_write_node
#visit_constant_path_or_write_node
#visit_constant_path_target_node
#visit_constant_path_write_node
#visit_constant_read_node
#visit_constant_target_node
#visit_constant_write_node
#visit_def_node
#visit_defined_node
#visit_else_node
#visit_embedded_statements_node
#visit_embedded_variable_node
#visit_ensure_node
#visit_false_node
#visit_find_pattern_node
#visit_flip_flop_node
#visit_float_node
#visit_for_node
#visit_forwarding_arguments_node
#visit_forwarding_parameter_node
#visit_forwarding_super_node
#visit_global_variable_and_write_node
#visit_global_variable_operator_write_node
#visit_global_variable_or_write_node
#visit_global_variable_read_node
#visit_global_variable_target_node
#visit_global_variable_write_node
#visit_hash_node
#visit_hash_pattern_node
#visit_if_node
#visit_imaginary_node
#visit_implicit_node
#visit_implicit_rest_node
#visit_in_node
#visit_index_and_write_node
#visit_index_operator_write_node
#visit_index_or_write_node
#visit_index_target_node
#visit_instance_variable_and_write_node
#visit_instance_variable_operator_write_node
#visit_instance_variable_or_write_node
#visit_instance_variable_read_node
#visit_instance_variable_target_node
#visit_instance_variable_write_node
#visit_integer_node
#visit_interpolated_match_last_line_node
#visit_interpolated_regular_expression_node
#visit_interpolated_string_node
#visit_interpolated_symbol_node
#visit_interpolated_x_string_node
#visit_it_local_variable_read_node
#visit_it_parameters_node
#visit_keyword_hash_node
#visit_keyword_rest_parameter_node
#visit_lambda_node
#visit_local_variable_and_write_node
#visit_local_variable_operator_write_node
#visit_local_variable_or_write_node
#visit_local_variable_read_node
#visit_local_variable_target_node
#visit_local_variable_write_node
#visit_match_last_line_node
#visit_match_predicate_node
#visit_match_required_node
#visit_match_write_node
#visit_missing_node
#visit_module_node
#visit_multi_target_node
#visit_multi_write_node
#visit_next_node
#visit_nil_node
#visit_no_keywords_parameter_node
#visit_numbered_parameters_node
#visit_numbered_reference_read_node
#visit_optional_keyword_parameter_node
#visit_optional_parameter_node
#visit_or_node
#visit_parameters_node
#visit_parentheses_node
#visit_pinned_expression_node
#visit_pinned_variable_node
#visit_post_execution_node
#visit_pre_execution_node
#visit_program_node
#visit_range_node
#visit_rational_node
#visit_redo_node
#visit_regular_expression_node
#visit_required_keyword_parameter_node
#visit_required_parameter_node
#visit_rescue_modifier_node
#visit_rescue_node
#visit_rest_parameter_node
#visit_retry_node
#visit_return_node
#visit_self_node
#visit_shareable_constant_node
#visit_singleton_class_node
#visit_source_encoding_node
#visit_source_file_node
#visit_source_line_node
#visit_splat_node
#visit_statements_node
#visit_string_node
#visit_super_node
#visit_symbol_node
#visit_true_node
#visit_undef_node
#visit_unless_node
#visit_until_node
#visit_when_node
#visit_while_node
#visit_x_string_node
#visit_yield_node

::Prism::BasicVisitor - Inherited

#visit

Calls accept on the given node if it is not nil, which in turn should call back into this visitor by calling the appropriate visit_* method.

#visit_all

Visits each node in nodes by calling accept on each one.

#visit_child_nodes

Visits the child nodes of node by calling accept on each one.

Constructor Details

.new(lines) ⇒ Newlines

Create a new Newlines visitor with the given newline offsets.

: (Integer lines) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 36

def initialize(lines)
  @lines = Array.new(1 + lines, false)
end

Instance Method Details

#visit_block_node(node)

Permit block nodes to mark newlines within themselves.

: (BlockNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 43

def visit_block_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_class_node(node)

Permit class nodes to mark newlines within themselves.

: (ClassNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 88

def visit_class_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_def_node(node)

Permit def nodes to mark newlines within themselves. The body of an endless method definition never emits newline events, so in that case mark every line as already seen while visiting it instead. Nested scopes (blocks, lambdas, etc.) reset the lines and emit events again.

: (DefNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 74

def visit_def_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, !node.equal_loc.nil?)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_embedded_statements_node(node)

Statements inside string interpolation do not emit newline events, so mark every line as already seen while visiting them. Nested scopes (blocks, lambdas, defs, etc.) reset the lines and emit events again.

: (EmbeddedStatementsNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 132

def visit_embedded_statements_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, true)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_if_node(node)

Mark if nodes as newlines.

: (IfNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 182

def visit_if_node(node)
  node.newline_flag!(@lines)
  super(node)
end

#visit_lambda_node(node)

Permit lambda nodes to mark newlines within themselves.

: (LambdaNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 57

def visit_lambda_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_module_node(node)

Permit module nodes to mark newlines within themselves.

: (ModuleNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 102

def visit_module_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_singleton_class_node(node)

Permit singleton class nodes to mark newlines within themselves.

: (SingletonClassNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 116

def visit_singleton_class_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    super(node)
  ensure
    @lines = old_lines
  end
end

#visit_statements_node(node)

Permit statements lists to mark newlines within themselves.

: (StatementsNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 198

def visit_statements_node(node)
  node.body.each do |child|
    child.newline_flag!(@lines)
  end
  super(node)
end

#visit_unless_node(node)

Mark unless nodes as newlines.

: (UnlessNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 190

def visit_unless_node(node)
  node.newline_flag!(@lines)
  super(node)
end

#visit_until_node(node)

The predicate of an until loop is compiled at the end of the loop, after the body, so any statements it contains (from parentheses) emit their line events again even if the lines were already seen.

: (UntilNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 166

def visit_until_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    visit(node.predicate)
  ensure
    @lines = old_lines
  end

  visit(node.statements)
end

#visit_while_node(node)

The predicate of a while loop is compiled at the end of the loop, after the body, so any statements it contains (from parentheses) emit their line events again even if the lines were already seen.

: (WhileNode node) -> void

[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 148

def visit_while_node(node)
  old_lines = @lines
  @lines = Array.new(old_lines.size, false)

  begin
    visit(node.predicate)
  ensure
    @lines = old_lines
  end

  visit(node.statements)
end