Skip to content

Commit 0215965

Browse files
kddnewtonmatzbot
authored andcommitted
[ruby/prism] Better error recovery for content after unterminated heredoc
ruby/prism@c2d325a886
1 parent a1d0c62 commit 0215965

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

prism/prism.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8658,7 +8658,7 @@ parser_lex(pm_parser_t *parser) {
86588658
// this is not a valid heredoc declaration. In this case we
86598659
// will add an error, but we will still return a heredoc
86608660
// start.
8661-
pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
8661+
pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM);
86628662
body_start = parser->end;
86638663
} else {
86648664
// Otherwise, we want to indicate that the body of the
@@ -9911,15 +9911,22 @@ parser_lex(pm_parser_t *parser) {
99119911
parser->next_start = NULL;
99129912
}
99139913

9914-
// We'll check if we're at the end of the file. If we are, then we need to
9915-
// return the EOF token.
9914+
// Now let's grab the information about the identifier off of the
9915+
// current lex mode.
9916+
pm_lex_mode_t *lex_mode = parser->lex_modes.current;
9917+
9918+
// We'll check if we're at the end of the file. If we are, then we
9919+
// will add an error (because we weren't able to find the
9920+
// terminator) but still continue parsing so that content after the
9921+
// declaration of the heredoc can be parsed.
99169922
if (parser->current.end >= parser->end) {
9917-
LEX(PM_TOKEN_EOF);
9923+
pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM);
9924+
parser->next_start = lex_mode->as.heredoc.next_start;
9925+
parser->heredoc_end = parser->current.end;
9926+
lex_state_set(parser, PM_LEX_STATE_END);
9927+
LEX(PM_TOKEN_HEREDOC_END);
99189928
}
99199929

9920-
// Now let's grab the information about the identifier off of the current
9921-
// lex mode.
9922-
pm_lex_mode_t *lex_mode = parser->lex_modes.current;
99239930
const uint8_t *ident_start = lex_mode->as.heredoc.ident_start;
99249931
size_t ident_length = lex_mode->as.heredoc.ident_length;
99259932

test/prism/errors_test.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,15 @@ def test_duplicated_parameter_names
12481248
assert_errors expected, "def foo(a = 1,b,*c);end", [["unexpected parameter `*`", 16..17]]
12491249
end
12501250

1251+
def test_content_after_unterminated_heredoc
1252+
receiver = StringNode(0, Location(), Location(), Location(), "")
1253+
expected = CallNode(0, receiver, Location(), :foo, Location(), nil, nil, nil, nil)
1254+
1255+
assert_errors expected, "<<~FOO.foo\n", [
1256+
["could not find a terminator for the heredoc", 11..11]
1257+
]
1258+
end
1259+
12511260
def test_invalid_message_name
12521261
result = Prism.parse("+.@foo,+=foo")
12531262
assert_equal :"", result.value.statements.body.first.write_name

0 commit comments

Comments
 (0)