aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-01-02 17:10:10 -0500
committergit <svn-admin@ruby-lang.org>2024-01-03 16:46:08 +0000
commit0215965df4ef8b70a1cd3668ed64821e9f25538a (patch)
treeac3b3db9e945b256ae573071442784868425d5ee
parenta1d0c621e90a5e1c44b8e18210a5d97f77df3472 (diff)
downloadruby-0215965df4ef8b70a1cd3668ed64821e9f25538a.tar.gz
[ruby/prism] Better error recovery for content after unterminated heredoc
https://github.com/ruby/prism/commit/c2d325a886
-rw-r--r--prism/prism.c21
-rw-r--r--test/prism/errors_test.rb9
2 files changed, 23 insertions, 7 deletions
diff --git a/prism/prism.c b/prism/prism.c
index bc758b49f2..4aeef976c9 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -8658,7 +8658,7 @@ parser_lex(pm_parser_t *parser) {
// this is not a valid heredoc declaration. In this case we
// will add an error, but we will still return a heredoc
// start.
- pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
+ pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM);
body_start = parser->end;
} else {
// Otherwise, we want to indicate that the body of the
@@ -9911,15 +9911,22 @@ parser_lex(pm_parser_t *parser) {
parser->next_start = NULL;
}
- // We'll check if we're at the end of the file. If we are, then we need to
- // return the EOF token.
+ // Now let's grab the information about the identifier off of the
+ // current lex mode.
+ pm_lex_mode_t *lex_mode = parser->lex_modes.current;
+
+ // We'll check if we're at the end of the file. If we are, then we
+ // will add an error (because we weren't able to find the
+ // terminator) but still continue parsing so that content after the
+ // declaration of the heredoc can be parsed.
if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
+ pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM);
+ parser->next_start = lex_mode->as.heredoc.next_start;
+ parser->heredoc_end = parser->current.end;
+ lex_state_set(parser, PM_LEX_STATE_END);
+ LEX(PM_TOKEN_HEREDOC_END);
}
- // Now let's grab the information about the identifier off of the current
- // lex mode.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
const uint8_t *ident_start = lex_mode->as.heredoc.ident_start;
size_t ident_length = lex_mode->as.heredoc.ident_length;
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 9e7bb10762..7ce6d17be5 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -1248,6 +1248,15 @@ module Prism
assert_errors expected, "def foo(a = 1,b,*c);end", [["unexpected parameter `*`", 16..17]]
end
+ def test_content_after_unterminated_heredoc
+ receiver = StringNode(0, Location(), Location(), Location(), "")
+ expected = CallNode(0, receiver, Location(), :foo, Location(), nil, nil, nil, nil)
+
+ assert_errors expected, "<<~FOO.foo\n", [
+ ["could not find a terminator for the heredoc", 11..11]
+ ]
+ end
+
def test_invalid_message_name
result = Prism.parse("+.@foo,+=foo")
assert_equal :"", result.value.statements.body.first.write_name