mod array;
mod object;
mod template;
pub use array::ArrayLiteral;
use core::ops::ControlFlow;
pub use object::{ObjectLiteral, ObjectMethodDefinition, PropertyDefinition};
pub use template::{TemplateElement, TemplateLiteral};
use crate::{
Span, Spanned,
visitor::{VisitWith, Visitor, VisitorMut},
};
use boa_interner::{Interner, Sym, ToInternedString};
use num_bigint::BigInt;
use super::Expression;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq)]
pub struct Literal {
kind: LiteralKind,
span: Span,
}
impl Literal {
#[inline]
#[must_use]
pub fn new<T: Into<LiteralKind>>(kind: T, span: Span) -> Self {
Self {
kind: kind.into(),
span,
}
}
#[inline]
#[must_use]
pub const fn kind(&self) -> &LiteralKind {
&self.kind
}
#[inline]
#[must_use]
pub const fn kind_mut(&mut self) -> &mut LiteralKind {
&mut self.kind
}
#[inline]
#[must_use]
pub const fn as_string(&self) -> Option<Sym> {
if let LiteralKind::String(sym) = self.kind() {
return Some(*sym);
}
None
}
#[inline]
#[must_use]
pub const fn is_undefined(&self) -> bool {
matches!(self.kind(), LiteralKind::Undefined)
}
}
impl Spanned for Literal {
#[inline]
fn span(&self) -> Span {
self.span
}
}
impl From<Literal> for Expression {
#[inline]
fn from(lit: Literal) -> Self {
Self::Literal(lit)
}
}
impl ToInternedString for Literal {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
self.kind().to_interned_string(interner)
}
}
impl VisitWith for Literal {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
if let LiteralKind::String(sym) = &self.kind {
visitor.visit_sym(sym)
} else {
ControlFlow::Continue(())
}
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
if let LiteralKind::String(sym) = &mut self.kind {
visitor.visit_sym_mut(sym)
} else {
ControlFlow::Continue(())
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum LiteralKind {
String(Sym),
Num(f64),
Int(i32),
BigInt(Box<BigInt>),
Bool(bool),
Null,
Undefined,
}
#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for LiteralKind {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let c = <u8 as arbitrary::Arbitrary<'a>>::arbitrary(u)? % 6;
match c {
0 => Ok(Self::String(<Sym as arbitrary::Arbitrary>::arbitrary(u)?)),
1 => Ok(Self::Num(<f64 as arbitrary::Arbitrary>::arbitrary(u)?)),
2 => Ok(Self::Int(<i32 as arbitrary::Arbitrary>::arbitrary(u)?)),
3 => Ok(Self::BigInt(Box::new(
<BigInt as arbitrary::Arbitrary>::arbitrary(u)?,
))),
4 => Ok(Self::Bool(<bool as arbitrary::Arbitrary>::arbitrary(u)?)),
5 => Ok(Self::Null),
_ => unreachable!(),
}
}
}
impl From<Sym> for LiteralKind {
#[inline]
fn from(string: Sym) -> Self {
Self::String(string)
}
}
impl From<f64> for LiteralKind {
#[inline]
fn from(num: f64) -> Self {
Self::Num(num)
}
}
impl From<i32> for LiteralKind {
#[inline]
fn from(i: i32) -> Self {
Self::Int(i)
}
}
impl From<BigInt> for LiteralKind {
#[inline]
fn from(i: BigInt) -> Self {
Self::BigInt(Box::new(i))
}
}
impl From<Box<BigInt>> for LiteralKind {
#[inline]
fn from(i: Box<BigInt>) -> Self {
Self::BigInt(i)
}
}
impl From<bool> for LiteralKind {
#[inline]
fn from(b: bool) -> Self {
Self::Bool(b)
}
}
impl ToInternedString for LiteralKind {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
match *self {
Self::String(st) => {
format!("\"{}\"", interner.resolve_expect(st))
}
Self::Num(num) => num.to_string(),
Self::Int(num) => num.to_string(),
Self::BigInt(ref num) => format!("{num}n"),
Self::Bool(v) => v.to_string(),
Self::Null => "null".to_owned(),
Self::Undefined => "undefined".to_owned(),
}
}
}