instance method
Prism::Translation::Parser::Compiler#string_nodes_from_line_continuations
string_nodes_from_line_continuations(unescaped, escaped, start_offset, opening)
lib/prism/translation/parser/compiler.rb
View on GitHub ↗
# File tmp/rubies/ruby-4.0.0/lib/prism/translation/parser/compiler.rb, line 2150
def string_nodes_from_line_continuations(unescaped, escaped, start_offset, opening)
unescaped = unescaped.lines
escaped = escaped.lines
percent_array = opening&.start_with?("%w", "%W", "%i", "%I")
regex = opening == "/" || opening&.start_with?("%r")
# Non-interpolating strings
if opening&.end_with?("'") || opening&.start_with?("%q", "%s", "%w", "%i")
current_length = 0
current_line = +""
escaped.filter_map.with_index do |escaped_line, index|
unescaped_line = unescaped.fetch(index, "")
current_length += escaped_line.bytesize
current_line << unescaped_line
# Glue line continuations together. Only %w and %i arrays can contain these.
if percent_array && escaped_line[/(\\)*\n$/, 1]&.length&.odd?
next unless index == escaped.count - 1
end
s = builder.string_internal([current_line, srange_offsets(start_offset, start_offset + current_length)])
start_offset += escaped_line.bytesize
current_line = +""
current_length = 0
s
end
else
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 = []
escaped
.chunk_while { |before, after| before[/(\\*)\r?\n$/, 1]&.length&.odd? || false }
.each do |lines|
escaped_lengths << lines.sum(&:bytesize)
unescaped_lines_count =
if regex
0 # Will always be preserved as is
else
lines.sum do |line|
count = line.scan(/(\\*)n/).count { |(backslashes)| backslashes&.length&.odd? }
count -= 1 if !line.end_with?("\n") && count > 0
count
end
end
extra = 1
extra = lines.count if percent_array # Account for line continuations in percent arrays
normalized_lengths.concat(Array.new(unescaped_lines_count + extra, 0))
normalized_lengths[-1] = lines.sum { |line| line.bytesize }
do_next_tokens.concat(Array.new(unescaped_lines_count + extra, false))
do_next_tokens[-1] = true
end
current_line = +""
current_normalized_length = 0
emitted_count = 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(emitted_count, 0)
current_line = +""
current_normalized_length = 0
emitted_count += 1
inner_part
else
nil
end
end
end
end
Create parser string nodes from a single prism node. The parser gem “glues” strings together when a line continuation is encountered.