use serde::{Serialize, Deserialize};
use thiserror::Error;
use crate::util::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum StringLiteralPrefixLastState {
Outside,
Inside,
Start,
Octal1,
Octal2,
AsciiHexx,
AsciiHex1,
UnicodeU,
Unicode41,
Unicode42,
Unicode43,
UnicodeLeftBrace,
Unicode51,
Unicode52,
Unicode53,
Unicode54,
Unicode55
}
#[derive(Debug, Error)]
pub enum StringLiteralPrefixError {
#[error("A syntax error was encountered.")]
SyntaxError {
last_state: StringLiteralPrefixLastState,
i: usize,
c: char,
scratchspace: u32,
quote: char,
partial: String
},
#[error("An invalid codepoint was encountered: {0}.")]
InvalidCodepoint(u32)
}
#[allow(clippy::missing_panics_doc, reason = "Shouldn't ever happen.")]
#[allow(clippy::unwrap_used, reason = "Who cares?")]
pub fn string_literal_prefix(s: &str) -> Result<String, StringLiteralPrefixError> {
debug!(prefix::js::string_literal_prefix, &(), s);
let mut ret = String::new();
let mut last_state = StringLiteralPrefixLastState::Outside;
let mut scratchspace: u32 = 0;
let mut quote = '"';
for (i, c) in s.chars().enumerate() {
debug!(prefix::js::string_literal_prefix, &(), i, c, last_state, scratchspace, quote, ret);
#[allow(clippy::arithmetic_side_effects, reason = "Shouldn't ever happen.")]
match (last_state, c) {
(StringLiteralPrefixLastState::Outside , '"' | '\'' ) => {last_state = StringLiteralPrefixLastState::Inside ; quote = c;},
(StringLiteralPrefixLastState::Inside , '\\' ) => {last_state = StringLiteralPrefixLastState::Start ;},
(StringLiteralPrefixLastState::Start , '0' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\0');},
(StringLiteralPrefixLastState::Start , 'b' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\u{0008}');},
(StringLiteralPrefixLastState::Start , 'g' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\u{000c}');},
(StringLiteralPrefixLastState::Start , 'n' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\n');},
(StringLiteralPrefixLastState::Start , '\n' ) => {last_state = StringLiteralPrefixLastState::Inside ;},
(StringLiteralPrefixLastState::Start , 'r' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\r');},
(StringLiteralPrefixLastState::Start , 't' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\t');},
(StringLiteralPrefixLastState::Start , 'v' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\u{000b}');},
(StringLiteralPrefixLastState::Start , '\'' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\'');},
(StringLiteralPrefixLastState::Start , '"' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('"') ;},
(StringLiteralPrefixLastState::Start , '\\' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push('\\');},
(StringLiteralPrefixLastState::Start , '0'..='7' ) => {last_state = StringLiteralPrefixLastState::Octal1 ; scratchspace = c.to_digit( 8).unwrap();},
(StringLiteralPrefixLastState::Octal1 , '0'..='7' ) => {last_state = StringLiteralPrefixLastState::Octal2 ; scratchspace = scratchspace * 8 + c.to_digit( 8).unwrap();},
(StringLiteralPrefixLastState::Octal2 , '0'..='7' ) => {last_state = StringLiteralPrefixLastState::Inside ; scratchspace = scratchspace * 8 + c.to_digit( 8).unwrap(); ret.push(char::from_u32(scratchspace).ok_or(StringLiteralPrefixError::InvalidCodepoint(scratchspace))?);},
(StringLiteralPrefixLastState::Start , 'x' ) => {last_state = StringLiteralPrefixLastState::AsciiHexx ;},
(StringLiteralPrefixLastState::AsciiHexx , '0'..='7' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::AsciiHex1 ; scratchspace = c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::AsciiHex1 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Inside ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap(); ret.push(char::from_u32(scratchspace).ok_or(StringLiteralPrefixError::InvalidCodepoint(scratchspace))?);},
(StringLiteralPrefixLastState::Start , 'u' ) => {last_state = StringLiteralPrefixLastState::UnicodeU ;},
(StringLiteralPrefixLastState::UnicodeU , '{' ) => {last_state = StringLiteralPrefixLastState::UnicodeLeftBrace;},
(StringLiteralPrefixLastState::UnicodeLeftBrace, '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode51 ; scratchspace = c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode51 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode52 ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode52 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode53 ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode53 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode54 ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode54 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode55 ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode51
| StringLiteralPrefixLastState::Unicode52
| StringLiteralPrefixLastState::Unicode53
| StringLiteralPrefixLastState::Unicode54
| StringLiteralPrefixLastState::Unicode55 , '}' ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push(char::from_u32(scratchspace).ok_or(StringLiteralPrefixError::InvalidCodepoint(scratchspace))?);},
(StringLiteralPrefixLastState::UnicodeU , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode41 ; scratchspace = c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode41 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode42 ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode42 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Unicode43 ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap();},
(StringLiteralPrefixLastState::Unicode43 , '0'..='9' | 'A'..='F' | 'a'..='f') => {last_state = StringLiteralPrefixLastState::Inside ; scratchspace = scratchspace * 16 + c.to_digit(16).unwrap(); ret.push(char::from_u32(scratchspace).ok_or(StringLiteralPrefixError::InvalidCodepoint(scratchspace))?);},
(StringLiteralPrefixLastState::Inside , '"' | '\'' ) if c == quote => break,
(StringLiteralPrefixLastState::Start , _ ) => {last_state = StringLiteralPrefixLastState::Inside ; ret.push(c);},
(StringLiteralPrefixLastState::Inside , _ ) => {ret.push(c);}
_ => Err(StringLiteralPrefixError::SyntaxError {last_state, i, c, scratchspace, quote, partial: ret.clone()})?
};
}
debug!(prefix::js::string_literal_prefix, &(), ret);
Ok(ret)
}