making the invalid escape sequence fully explain the sintax

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2025-01-01 19:49:19 +01:00
parent 6f94ae2b2a
commit da5bd3d36a
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
2 changed files with 24 additions and 15 deletions

View file

@ -36,6 +36,7 @@ pub use fs::*;
use { use {
self::{ty::Builtin, utils::Ent}, self::{ty::Builtin, utils::Ent},
alloc::vec::Vec, alloc::vec::Vec,
core::{fmt::Arguments, format_args as fa},
}; };
#[macro_use] #[macro_use]
@ -316,9 +317,9 @@ impl Ident {
fn endoce_string( fn endoce_string(
literal: &str, literal: &str,
str: &mut Vec<u8>, str: &mut Vec<u8>,
report: impl Fn(&core::str::Bytes, &str), report: impl Fn(&core::str::Bytes, Arguments),
) -> Option<usize> { ) -> Option<usize> {
let report = |bytes: &core::str::Bytes, msg: &_| { let report = |bytes: &core::str::Bytes, msg: Arguments| {
report(bytes, msg); report(bytes, msg);
None::<u8> None::<u8>
}; };
@ -327,13 +328,13 @@ fn endoce_string(
while let Some(b) = bytes.next() while let Some(b) = bytes.next()
&& b != b'}' && b != b'}'
{ {
let c = bytes.next().or_else(|| report(bytes, "incomplete escape sequence"))?; let c = bytes.next().or_else(|| report(bytes, fa!("incomplete escape sequence")))?;
let decode = |b: u8| { let decode = |b: u8| {
Some(match b { Some(match b {
b'0'..=b'9' => b - b'0', b'0'..=b'9' => b - b'0',
b'a'..=b'f' => b - b'a' + 10, b'a'..=b'f' => b - b'a' + 10,
b'A'..=b'F' => b - b'A' + 10, b'A'..=b'F' => b - b'A' + 10,
_ => report(bytes, "expected hex digit or '}'")?, _ => report(bytes, fa!("expected hex digit or '}}'"))?,
}) })
}; };
str.push(decode(b)? << 4 | decode(c)?); str.push(decode(b)? << 4 | decode(c)?);
@ -350,19 +351,27 @@ fn endoce_string(
str.push(b); str.push(b);
continue; continue;
} }
let b = match bytes.next().or_else(|| report(&bytes, "incomplete escape sequence"))? {
b'n' => b'\n', const SPECIAL_CHARS: &str = "nrt\\'\"0";
b'r' => b'\r', const TO_BYTES: &[u8] = b"\n\r\t\\'\"\0";
b't' => b'\t', const _: () = assert!(SPECIAL_CHARS.len() == TO_BYTES.len());
b'\\' => b'\\',
b'\'' => b'\'', let b = match bytes.next().or_else(|| report(&bytes, fa!("incomplete escape sequence")))? {
b'"' => b'"', b if let Some((_, &i)) = SPECIAL_CHARS.bytes().zip(TO_BYTES).find(|&(i, _)| i == b) => {
b'0' => b'\0', i
}
b'{' => { b'{' => {
decode_braces(str, &mut bytes); decode_braces(str, &mut bytes);
continue; continue;
} }
_ => report(&bytes, "unknown escape sequence, expected [nrt\\\"'{0]")?, _ => report(
&bytes,
format_args!(
"unknown escape sequence, \
expected one of special characters (regex /[{SPECIAL_CHARS}]/), \
or arbitrary byte sequence in hex (regex /\\{{[0-9a-f]{{2}}+\\/}})"
),
)?,
}; };
str.push(b); str.push(b);
} }

View file

@ -28,7 +28,7 @@ use {
assert_matches::debug_assert_matches, assert_matches::debug_assert_matches,
cell::RefCell, cell::RefCell,
error, error,
fmt::{self, Debug, Display, Write}, fmt::{self, Arguments, Debug, Display, Write},
format_args as fa, mem, format_args as fa, mem,
}, },
}; };
@ -887,7 +887,7 @@ impl<'a> Codegen<'a> {
let mut data = core::mem::take(&mut self.pool.lit_buf); let mut data = core::mem::take(&mut self.pool.lit_buf);
debug_assert!(data.is_empty()); debug_assert!(data.is_empty());
let report = |bytes: &core::str::Bytes, message: &str| { let report = |bytes: &core::str::Bytes, message: Arguments| {
self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message); self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message);
}; };