summaryrefslogtreecommitdiff
path: root/lib/prism/translation/parser/compiler.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/prism/translation/parser/compiler.rb')
-rw-r--r--lib/prism/translation/parser/compiler.rb111
1 files changed, 56 insertions, 55 deletions
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index 54e08eb991..c6a7154625 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -1511,13 +1511,9 @@ module Prism
# /foo/
# ^^^^^
def visit_regular_expression_node(node)
- content = node.content
parts =
- if content.include?("\n")
- offset = node.content_loc.start_offset
- content.lines.map do |line|
- builder.string_internal([line, srange_offsets(offset, offset += line.bytesize)])
- end
+ if node.content.include?("\n")
+ string_nodes_from_line_continuations(node, node.content_loc.start_offset, node.opening)
else
[builder.string_internal(token(node.content_loc))]
end
@@ -2074,55 +2070,7 @@ module Prism
node.parts.each do |part|
pushing =
if part.is_a?(StringNode) && part.unescaped.include?("\n")
- unescaped = part.unescaped.lines
- escaped = part.content.lines
-
- escaped_lengths = []
- normalized_lengths = []
- # Keeps track of where an unescaped line should start a new token. An unescaped
- # \n would otherwise be indistinguishable from the actual newline at the end of
- # of the line. The parser gem only emits a new string node at "real" newlines,
- # line continuations don't start a new node as well.
- do_next_tokens = []
-
- if node.opening.end_with?("'")
- escaped.each do |line|
- escaped_lengths << line.bytesize
- normalized_lengths << chomped_bytesize(line)
- do_next_tokens << true
- end
- else
- escaped
- .chunk_while { |before, after| before[/(\\*)\r?\n$/, 1]&.length&.odd? || false }
- .each do |lines|
- escaped_lengths << lines.sum(&:bytesize)
- normalized_lengths << lines.sum { |line| chomped_bytesize(line) }
- unescaped_lines_count = lines.sum do |line|
- line.scan(/(\\*)n/).count { |(backslashes)| backslashes&.length&.odd? || false }
- end
- do_next_tokens.concat(Array.new(unescaped_lines_count + 1, false))
- do_next_tokens[-1] = true
- end
- end
-
- start_offset = part.location.start_offset
- current_line = +""
- current_normalized_length = 0
-
- unescaped.filter_map.with_index do |unescaped_line, index|
- current_line << unescaped_line
- current_normalized_length += normalized_lengths.fetch(index, 0)
-
- if do_next_tokens[index]
- inner_part = builder.string_internal([current_line, srange_offsets(start_offset, start_offset + current_normalized_length)])
- start_offset += escaped_lengths.fetch(index, 0)
- current_line = +""
- current_normalized_length = 0
- inner_part
- else
- nil
- end
- end
+ string_nodes_from_line_continuations(part, part.location.start_offset, node.opening)
else
[visit(part)]
end
@@ -2172,6 +2120,59 @@ module Prism
parser.pattern_variables.pop
end
end
+
+ # Create parser string nodes from a single prism node. The parser gem
+ # "glues" strings together when a line continuation is encountered.
+ def string_nodes_from_line_continuations(node, start_offset, opening)
+ unescaped = node.unescaped.lines
+ escaped = node.content.lines
+
+ escaped_lengths = []
+ normalized_lengths = []
+ # Keeps track of where an unescaped line should start a new token. An unescaped
+ # \n would otherwise be indistinguishable from the actual newline at the end of
+ # of the line. The parser gem only emits a new string node at "real" newlines,
+ # line continuations don't start a new node as well.
+ do_next_tokens = []
+
+ if opening.end_with?("'")
+ escaped.each do |line|
+ escaped_lengths << line.bytesize
+ normalized_lengths << chomped_bytesize(line)
+ do_next_tokens << true
+ end
+ else
+ escaped
+ .chunk_while { |before, after| before[/(\\*)\r?\n$/, 1]&.length&.odd? || false }
+ .each do |lines|
+ escaped_lengths << lines.sum(&:bytesize)
+ normalized_lengths << lines.sum { |line| chomped_bytesize(line) }
+ unescaped_lines_count = lines.sum do |line|
+ line.scan(/(\\*)n/).count { |(backslashes)| backslashes&.length&.odd? || false }
+ end
+ do_next_tokens.concat(Array.new(unescaped_lines_count + 1, false))
+ do_next_tokens[-1] = true
+ end
+ end
+
+ current_line = +""
+ current_normalized_length = 0
+
+ unescaped.filter_map.with_index do |unescaped_line, index|
+ current_line << unescaped_line
+ current_normalized_length += normalized_lengths.fetch(index, 0)
+
+ if do_next_tokens[index]
+ inner_part = builder.string_internal([current_line, srange_offsets(start_offset, start_offset + current_normalized_length)])
+ start_offset += escaped_lengths.fetch(index, 0)
+ current_line = +""
+ current_normalized_length = 0
+ inner_part
+ else
+ nil
+ end
+ end
+ end
end
end
end