use core::fmt; use std::num::ParseFloatError; use num::{bigint::ParseBigIntError, Num}; use crate::{ lstring::{LStr, LString}, number::Int, }; use super::Span; #[derive(Clone, Debug)] pub struct ParserError { pub span: Span, pub msg: String, } impl std::error::Error for ParserError {} impl fmt::Display for ParserError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} | {}", self.span, self.msg) } } pub trait SpanParserError { type Output; fn span_err(self, span: Span) -> Self::Output; } impl SpanParserError for Result { type Output = Result; fn span_err(self, span: Span) -> Self::Output { self.map_err(|e| ParserError { span, msg: e.to_string(), }) } } #[derive(Clone, Copy, Debug)] pub enum StrEscapeError { Eof, HexEof, UnicodeEof, Invalid(char), InvalidHex(char), MissingBrace, InvalidCodepoint(u32), CodepointTooLarge, } impl std::error::Error for StrEscapeError {} impl fmt::Display for StrEscapeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { StrEscapeError::Eof => write!(f, "EOF in string escape"), StrEscapeError::HexEof => write!(f, "EOF in string escape \\x"), StrEscapeError::UnicodeEof => write!(f, "EOF in string escape \\u"), StrEscapeError::Invalid(c) => write!(f, "invalid string escape \\{c}"), StrEscapeError::InvalidHex(x) => { write!(f, "invalid hex digit '{x}' in string escape") } StrEscapeError::MissingBrace => { write!(f, "missing brace after string escape \\u") } StrEscapeError::InvalidCodepoint(n) => { write!(f, "invalid codepoint in string escape: U+{n:0>4x})") } StrEscapeError::CodepointTooLarge => { write!(f, "codepoint in string escape too large") } } } } pub fn parse_str_escapes(src: &str) -> Result { let mut s = LString::with_capacity(src.len()); let mut chars = src.chars(); while let Some(c) = chars.next() { if c != '\\' { s.push_char(c); continue } let c = chars.next().ok_or(StrEscapeError::Eof)?; match c { '"' | '\'' | '\\' => s.push_char(c), '0' => s.push_char('\0'), 'a' => s.push_char('\x07'), 'b' => s.push_char('\x08'), 't' => s.push_char('\t'), 'n' => s.push_char('\n'), 'v' => s.push_char('\x0b'), 'f' => s.push_char('\x0c'), 'r' => s.push_char('\r'), 'e' => s.push_char('\x1b'), 'x' => { let c = chars.next().ok_or(StrEscapeError::HexEof)?; let n1 = c.to_digit(16).ok_or(StrEscapeError::InvalidHex(c))?; let c = chars.next().ok_or(StrEscapeError::HexEof)?; let n2 = c.to_digit(16).ok_or(StrEscapeError::InvalidHex(c))?; s.push_byte((n1 * 16 + n2) as u8); } 'u' => { let Some('{') = chars.next() else { return Err(StrEscapeError::MissingBrace) }; let mut n = 0_u32; loop { let Some(c) = chars.next() else { return Err(StrEscapeError::UnicodeEof) }; if c == '}' { break } if n > 0x10ffff { return Err(StrEscapeError::CodepointTooLarge) } n = n * 16 + c.to_digit(16).ok_or(StrEscapeError::InvalidHex(c))?; } let ch = char::from_u32(n).ok_or(StrEscapeError::InvalidCodepoint(n))?; s.push_char(ch); } c => return Err(StrEscapeError::Invalid(c)), } } Ok(s) } pub fn parse_float<'a, S: Into<&'a LStr>>(f: S) -> Result { let mut s = String::new(); for c in f.into().chars() { if c != '_' { s.push(c); } } s.parse() } pub fn parse_int<'a, S: Into<&'a LStr>>(f: S, radix: u32) -> Result { let mut s = String::new(); for c in f.into().chars() { if c != '_' { s.push(c); } } Int::from_str_radix(&s, radix) } pub fn parse_int_literal<'a, S: Into<&'a LStr>>(f: S) -> Result { let f = f.into(); match f.chars().nth(1) { Some('x') => parse_int(&f[2..], 16), Some('o') => parse_int(&f[2..], 8), Some('s') => parse_int(&f[2..], 6), Some('b') => parse_int(&f[2..], 2), _ => parse_int(f, 10), } }