Skip to content

Commit 34899bd

Browse files
committed
Fix incompatibilities for on_word_sep in ripper
It was mostly good, just a few edgecases: * word_sep always only contains a single line. if there are multiple lines, it is also multiple word_sep * Handle trailing whitespace The excluded testcase is interpolation mixed with heredoc. That is not currently handled properly and word_sep contains the content of the heredoc I also switched start/end_offset names in the method, they seem to be backwards
1 parent c4d202d commit 34899bd

2 files changed

Lines changed: 28 additions & 14 deletions

File tree

lib/prism/translation/ripper.rb

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -696,14 +696,16 @@ def visit_array_node(node)
696696
previous = nil
697697

698698
node.elements.each do |element|
699-
visit_words_sep(opening_loc, previous, element)
699+
visit_words_sep(opening_loc, previous, element.start_offset)
700700

701701
bounds(element.location)
702702
elements = on_qwords_add(elements, on_tstring_content(element.content))
703703

704704
previous = element
705705
end
706706

707+
visit_words_sep(opening_loc, node.elements.last, node.closing_loc.start_offset)
708+
707709
bounds(node.closing_loc)
708710
on_tstring_end(node.closing)
709711
when /^%i/
@@ -715,14 +717,16 @@ def visit_array_node(node)
715717
previous = nil
716718

717719
node.elements.each do |element|
718-
visit_words_sep(opening_loc, previous, element)
720+
visit_words_sep(opening_loc, previous, element.start_offset)
719721

720722
bounds(element.location)
721723
elements = on_qsymbols_add(elements, on_tstring_content(element.value))
722724

723725
previous = element
724726
end
725727

728+
visit_words_sep(opening_loc, node.elements.last, node.closing_loc.start_offset)
729+
726730
bounds(node.closing_loc)
727731
on_tstring_end(node.closing)
728732
when /^%W/
@@ -734,7 +738,7 @@ def visit_array_node(node)
734738
previous = nil
735739

736740
node.elements.each do |element|
737-
visit_words_sep(opening_loc, previous, element)
741+
visit_words_sep(opening_loc, previous, element.start_offset)
738742

739743
bounds(element.location)
740744
elements =
@@ -760,6 +764,8 @@ def visit_array_node(node)
760764
previous = element
761765
end
762766

767+
visit_words_sep(opening_loc, node.elements.last, node.closing_loc.start_offset)
768+
763769
bounds(node.closing_loc)
764770
on_tstring_end(node.closing)
765771
when /^%I/
@@ -771,7 +777,7 @@ def visit_array_node(node)
771777
previous = nil
772778

773779
node.elements.each do |element|
774-
visit_words_sep(opening_loc, previous, element)
780+
visit_words_sep(opening_loc, previous, element.start_offset)
775781

776782
bounds(element.location)
777783
elements =
@@ -797,6 +803,8 @@ def visit_array_node(node)
797803
previous = element
798804
end
799805

806+
visit_words_sep(opening_loc, node.elements.last, node.closing_loc.start_offset)
807+
800808
bounds(node.closing_loc)
801809
on_tstring_end(node.closing)
802810
else
@@ -813,15 +821,20 @@ def visit_array_node(node)
813821
on_array(elements)
814822
end
815823

816-
# Dispatch a words_sep event that contains the space between the elements
824+
# Dispatch words_sep events that contains the whitespace between the elements
817825
# of list literals.
818-
private def visit_words_sep(opening_loc, previous, current)
819-
end_offset = (previous.nil? ? opening_loc : previous.location).end_offset
820-
start_offset = current.location.start_offset
821-
822-
if end_offset != start_offset
823-
bounds(current.location.copy(start_offset: end_offset))
824-
on_words_sep(source.byteslice(end_offset...start_offset))
826+
private def visit_words_sep(opening_loc, previous, end_offset)
827+
start_offset = (previous.nil? ? opening_loc : previous.location).end_offset
828+
length = end_offset - start_offset
829+
830+
if length > 0
831+
whitespace = source.byteslice(start_offset, length)
832+
current_offset = start_offset
833+
whitespace.each_line do |part|
834+
bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize))
835+
on_words_sep(part)
836+
current_offset += part.bytesize
837+
end
825838
end
826839
end
827840

test/prism/ruby/ripper_test.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class RipperTest < TestCase
101101
"seattlerb/messy_op_asgn_lineno.txt",
102102
"seattlerb/op_asgn_primary_colon_const_command_call.txt",
103103
"seattlerb/parse_pattern_076.txt",
104+
"seattlerb/pct_w_heredoc_interp_nested.txt",
104105
"tilde_heredocs.txt",
105106
"unparser/corpus/literal/assignment.txt",
106107
"unparser/corpus/literal/pattern.txt",
@@ -138,11 +139,11 @@ def test_lex_ignored_missing_heredoc_end
138139
end
139140
end
140141

141-
UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end nl semicolon sp words_sep ignored_sp]
142+
UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end nl semicolon sp ignored_sp]
142143
# Events that are currently not emitted
143144
SUPPORTED_EVENTS = Translation::Ripper::EVENTS - UNSUPPORTED_EVENTS
144145
# Events that assert against their line/column
145-
CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen]
146+
CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen words_sep]
146147

147148
module Events
148149
attr_reader :events

0 commit comments

Comments
 (0)