parse.y: fix here-doc identifier with newline
* parse.y (heredoc_identifier): quoted here-document identifier must end within the same line. the only corner case that here-document identifier can contain a newline is that the closing qoute is placed at the beginning of the next line, and has been warned since 2.4. ```ruby <<"EOS " # warning: here document identifier ends with a newline EOS ```
This commit is contained in:
parent
69cad44fac
commit
330b376133
6
NEWS
6
NEWS
@ -42,6 +42,12 @@ sufficient information, see the ChangeLog file or Redmine
|
|||||||
* Setting <code>$,</code> to non-nil value is warned now. Use of it in
|
* Setting <code>$,</code> to non-nil value is warned now. Use of it in
|
||||||
Array#join is warned too.
|
Array#join is warned too.
|
||||||
|
|
||||||
|
* Quoted here-document identifier must end within the same line.
|
||||||
|
|
||||||
|
<<"EOS
|
||||||
|
" # This has been warned since 2.4
|
||||||
|
EOS
|
||||||
|
|
||||||
=== Core classes updates (outstanding ones only)
|
=== Core classes updates (outstanding ones only)
|
||||||
|
|
||||||
Enumerable::
|
Enumerable::
|
||||||
|
@ -255,6 +255,9 @@ behaves like Kernel#`:
|
|||||||
cat #{__FILE__}
|
cat #{__FILE__}
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
|
When surrounding with quotes, any characters but that quote and newline
|
||||||
|
can be used as the identifier.
|
||||||
|
|
||||||
To call a method on a heredoc place it after the opening identifier:
|
To call a method on a heredoc place it after the opening identifier:
|
||||||
|
|
||||||
expected_result = <<-EXPECTED.chomp
|
expected_result = <<-EXPECTED.chomp
|
||||||
|
14
parse.y
14
parse.y
@ -6788,7 +6788,6 @@ heredoc_identifier(struct parser_params *p)
|
|||||||
int c = nextc(p), term, func = 0, term_len = 2;
|
int c = nextc(p), term, func = 0, term_len = 2;
|
||||||
enum yytokentype token = tSTRING_BEG;
|
enum yytokentype token = tSTRING_BEG;
|
||||||
long len;
|
long len;
|
||||||
int newline = 0;
|
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
|
|
||||||
if (c == '-') {
|
if (c == '-') {
|
||||||
@ -6821,23 +6820,14 @@ heredoc_identifier(struct parser_params *p)
|
|||||||
tokadd(p, func);
|
tokadd(p, func);
|
||||||
term = c;
|
term = c;
|
||||||
while ((c = nextc(p)) != -1 && c != term) {
|
while ((c = nextc(p)) != -1 && c != term) {
|
||||||
|
if (c == '\n') goto unterminated;
|
||||||
if (tokadd_mbchar(p, c) == -1) return 0;
|
if (tokadd_mbchar(p, c) == -1) return 0;
|
||||||
if (!newline && c == '\n') newline = 1;
|
|
||||||
else if (newline) newline = 2;
|
|
||||||
}
|
}
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
|
unterminated:
|
||||||
yyerror(NULL, p, "unterminated here document identifier");
|
yyerror(NULL, p, "unterminated here document identifier");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
switch (newline) {
|
|
||||||
case 1:
|
|
||||||
rb_warn0("here document identifier ends with a newline");
|
|
||||||
if (--p->tokidx > 0 && p->tokenbuf[p->tokidx] == '\r') --p->tokidx;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
compile_error(p, "here document identifier across newlines, never match");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -852,10 +852,9 @@ eom
|
|||||||
assert_syntax_error("puts <<""EOS\n""ng\n""EOS\r""NO\n", /can't find string "EOS" anywhere before EOF/)
|
assert_syntax_error("puts <<""EOS\n""ng\n""EOS\r""NO\n", /can't find string "EOS" anywhere before EOF/)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_heredoc_newline
|
def test_unterminated_heredoc
|
||||||
assert_warn(/ends with a newline/) do
|
assert_syntax_error("<<\"EOS\n\nEOS\n", /unterminated/)
|
||||||
eval("<<\"EOS\n\"\nEOS\n")
|
assert_syntax_error("<<\"EOS\n\"\nEOS\n", /unterminated/)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test__END___cr
|
def test__END___cr
|
||||||
|
Loading…
x
Reference in New Issue
Block a user