Skip to content

Commit 0924ff2

Browse files
st0012matzbot
authored andcommitted
[ruby/prism] Fix parser translation's heredoc whitespace calculation
Given this example: ```rb <<~HEREDOC #{x} HEREDOC ``` Both the parser gem and Prism's translation layer would generate the following AST: ``` s(:dstr, s(:begin, s(:int, 1)), s(:str, " a\n")) ``` However, the parser gem inserts a empty string node into this node's location, like: ``` <Parser::Source::Map::Heredoc:0x0000000104ce73b8 @expression=#<Parser::Source::Range (string) 0...10>, @heredoc_body=#<Parser::Source::Range (string) 11...20>, @heredoc_end=#<Parser::Source::Range (string) 20...27>, @node=s(:dstr, s(:str, ""), s(:begin, s(:int, 1)), s(:str, " a\n"))> ``` This is required to calculate the correct whitespace for the heredoc body. We need to adjust the translation layer to account for this. With this fix, we also won't need to ignore the tilde heredoc fixture anymore. ruby/prism@e7372e3ba5
1 parent abd05c8 commit 0924ff2

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

lib/prism/translation/parser/compiler.rb

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,8 +947,35 @@ def visit_interpolated_regular_expression_node(node)
947947
def visit_interpolated_string_node(node)
948948
if node.heredoc?
949949
children, closing = visit_heredoc(node)
950+
opening = token(node.opening_loc)
951+
952+
start_offset = node.opening_loc.end_offset + 1
953+
end_offset = node.parts.first.location.start_offset
954+
955+
# In the below case, the offsets should be the same:
956+
#
957+
# <<~HEREDOC
958+
# a #{b}
959+
# HEREDOC
960+
#
961+
# But in this case, the end_offset would be greater than the start_offset:
962+
#
963+
# <<~HEREDOC
964+
# #{b}
965+
# HEREDOC
966+
#
967+
# So we need to make sure the result node's heredoc range is correct, without updating the children
968+
result = if start_offset < end_offset
969+
# We need to add a padding string to ensure that the heredoc has correct range for its body
970+
padding_string_node = builder.string_internal(["", srange_offsets(start_offset, end_offset)])
971+
node_with_correct_location = builder.string_compose(opening, [padding_string_node, *children], closing)
972+
# But the padding string should not be included in the final AST, so we need to update the result's children
973+
node_with_correct_location.updated(:dstr, children)
974+
else
975+
builder.string_compose(opening, children, closing)
976+
end
950977

951-
return builder.string_compose(token(node.opening_loc), children, closing)
978+
return result
952979
end
953980

954981
parts = if node.parts.one? { |part| part.type == :string_node }

test/prism/parser_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class ParserTest < TestCase
5959
"regex_char_width.txt",
6060
"spanning_heredoc.txt",
6161
"spanning_heredoc_newlines.txt",
62-
"tilde_heredocs.txt",
6362
"unescaping.txt"
6463
]
6564

@@ -76,6 +75,7 @@ class ParserTest < TestCase
7675
"indented_file_end.txt",
7776
"methods.txt",
7877
"strings.txt",
78+
"tilde_heredocs.txt",
7979
"xstring_with_backslash.txt"
8080
]
8181

0 commit comments

Comments
 (0)