use crate::error::Error;
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
Number(f64),
BigInt(String),
String(String),
Boolean(bool),
Null,
RegExp {
pattern: String,
flags: String,
},
}
impl Eq for Literal {}
impl Literal {
#[must_use]
pub fn number(value: f64) -> Self {
Self::Number(value)
}
#[must_use]
pub fn bigint(digits: impl Into<String>) -> Self {
Self::BigInt(digits.into())
}
#[must_use]
pub fn string(content: impl Into<String>) -> Self {
Self::String(content.into())
}
#[must_use]
pub fn boolean(value: bool) -> Self {
Self::Boolean(value)
}
#[must_use]
pub fn null() -> Self {
Self::Null
}
pub fn regex(pattern: impl Into<String>, flags: impl Into<String>) -> Result<Self, Error> {
let pattern = pattern.into();
let flags = flags.into();
if pattern.is_empty() {
Err(Error::EmptyRegexPattern)
} else {
flags
.chars()
.find(|c| !is_valid_regex_flag(*c))
.map_or(Ok(Self::RegExp { pattern, flags }), |flag| {
Err(Error::InvalidRegexFlag { flag })
})
}
}
}
impl std::fmt::Display for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Number(value) => write!(f, "{value}"),
Self::BigInt(digits) => write!(f, "{digits}n"),
Self::String(content) => write!(f, "{content:?}"),
Self::Boolean(value) => write!(f, "{value}"),
Self::Null => f.write_str("null"),
Self::RegExp { pattern, flags } => write!(f, "/{pattern}/{flags}"),
}
}
}
fn is_valid_regex_flag(flag: char) -> bool {
matches!(flag, 'g' | 'i' | 'm' | 's' | 'u' | 'y' | 'd' | 'v')
}