Skip to content

Commit b94162a

Browse files
Earlopainmatzbot
authored andcommitted
[ruby/prism] Preserve line-continuation only in dedent heredocs
Closes ruby/prism#3837 While these lines are whitespace only from a runtime perspective, the line continuation is significant for AST consumers. Sort of a followup to ruby/prism@faab217 ruby/prism@a8a7c6b77d
1 parent 731b609 commit b94162a

3 files changed

Lines changed: 21 additions & 3 deletions

File tree

prism/prism.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15957,6 +15957,19 @@ parse_heredoc_dedent_string(pm_string_t *string, size_t common_whitespace) {
1595715957
string->length = dest_length;
1595815958
}
1595915959

15960+
/**
15961+
* If we end up trimming all of the whitespace from a node and it isn't
15962+
* part of a line continuation, then we'll drop it from the list entirely.
15963+
*/
15964+
static inline bool
15965+
heredoc_dedent_discard_string_node(pm_parser_t *parser, pm_string_node_t *string_node) {
15966+
if (string_node->unescaped.length == 0) {
15967+
const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->content_loc);
15968+
return pm_memchr(cursor, '\\', string_node->content_loc.length, parser->encoding_changed, parser->encoding) == NULL;
15969+
}
15970+
return false;
15971+
}
15972+
1596015973
/**
1596115974
* Take a heredoc node that is indented by a ~ and trim the leading whitespace.
1596215975
*/
@@ -15967,8 +15980,7 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
1596715980
bool dedent_next = true;
1596815981

1596915982
// Iterate over all nodes, and trim whitespace accordingly. We're going to
15970-
// keep around two indices: a read and a write. If we end up trimming all of
15971-
// the whitespace from a node, then we'll drop it from the list entirely.
15983+
// keep around two indices: a read and a write.
1597215984
size_t write_index = 0;
1597315985

1597415986
pm_node_t *node;
@@ -15987,7 +15999,7 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
1598715999
parse_heredoc_dedent_string(&string_node->unescaped, common_whitespace);
1598816000
}
1598916001

15990-
if (string_node->unescaped.length == 0) {
16002+
if (heredoc_dedent_discard_string_node(parser, string_node)) {
1599116003
pm_node_destroy(parser, node);
1599216004
} else {
1599316005
nodes->nodes[write_index++] = node;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<<~FOO
2+
foo\
3+
\
4+
bar
5+
FOO

test/prism/ruby/ruby_parser_test.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class RubyParserTest < TestCase
3737
"alias.txt",
3838
"dsym_str.txt",
3939
"dos_endings.txt",
40+
"heredoc_dedent_line_continuation.txt",
4041
"heredoc_percent_q_newline_delimiter.txt",
4142
"heredocs_with_fake_newlines.txt",
4243
"heredocs_with_ignored_newlines.txt",

0 commit comments

Comments
 (0)