#371

Reject unknown escapes in string literals (A2/A3/B8)

OpenTumCucTomwants to merge intofrom

Summary

The string-literal decoder's catch-all branch appended the byte after \\ verbatim. Three findings flowed from that one gap:

  • "\q" silently decoded to "q" (A2)
  • "\0" silently decoded to "0" (A3)
  • "A" silently decoded to "u0041" (B8)

The char scanner at canonical_text.c:220-222 already whitelists the known escapes and rejects everything else with PAR100. This PR mirrors that policy in the string decoder: explicitly accept n, r, t, and x..; pass through the self-escaped \\, ', "; reject everything else with PAR100. \\x00 continues to be rejected (a NUL byte would truncate a C string), which now matches \\0.

Closes three items from #318.

Test plan

  • conformance/native/pass/string-escape-canonical.0 covers \\n, \\t, \\", \\\\, \\x41
  • conformance/native/fail/string-unknown-escape.0 covers "\q"
  • conformance/native/fail/string-null-escape.0 covers "\0"
  • pnpm run conformance passes
  • compiler-metrics.mts has 0 violations (budget bumped by 17)
  • No C compiler warnings
  • No existing *.0 source uses "\0" or "\u..." so the rejection is safe