diff --git a/src/prism.c b/src/prism.c index 1b3cb10b61..a968e2dbbc 100644 --- a/src/prism.c +++ b/src/prism.c @@ -10700,6 +10700,14 @@ parser_lex(pm_parser_t *parser) { // We'll check if we're at the end of the file. If we are, then we // need to return the EOF token. if (parser->current.end >= parser->end) { + // If we hit EOF, but the EOF came immediately after a newline, + // set the start of the token to the newline. This way any EOF + // errors will be reported as happening on that line rather than + // a line after. For example "foo(\n" should report an error + // on line 1 even though EOF technically occurs on line 2. + if (parser->current.start > parser->start && (*(parser->current.start - 1) == '\n')) { + parser->current.start -= 1; + } LEX(PM_TOKEN_EOF); } diff --git a/test/prism/errors/unterminated_block.txt b/test/prism/errors/unterminated_block.txt new file mode 100644 index 0000000000..8cc772db16 --- /dev/null +++ b/test/prism/errors/unterminated_block.txt @@ -0,0 +1,4 @@ +foo { + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected a block beginning with `{` to end with `}` + diff --git a/test/prism/errors/unterminated_method_parameters.txt b/test/prism/errors/unterminated_method_parameters.txt new file mode 100644 index 0000000000..e71371ba16 --- /dev/null +++ b/test/prism/errors/unterminated_method_parameters.txt @@ -0,0 +1,3 @@ +foo( + ^ unexpected end-of-input; expected a `)` to close the arguments + diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index f46cb942a2..a96c2e488d 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -32,6 +32,17 @@ class ErrorsTest < TestCase end end + def test_newline_preceding_eof + err = Prism.parse("foo(").errors.first + assert_equal 1, err.location.start_line + + err = Prism.parse("foo(\n").errors.first + assert_equal 1, err.location.start_line + + err = Prism.parse("foo(\n\n\n\n\n").errors.first + assert_equal 5, err.location.start_line + end + def test_embdoc_ending source = <<~RUBY =begin\n=end