Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 1 addition & 23 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -22282,28 +22282,6 @@ pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t
#undef LINE_SIZE
}

/**
* Determine if there was an unterminated heredoc at the end of the input, which
* would mean the stream isn't finished and we should keep reading.
*
* For the other lex modes we can check if the lex mode has been closed, but for
* heredocs when we hit EOF we close the lex mode and then go back to parse the
* rest of the line after the heredoc declaration so that we get more of the
* syntax tree.
*/
static bool
pm_parse_stream_unterminated_heredoc_p(pm_parser_t *parser) {
pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) parser->error_list.head;

for (; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
return true;
}
}

return false;
}

/**
* Parse a stream of Ruby source and return the tree.
*
Expand All @@ -22319,7 +22297,7 @@ pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse
pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
pm_node_t *node = pm_parse(parser);

while (!eof && parser->error_list.size > 0 && (parser->lex_modes.index > 0 || pm_parse_stream_unterminated_heredoc_p(parser))) {
while (!eof && parser->error_list.size > 0) {
pm_node_destroy(parser, node);
eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);

Expand Down
51 changes: 44 additions & 7 deletions test/prism/api/parse_stream_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,48 +30,85 @@ def test_multi_read
end

def test___END__
io = StringIO.new("1 + 2\n3 + 4\n__END__\n5 + 6")
io = StringIO.new(<<~RUBY)
1 + 2
3 + 4
__END__
5 + 6
RUBY
result = Prism.parse_stream(io)

assert result.success?
assert_equal 2, result.value.statements.body.length
assert_equal "5 + 6", io.read
assert_equal "5 + 6\n", io.read
end

def test_false___END___in_string
io = StringIO.new("1 + 2\n3 + 4\n\"\n__END__\n\"\n5 + 6")
io = StringIO.new(<<~RUBY)
1 + 2
3 + 4
"
__END__
"
5 + 6
RUBY
result = Prism.parse_stream(io)

assert result.success?
assert_equal 4, result.value.statements.body.length
end

def test_false___END___in_regexp
io = StringIO.new("1 + 2\n3 + 4\n/\n__END__\n/\n5 + 6")
io = StringIO.new(<<~RUBY)
1 + 2
3 + 4
/
__END__
/
5 + 6
RUBY
result = Prism.parse_stream(io)

assert result.success?
assert_equal 4, result.value.statements.body.length
end

def test_false___END___in_list
io = StringIO.new("1 + 2\n3 + 4\n%w[\n__END__\n]\n5 + 6")
io = StringIO.new(<<~RUBY)
1 + 2
3 + 4
%w[
__END__
]
5 + 6
RUBY
result = Prism.parse_stream(io)

assert result.success?
assert_equal 4, result.value.statements.body.length
end

def test_false___END___in_heredoc
io = StringIO.new("1 + 2\n3 + 4\n<<-EOF\n__END__\nEOF\n5 + 6")
io = StringIO.new(<<~RUBY)
1 + 2
3 + 4
<<-EOF
__END__
EOF
5 + 6
RUBY
result = Prism.parse_stream(io)

assert result.success?
assert_equal 4, result.value.statements.body.length
end

def test_nul_bytes
io = StringIO.new("1 # \0\0\0 \n2 # \0\0\0\n3")
io = StringIO.new(<<~RUBY)
1 # \0\0\0\t
2 # \0\0\0
3
RUBY
result = Prism.parse_stream(io)

assert result.success?
Expand Down