1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
# frozen_string_literal: true
# :markup: markdown
module Prism
class ParseResult < Result
# 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 Newlines < Visitor
# Create a new Newlines visitor with the given newline offsets.
def initialize(lines)
# @type var lines: Integer
@lines = Array.new(1 + lines, false)
end
# Permit block/lambda nodes to mark newlines within themselves.
def visit_block_node(node)
old_lines = @lines
@lines = Array.new(old_lines.size, false)
begin
super(node)
ensure
@lines = old_lines
end
end
alias_method :visit_lambda_node, :visit_block_node
# Mark if/unless nodes as newlines.
def visit_if_node(node)
node.newline_flag!(@lines)
super(node)
end
alias_method :visit_unless_node, :visit_if_node
# Permit statements lists to mark newlines within themselves.
def visit_statements_node(node)
node.body.each do |child|
child.newline_flag!(@lines)
end
super(node)
end
end
end
class Node
def newline_flag? # :nodoc:
!!defined?(@newline_flag)
end
def newline_flag!(lines) # :nodoc:
line = location.start_line
unless lines[line]
lines[line] = true
@newline_flag = true
end
end
end
class BeginNode < Node
def newline_flag!(lines) # :nodoc:
# Never mark BeginNode with a newline flag, mark children instead.
end
end
class ParenthesesNode < Node
def newline_flag!(lines) # :nodoc:
# Never mark ParenthesesNode with a newline flag, mark children instead.
end
end
class IfNode < Node
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class UnlessNode < Node
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class UntilNode < Node
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class WhileNode < Node
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class RescueModifierNode < Node
def newline_flag!(lines) # :nodoc:
expression.newline_flag!(lines)
end
end
class InterpolatedMatchLastLineNode < Node
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
end
end
class InterpolatedRegularExpressionNode < Node
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
end
end
class InterpolatedStringNode < Node
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
end
end
class InterpolatedSymbolNode < Node
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
end
end
class InterpolatedXStringNode < Node
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
end
end
end
|