Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix line continuations in literals #3362

Merged
merged 2 commits into from
Sep 11, 2020
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

'a\
b'
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
s(:dstr,
s(:str, "a\
"),
s(:str, "b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# typed: strict

<<-'HERE'
a\
b
HERE
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
s(:dstr,
s(:str, "a\
"),
s(:str, "b
"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%I{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:array,
s(:sym, :a\nb))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

:'a\
b'
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
s(:dsym,
s(:str, "a\
"),
s(:str, "b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%s{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
s(:dsym,
s(:str, "a\
"),
s(:str, "b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

:"a\
b"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s(:sym, :ab)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

/a\
b/
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
s(:regexp,
s(:str, "ab"),
s(:regopt, ""))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%r{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
s(:regexp,
s(:str, "ab"),
s(:regopt, ""))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%x{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:xstr,
s(:str, "ab"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

`a\
b`
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:xstr,
s(:str, "ab"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# typed: strict

<<-`HERE`
a\
b
HERE
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
s(:xstr,
s(:str, "ab
"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# typed: strict

<<-HERE
a\
b
HERE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:str, "ab
")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%q{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
s(:dstr,
s(:str, "a\
"),
s(:str, "b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# typed: strict

<<~HERE
a\
b
HERE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:str, "ab
")
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# typed: strict

<<~HERE
a\
b
HERE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:str, "a b
")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

"a\
b"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s(:str, "ab")
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# typed: strict

<<-"HERE"
a\
b
HERE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:str, "ab
")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s(:str, "ab")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%Q{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s(:str, "ab")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%w{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
s(:array,
s(:str, "a
b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%W{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
s(:array,
s(:str, "a
b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# typed: strict

%i{a\
b}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s(:array,
s(:sym, :a\nb))
23 changes: 21 additions & 2 deletions third_party/parser/cc/lexer.rl
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,7 @@ void lexer::set_state_expr_value() {

action extend_string_escaped {
auto& current_literal = literal_();

// Get the first character after the backslash.
// TODO multibyte
auto escaped_char = *escape_s;

Expand Down Expand Up @@ -1071,7 +1071,26 @@ void lexer::set_state_expr_value() {
}
} else {
// It does not. So this is an actual escape sequence, yay!
if (current_literal.regexp()) {
if (current_literal.squiggly_heredoc() && escaped_char == '\n') {
// Squiggly heredocs like
// <<~-HERE
// 1\
// 2
// HERE
// treat '\' as a line continuation, but still dedent the body, so the heredoc above becomes "12\n".
// This information is emitted as is, without escaping,
// later this escape sequence (\\\n) gets handled manually in the dedenter
std::string str = gsub(tok(), "\\\n", "");
current_literal.extend_string(str, ts, te);
} else if (current_literal.support_line_continuation_via_slash() && escaped_char == '\n') {
// Heredocs, regexp and a few other types of literals support line
// continuation via \\\n sequence. The code like
// "a\
// b"
// must be parsed as "ab"
std::string str = gsub(tok(), "\\\n", "");
current_literal.extend_string(str, ts, te);
} else if (current_literal.regexp()) {
// Regular expressions should include escape sequences in their
// escaped form. On the other hand, escaped newlines are removed.
std::string str = gsub(tok(), "\\\n", "");
Expand Down
8 changes: 8 additions & 0 deletions third_party/parser/cc/literal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ bool literal::heredoc() const {
return heredoc_e != nullptr;
}

bool literal::squiggly_heredoc() const {
return heredoc() && dedent_body;
}

bool literal::support_line_continuation_via_slash() const {
return !words() && interpolate();
}

token_type literal::start_token_type() const {
switch (_type) {
case literal_type::SQUOTE_STRING:
Expand Down
2 changes: 2 additions & 0 deletions third_party/parser/include/ruby_parser/literal.hh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ namespace ruby_parser {
bool interpolate() const;
bool regexp() const;
bool heredoc() const;
bool squiggly_heredoc() const;
bool support_line_continuation_via_slash() const;

token_type start_token_type() const;

Expand Down