Skip to content

fix(lexer): strip backslash-newline line continuations in interpolating strings - #13

Merged
tannevaled merged 1 commit into
mainfrom
fix/string-line-continuation
Jul 31, 2026
Merged

fix(lexer): strip backslash-newline line continuations in interpolating strings#13
tannevaled merged 1 commit into
mainfrom
fix/string-line-continuation

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Bug

Inside a double-quoted / interpolating string literal, a backslash placed immediately before a newline is a line continuation — MRI removes both the backslash and the newline. The escape decoder fell through to its default branch and emitted the raw newline byte, so:

s = "a\
b"
p s      # MRI => "ab"     was => "a\nb"  (WRONG)

Fix

Add the continuation branch to scanStringSegment (the interpolating-string escape decoder that the double-quoted, %Q/%(), and interpolating-heredoc paths all re-lex through). Both \<LF> and \<CR><LF> are stripped entirely; a lone \<CR> stays dropped-backslash + literal CR, matching MRI. The non-interpolating flavours (single-quoted, %q, <<'TERM' heredocs) never reach this decoder and keep the backslash+newline verbatim — also matching MRI.

MRI-match matrix (verified byte-for-byte vs ruby 4.0.5)

flavour \+newline changed?
"..." double-quoted stripped (LF and CRLF) yes
%Q() / %() stripped yes
interpolating heredoc <<~/<<-/<< stripped yes
lone \<CR> (no LF) backslash dropped, CR kept matches (unchanged)
'...' single-quoted literal backslash+newline no
%q() literal backslash+newline no
<<'TERM' non-interpolating heredoc literal backslash+newline no

Covers continuation-then-escape (\<LF>\t), at end-of-literal, and immediately before #{…}.

Gate

  • New tests for every branch; merged coverage 100.0% (CI gate).
  • go vet clean; builds on all 6 64-bit arches (amd64/arm64/riscv64/loong64/ppc64le/s390x) + js/wasm + wasip1/wasm.

🤖 Generated with Claude Code

…ng strings

Inside a double-quoted / interpolating string literal, a backslash placed
immediately before a newline is a line continuation: MRI removes BOTH the
backslash and the newline. The escape decoder previously fell through to its
default branch and emitted the raw newline byte, so "a\<LF>b" decoded to
"a\nb" instead of "ab".

Add the continuation branch to scanStringSegment (the interpolating-string
decoder, which the double-quoted, %Q/%(), and interpolating-heredoc paths all
re-lex through). Handle both the LF and CR-LF forms; a lone \<CR> stays a
dropped-backslash + literal CR, matching MRI. The non-interpolating flavours
(single-quoted, %q, <<'TERM' heredocs) never reach this decoder and keep the
backslash+newline verbatim, also matching MRI.

Verified byte-for-byte against ruby 4.0.x across the full string-flavour matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 2008b7e into main Jul 31, 2026
11 checks passed
@tannevaled
tannevaled deleted the fix/string-line-continuation branch July 31, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant