swc_ecma_ast 0.96.3

Ecmascript ast.
use std::{
    borrow::Cow,
    fmt::{self, Display, Formatter},
    hash::{Hash, Hasher},
    mem,
};

use num_bigint::BigInt as BigIntValue;
#[cfg(feature = "rkyv-bytecheck-impl")]
use rkyv_latest as rkyv;
use swc_atoms::{js_word, Atom, JsWord};
use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span, DUMMY_SP};

use crate::jsx::JSXText;

#[ast_node]
#[derive(Eq, Hash, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Lit {
    #[tag("StringLiteral")]
    Str(Str),

    #[tag("BooleanLiteral")]
    Bool(Bool),

    #[tag("NullLiteral")]
    Null(Null),

    #[tag("NumericLiteral")]
    Num(Number),

    #[tag("BigIntLiteral")]
    BigInt(BigInt),

    #[tag("RegExpLiteral")]
    Regex(Regex),

    #[tag("JSXText")]
    JSXText(JSXText),
}

macro_rules! bridge_lit_from {
    ($bridge: ty, $src:ty) => {
        bridge_expr_from!(crate::Lit, $src);
        bridge_from!(Lit, $bridge, $src);
    };
}

bridge_expr_from!(Lit, Str);
bridge_expr_from!(Lit, Bool);
bridge_expr_from!(Lit, Number);
bridge_expr_from!(Lit, BigInt);
bridge_expr_from!(Lit, Regex);
bridge_expr_from!(Lit, Null);
bridge_expr_from!(Lit, JSXText);

bridge_lit_from!(Str, &'_ str);
bridge_lit_from!(Str, JsWord);
bridge_lit_from!(Str, Atom);
bridge_lit_from!(Str, Cow<'_, str>);
bridge_lit_from!(Str, String);
bridge_lit_from!(Bool, bool);
bridge_lit_from!(Number, f64);
bridge_lit_from!(Number, usize);
bridge_lit_from!(BigInt, BigIntValue);

#[ast_node("BigIntLiteral")]
#[derive(Eq, Hash)]
pub struct BigInt {
    pub span: Span,
    #[cfg_attr(
        any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
        with(EncodeBigInt)
    )]
    pub value: Box<BigIntValue>,

    /// Use `None` value only for transformations to avoid recalculate
    /// characters in big integer
    pub raw: Option<Atom>,
}

impl EqIgnoreSpan for BigInt {
    fn eq_ignore_span(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

#[cfg(feature = "__rkyv")]
#[derive(Debug, Clone, Copy)]
pub struct EncodeBigInt;

#[cfg(any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"))]
impl rkyv::with::ArchiveWith<Box<BigIntValue>> for EncodeBigInt {
    type Archived = rkyv::Archived<String>;
    type Resolver = rkyv::Resolver<String>;

    unsafe fn resolve_with(
        field: &Box<BigIntValue>,
        pos: usize,
        resolver: Self::Resolver,
        out: *mut Self::Archived,
    ) {
        use rkyv::Archive;

        let s = field.to_string();
        s.resolve(pos, resolver, out);
    }
}

#[cfg(any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"))]
impl<S> rkyv::with::SerializeWith<Box<BigIntValue>, S> for EncodeBigInt
where
    S: ?Sized + rkyv::ser::Serializer,
{
    fn serialize_with(
        field: &Box<BigIntValue>,
        serializer: &mut S,
    ) -> Result<Self::Resolver, S::Error> {
        let field = field.to_string();
        rkyv::string::ArchivedString::serialize_from_str(&field, serializer)
    }
}

#[cfg(any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"))]
impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Box<BigIntValue>, D> for EncodeBigInt
where
    D: ?Sized + rkyv::Fallible,
{
    fn deserialize_with(
        field: &rkyv::Archived<String>,
        deserializer: &mut D,
    ) -> Result<Box<BigIntValue>, D::Error> {
        use rkyv::Deserialize;

        let s: String = field.deserialize(deserializer)?;

        Ok(Box::new(s.parse().unwrap()))
    }
}

#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
impl<'a> arbitrary::Arbitrary<'a> for BigInt {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        let span = u.arbitrary()?;
        let value = Box::new(u.arbitrary::<usize>()?.into());
        let raw = Some(u.arbitrary::<String>()?.into());

        Ok(Self { span, value, raw })
    }
}

impl From<BigIntValue> for BigInt {
    #[inline]
    fn from(value: BigIntValue) -> Self {
        BigInt {
            span: DUMMY_SP,
            value: Box::new(value),
            raw: None,
        }
    }
}

/// A string literal.
#[ast_node("StringLiteral")]
#[derive(Eq, Hash)]
pub struct Str {
    pub span: Span,

    #[cfg_attr(
        any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
        with(swc_atoms::EncodeJsWord)
    )]
    pub value: JsWord,

    /// Use `None` value only for transformations to avoid recalculate escaped
    /// characters in strings
    pub raw: Option<Atom>,
}

impl Take for Str {
    fn dummy() -> Self {
        Str {
            span: DUMMY_SP,
            value: js_word!(""),
            raw: None,
        }
    }
}

#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
impl<'a> arbitrary::Arbitrary<'a> for Str {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        let span = u.arbitrary()?;
        let value = u.arbitrary::<String>()?.into();
        let raw = Some(u.arbitrary::<String>()?.into());

        Ok(Self { span, value, raw })
    }
}

impl Str {
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.value.is_empty()
    }
}

impl EqIgnoreSpan for Str {
    fn eq_ignore_span(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

impl From<JsWord> for Str {
    #[inline]
    fn from(value: JsWord) -> Self {
        Str {
            span: DUMMY_SP,
            value,
            raw: None,
        }
    }
}

impl From<Atom> for Str {
    #[inline]
    fn from(value: Atom) -> Self {
        Str {
            span: DUMMY_SP,
            value: JsWord::from(&*value),
            raw: None,
        }
    }
}

bridge_from!(Str, JsWord, &'_ str);
bridge_from!(Str, JsWord, String);
bridge_from!(Str, JsWord, Cow<'_, str>);

/// A boolean literal.
///
///
/// # Creation
///
/// If you are creating a boolean literal with a dummy span, please use
/// `true.into()` or `false.into()`, instead of creating this struct directly.
///
/// All of `Box<Expr>`, `Expr`, `Lit`, `Bool` implements `From<bool>`.
#[ast_node("BooleanLiteral")]
#[derive(Copy, Eq, Hash, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Bool {
    pub span: Span,
    pub value: bool,
}

impl Take for Bool {
    fn dummy() -> Self {
        Bool {
            span: DUMMY_SP,
            value: false,
        }
    }
}

impl From<bool> for Bool {
    #[inline]
    fn from(value: bool) -> Self {
        Bool {
            span: DUMMY_SP,
            value,
        }
    }
}

#[ast_node("NullLiteral")]
#[derive(Copy, Eq, Hash, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Null {
    pub span: Span,
}

impl Take for Null {
    fn dummy() -> Self {
        Null { span: DUMMY_SP }
    }
}

#[ast_node("RegExpLiteral")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Regex {
    pub span: Span,

    #[serde(rename = "pattern")]
    pub exp: Atom,

    #[serde(default)]
    pub flags: Atom,
}

impl Take for Regex {
    fn dummy() -> Self {
        Self {
            span: DUMMY_SP,
            exp: Default::default(),
            flags: Default::default(),
        }
    }
}

#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
impl<'a> arbitrary::Arbitrary<'a> for Regex {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        let span = u.arbitrary()?;
        let exp = u.arbitrary::<String>()?.into();
        let flags = "".into(); // TODO

        Ok(Self { span, exp, flags })
    }
}

/// A numeric literal.
///
///
/// # Creation
///
/// If you are creating a numeric literal with a dummy span, please use
/// `literal.into()`, instead of creating this struct directly.
///
/// All of `Box<Expr>`, `Expr`, `Lit`, `Number` implements `From<64>` and
/// `From<usize>`.

#[ast_node("NumericLiteral")]
pub struct Number {
    pub span: Span,
    /// **Note**: This should not be `NaN`. Use [crate::Ident] to represent NaN.
    ///
    /// If you store `NaN` in this field, a hash map will behave strangely.
    pub value: f64,

    /// Use `None` value only for transformations to avoid recalculate
    /// characters in number literal
    pub raw: Option<Atom>,
}

impl Eq for Number {}

impl EqIgnoreSpan for Number {
    fn eq_ignore_span(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

#[allow(clippy::derive_hash_xor_eq)]
#[allow(clippy::transmute_float_to_int)]
impl Hash for Number {
    fn hash<H: Hasher>(&self, state: &mut H) {
        fn integer_decode(val: f64) -> (u64, i16, i8) {
            let bits: u64 = unsafe { mem::transmute(val) };
            let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
            let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
            let mantissa = if exponent == 0 {
                (bits & 0xfffffffffffff) << 1
            } else {
                (bits & 0xfffffffffffff) | 0x10000000000000
            };

            exponent -= 1023 + 52;
            (mantissa, exponent, sign)
        }

        self.span.hash(state);
        integer_decode(self.value).hash(state);
        self.raw.hash(state);
    }
}

impl Display for Number {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if self.value.is_infinite() {
            if self.value.is_sign_positive() {
                Display::fmt("Infinity", f)
            } else {
                Display::fmt("-Infinity", f)
            }
        } else {
            Display::fmt(&self.value, f)
        }
    }
}

#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
impl<'a> arbitrary::Arbitrary<'a> for Number {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        let span = u.arbitrary()?;
        let value = u.arbitrary::<f64>()?;
        let raw = Some(u.arbitrary::<String>()?.into());

        Ok(Self { span, value, raw })
    }
}

impl From<f64> for Number {
    #[inline]
    fn from(value: f64) -> Self {
        Number {
            span: DUMMY_SP,
            value,
            raw: None,
        }
    }
}

impl From<usize> for Number {
    #[inline]
    fn from(value: usize) -> Self {
        Number {
            span: DUMMY_SP,
            value: value as _,
            raw: None,
        }
    }
}