From 61bf873c6194aef53e8cfdda85eb20d1283fa717 Mon Sep 17 00:00:00 2001 From: Matijs van Zuijlen Date: Fri, 24 Sep 2021 16:20:13 +0200 Subject: [PATCH] - dedenter.rb: Fix squiggly heredoc line continuation handling (#819) 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: ```ruby <<~'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. This is issue #789. In that case, the following source: ```ruby <<~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 e180b9baa..4a71e1e7a 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