Problem
Escape sequences in the literal parts of an interpolated string are printed as written:
fn main() {
let x = 1
print("a\t${x}\tb")
print("cost: \${x} is ${x}")
print("q: \"${x}\"")
}home run prints a\t1\tb, cost: \${x} is 1 and q: \"1\". The same escapes in a plain string literal are decoded (print("a\tb") prints a tab), and the expected output is a, tab, 1, tab, b, then cost: ${x} is 1 and q: "1". The interpreter decodes plain literals with processStringEscapes, but appends the parts of an interpolated string unchanged. \$, which the lexer accepts inside interpolated strings so that ${ can be written literally, is not handled by processStringEscapes at all.
Fix
The interpreter decodes each literal part of an interpolated string with processStringEscapes. A new interpolated argument makes the parts also decode \$ to $; plain, raw and triple-quoted literals pass false and keep \$ as it is today.
Tests
Two new tests in packages/interpreter/tests/program_eval_test.zig. eval: interpolated strings decode escape sequences checks \n, \t, \" and \$ around interpolations; on main it fails with Assertion failed: 3 Equal 2, and it also fails (10 Equal 9) if parts do not decode \$. eval: raw and triple-quoted strings keep a backslash before $ passes on main and with this change, and fails if \$ is decoded in every string literal. zig build test -Denable_jsc=false -Dfilter=interpreter on macOS: 25/25. On Linux the interpreter test step does not compile on main or on this branch, because the parser's module resolver calls libc access and that test target does not link libc.
GitHub Actions does not run on this repo at the moment, so I ran the full suite on Linux x86_64 with the pinned Zig 0.17.0-dev.2163, on main (854d00f) and on this branch: zig build test --summary all passes 9226/9237 on both, with the same 3 failing tests, 8 skips and 23 failed build steps, and the diagnostic snapshot harness output is identical. With the built home, the program above prints the escaped text on main and the decoded text on this branch; a raw literal r"keep \$" added to it prints the same on both.