From e1ef0ac0eab586c2180f133be260893dd407284a Mon Sep 17 00:00:00 2001 From: Matijs van Zuijlen Date: Fri, 24 Sep 2021 13:06:41 +0200 Subject: [PATCH] Fix squiggly heredoc line continuation handling Firstly, this fixes an issue with non-interpolating squiggly heredocs, where line continuation characters should be ignored. Two things were broken: - The line continuation backslash would be removed, as well as the subsequent carriage return - The subsequent line would not be dedented. For example, the following source: <<~'END' foo \ bar END Would be parsed as follows: (dstr (str "foo ") (str " bar\n")) With the change, the result is: (dstr (str "foo \\\n") (str "bar\n")) This also fixes an issue with interpolating squiggly heredocs, where an escaped backslash followed by a newline would be interpreted as a line continuation. In that case, the following source: <<~END foo \\ bar END Would (again) be parsed as follows: (dstr (str "foo ") (str " bar\n")) With the change, the result is: (dstr (str "foo \\\n") (str "bar\n")) --- lib/parser/lexer/dedenter.rb | 8 +++++++- test/test_parser.rb | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/parser/lexer/dedenter.rb b/lib/parser/lexer/dedenter.rb index 5f0ff2700..5ff16007a 100644 --- a/lib/parser/lexer/dedenter.rb +++ b/lib/parser/lexer/dedenter.rb @@ -38,7 +38,13 @@ def dedent(string) # Prevent the following error when processing binary encoded source. # "\xC0".split # => ArgumentError (invalid byte sequence in UTF-8) lines = string.force_encoding(Encoding::BINARY).split("\\\n") - lines.map! {|s| s.force_encoding(original_encoding) } + if lines.length == 1 + # If the line continuation sequence was found but there is no second + # line, it was not really a line continuation and must be ignored. + lines = [string] + else + lines.map! {|s| s.force_encoding(original_encoding) } + end if @at_line_begin lines_to_dedent = lines diff --git a/test/test_parser.rb b/test/test_parser.rb index 7aa78c7a1..20d77d725 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -439,6 +439,22 @@ def test_parser_bug_640 SINCE_2_3) end + def test_dedenting_non_interpolating_heredoc_line_continuation + assert_parses( + s(:dstr, s(:str, "baz\\\n"), s(:str, "qux\n")), + %Q{<<~'FOO'\n baz\\\n qux\nFOO}, + %q{}, + SINCE_2_3) + end + + def test_dedenting_interpolating_heredoc_fake_line_continuation + assert_parses( + s(:dstr, s(:str, "baz\\\n"), s(:str, "qux\n")), + %Q{<<~'FOO'\n baz\\\\\n qux\nFOO}, + %q{}, + SINCE_2_3) + end + # Symbols def test_symbol_plain