use crate::lexer::template::TemplateString;
use bitflags::bitflags;
use boa_ast::{Keyword, LinearSpan, PositionGroup, Punctuator, Span, Spanned};
use boa_interner::{Interner, Sym};
use num_bigint::BigInt;
#[derive(Debug, Clone, PartialEq)]
pub struct Token {
kind: TokenKind,
span: Span,
linear_span: LinearSpan,
}
impl Token {
#[inline]
#[must_use]
pub const fn new(kind: TokenKind, span: Span, linear_span: LinearSpan) -> Self {
Self {
kind,
span,
linear_span,
}
}
#[inline]
#[must_use]
pub fn new_by_position_group(
kind: TokenKind,
start: PositionGroup,
end: PositionGroup,
) -> Self {
Self::new(
kind,
Span::new(start.position(), end.position()),
LinearSpan::new(start.linear_position(), end.linear_position()),
)
}
#[inline]
#[must_use]
pub const fn kind(&self) -> &TokenKind {
&self.kind
}
#[inline]
#[must_use]
pub const fn start_group(&self) -> PositionGroup {
PositionGroup::new(self.span.start(), self.linear_span.start())
}
#[inline]
#[must_use]
pub const fn linear_span(&self) -> LinearSpan {
self.linear_span
}
#[inline]
pub(crate) fn to_string(&self, interner: &Interner) -> String {
self.kind.to_string(interner)
}
}
impl Spanned for Token {
#[inline]
fn span(&self) -> Span {
self.span
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum Numeric {
Rational(f64),
Integer(i32),
BigInt(Box<BigInt>),
}
impl From<f64> for Numeric {
#[inline]
fn from(n: f64) -> Self {
Self::Rational(n)
}
}
impl From<i32> for Numeric {
#[inline]
fn from(n: i32) -> Self {
Self::Integer(n)
}
}
impl From<BigInt> for Numeric {
#[inline]
fn from(n: BigInt) -> Self {
Self::BigInt(Box::new(n))
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum TokenKind {
BooleanLiteral((bool, ContainsEscapeSequence)),
EOF,
IdentifierName((Sym, ContainsEscapeSequence)),
PrivateIdentifier(Sym),
Keyword((Keyword, bool)),
NullLiteral(ContainsEscapeSequence),
NumericLiteral(Numeric),
Punctuator(Punctuator),
StringLiteral((Sym, EscapeSequence)),
TemplateNoSubstitution(TemplateString),
TemplateMiddle(TemplateString),
RegularExpressionLiteral(Sym, Sym),
LineTerminator,
Comment,
}
impl From<bool> for TokenKind {
#[inline]
fn from(oth: bool) -> Self {
Self::BooleanLiteral((oth, ContainsEscapeSequence(false)))
}
}
impl From<(Keyword, bool)> for TokenKind {
#[inline]
fn from(kw: (Keyword, bool)) -> Self {
Self::Keyword(kw)
}
}
impl From<Punctuator> for TokenKind {
#[inline]
fn from(punc: Punctuator) -> Self {
Self::Punctuator(punc)
}
}
impl From<Numeric> for TokenKind {
#[inline]
fn from(num: Numeric) -> Self {
Self::NumericLiteral(num)
}
}
impl TokenKind {
#[inline]
#[must_use]
pub const fn boolean_literal(lit: bool) -> Self {
Self::BooleanLiteral((lit, ContainsEscapeSequence(false)))
}
#[inline]
#[must_use]
pub const fn eof() -> Self {
Self::EOF
}
#[inline]
#[must_use]
pub const fn identifier(ident: Sym) -> Self {
Self::IdentifierName((ident, ContainsEscapeSequence(false)))
}
#[must_use]
pub fn numeric_literal<L>(lit: L) -> Self
where
L: Into<Numeric>,
{
Self::NumericLiteral(lit.into())
}
#[inline]
#[must_use]
pub const fn punctuator(punc: Punctuator) -> Self {
Self::Punctuator(punc)
}
#[inline]
#[must_use]
pub const fn string_literal(lit: Sym, escape_sequence: EscapeSequence) -> Self {
Self::StringLiteral((lit, escape_sequence))
}
#[inline]
#[must_use]
pub const fn template_middle(template_string: TemplateString) -> Self {
Self::TemplateMiddle(template_string)
}
#[inline]
#[must_use]
pub const fn template_no_substitution(template_string: TemplateString) -> Self {
Self::TemplateNoSubstitution(template_string)
}
#[inline]
#[must_use]
pub const fn regular_expression_literal(body: Sym, flags: Sym) -> Self {
Self::RegularExpressionLiteral(body, flags)
}
#[inline]
#[must_use]
pub const fn line_terminator() -> Self {
Self::LineTerminator
}
#[inline]
#[must_use]
pub const fn comment() -> Self {
Self::Comment
}
#[must_use]
pub fn to_string(&self, interner: &Interner) -> String {
match *self {
Self::BooleanLiteral((val, _)) => val.to_string(),
Self::EOF => "end of file".to_owned(),
Self::IdentifierName((ident, _)) => interner.resolve_expect(ident).to_string(),
Self::PrivateIdentifier(ident) => format!("#{}", interner.resolve_expect(ident)),
Self::Keyword((word, _)) => word.to_string(),
Self::NullLiteral(_) => "null".to_owned(),
Self::NumericLiteral(Numeric::Rational(num)) => num.to_string(),
Self::NumericLiteral(Numeric::Integer(num)) => num.to_string(),
Self::NumericLiteral(Numeric::BigInt(ref num)) => format!("{num}n"),
Self::Punctuator(punc) => punc.to_string(),
Self::StringLiteral((lit, _)) => interner.resolve_expect(lit).to_string(),
Self::TemplateNoSubstitution(ts) | Self::TemplateMiddle(ts) => {
interner.resolve_expect(ts.raw()).to_string()
}
Self::RegularExpressionLiteral(body, flags) => {
format!(
"/{}/{}",
interner.resolve_expect(body),
interner.resolve_expect(flags),
)
}
Self::LineTerminator => "line terminator".to_owned(),
Self::Comment => "comment".to_owned(),
}
}
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct EscapeSequence: u8 {
const LEGACY_OCTAL = 0b0000_0001;
const NON_OCTAL_DECIMAL = 0b0000_0010;
const OTHER = 0b0000_0100;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ContainsEscapeSequence(pub bool);