use std::{
fmt,
hash::{Hash, Hasher},
};
use bitflags::bitflags;
use num_bigint::BigInt;
use oxc_span::{Atom, Span};
use oxc_syntax::NumberBase;
#[cfg(feature = "serde")]
use serde::Serialize;
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct BooleanLiteral {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
pub value: bool,
}
impl BooleanLiteral {
pub fn as_str(&self) -> &'static str {
if self.value { "true" } else { "false" }
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct NullLiteral {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
}
impl Hash for NullLiteral {
fn hash<H: Hasher>(&self, state: &mut H) {
None::<bool>.hash(state);
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct NumberLiteral<'a> {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
pub value: f64,
#[cfg_attr(feature = "serde", serde(skip))]
pub raw: &'a str,
#[cfg_attr(feature = "serde", serde(skip))]
pub base: NumberBase,
}
impl<'a> NumberLiteral<'a> {
pub fn new(span: Span, value: f64, raw: &'a str, base: NumberBase) -> Self {
Self { span, value, raw, base }
}
}
impl<'a> Hash for NumberLiteral<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.base.hash(state);
self.raw.hash(state);
}
}
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct BigintLiteral {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::serialize::serialize_bigint"))]
pub value: BigInt,
}
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct RegExpLiteral {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
pub value: EmptyObject,
pub regex: RegExp,
}
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct RegExp {
pub pattern: Atom,
pub flags: RegExpFlags,
}
impl fmt::Display for RegExp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "/{}/{}", self.pattern, self.flags)
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RegExpFlags: u8 {
const G = 1 << 0;
const I = 1 << 1;
const M = 1 << 2;
const S = 1 << 3;
const U = 1 << 4;
const Y = 1 << 5;
const D = 1 << 6;
const V = 1 << 7;
}
}
impl fmt::Display for RegExpFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.contains(Self::G) {
write!(f, "g")?;
}
if self.contains(Self::I) {
write!(f, "i")?;
}
if self.contains(Self::M) {
write!(f, "m")?;
}
if self.contains(Self::S) {
write!(f, "s")?;
}
if self.contains(Self::U) {
write!(f, "u")?;
}
if self.contains(Self::Y) {
write!(f, "y")?;
}
if self.contains(Self::D) {
write!(f, "d")?;
}
if self.contains(Self::V) {
write!(f, "v")?;
}
Ok(())
}
}
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct EmptyObject;
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct StringLiteral {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
pub value: Atom,
}
impl StringLiteral {
pub fn is_string_well_formed_unicode(&self) -> bool {
let mut chars = self.value.chars();
while let Some(c) = chars.next() {
if c == '\\' && chars.next() == Some('u') {
let hex = &chars.as_str()[..4];
if let Ok(hex) = u32::from_str_radix(hex, 16) {
if (0xd800..=0xdfff).contains(&hex) {
return false;
}
};
}
}
true
}
}