just/src/string_literal.rs

64 lines
1.6 KiB
Rust

use crate::common::*;
#[derive(PartialEq, Debug)]
pub struct StringLiteral<'a> {
pub raw: &'a str,
pub cooked: Cow<'a, str>,
}
impl<'a> StringLiteral<'a> {
pub fn new(token: &Token<'a>) -> CompilationResult<'a, StringLiteral<'a>> {
let raw = &token.lexeme()[1..token.lexeme().len() - 1];
if let TokenKind::StringRaw = token.kind {
Ok(StringLiteral {
cooked: Cow::Borrowed(raw),
raw,
})
} else if let TokenKind::StringCooked = token.kind {
let mut cooked = String::new();
let mut escape = false;
for c in raw.chars() {
if escape {
match c {
'n' => cooked.push('\n'),
'r' => cooked.push('\r'),
't' => cooked.push('\t'),
'\\' => cooked.push('\\'),
'"' => cooked.push('"'),
other => {
return Err(
token.error(CompilationErrorKind::InvalidEscapeSequence { character: other }),
);
}
}
escape = false;
continue;
}
if c == '\\' {
escape = true;
continue;
}
cooked.push(c);
}
Ok(StringLiteral {
raw,
cooked: Cow::Owned(cooked),
})
} else {
Err(token.error(CompilationErrorKind::Internal {
message: "cook_string() called on non-string token".to_string(),
}))
}
}
}
impl<'a> Display for StringLiteral<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self.cooked {
Cow::Borrowed(raw) => write!(f, "'{}'", raw),
Cow::Owned(_) => write!(f, "\"{}\"", self.raw),
}
}
}