use derive_finite_automaton::FiniteAutomataConstructor;
use derive_partial_eq_extras::PartialEqExtras;
use enum_variant_type::EnumVariantType;
use enum_variants_strings::EnumVariantsStrings;
use source_map::Span;
use tokenizer_lib::{sized_tokens::TokenStart, Token};
use crate::{ParseError, Quoted};
#[derive(Debug, FiniteAutomataConstructor, PartialEqExtras)]
#[automaton_mappings(
"{" => TSXToken::OpenBrace,
"}" => TSXToken::CloseBrace,
"[" => TSXToken::OpenBracket,
"]" => TSXToken::CloseBracket,
"(" => TSXToken::OpenParentheses,
")" => TSXToken::CloseParentheses,
":" => TSXToken::Colon,
"@" => TSXToken::At,
"," => TSXToken::Comma,
";" => TSXToken::SemiColon,
"#" => TSXToken::HashTag,
"+" => TSXToken::Add,
"+=" => TSXToken::AddAssign,
"++" => TSXToken::Increment,
"-" => TSXToken::Subtract,
"-=" => TSXToken::SubtractAssign,
"--" => TSXToken::Decrement,
"*" => TSXToken::Multiply,
"*=" => TSXToken::MultiplyAssign,
"**" => TSXToken::Exponent,
"**=" => TSXToken::ExponentAssign,
"/" => TSXToken::Divide,
"//" => TSXToken::Comment(String::new()),
"/=" => TSXToken::DivideAssign,
"/*" => TSXToken::MultiLineComment(String::new()),
"%" => TSXToken::Modulo,
"%=" => TSXToken::ModuloAssign,
"=" => TSXToken::Assign,
"==" => TSXToken::Equal,
"===" => TSXToken::StrictEqual,
"=>" => TSXToken::Arrow,
"!" => TSXToken::LogicalNot,
"!=" => TSXToken::NotEqual,
"!==" => TSXToken::StrictNotEqual,
"&" => TSXToken::BitwiseAnd,
"&=" => TSXToken::BitwiseAndAssign,
"&&" => TSXToken::LogicalAnd,
"&&=" => TSXToken::LogicalAndAssign,
"|" => TSXToken::BitwiseOr,
"|=" => TSXToken::BitwiseOrAssign,
"||" => TSXToken::LogicalOr,
"||=" => TSXToken::LogicalOrAssign,
"~" => TSXToken::BitwiseNot,
"^" => TSXToken::BitwiseXOr,
"^=" => TSXToken::BitwiseXorAssign,
"?" => TSXToken::QuestionMark,
"?:" => TSXToken::OptionalMember,
"?." => TSXToken::OptionalChain,
"?.(" => TSXToken::OptionalCall,
"?.[" => TSXToken::OptionalIndex,
"-?:" => TSXToken::NonOptionalMember,
"??" => TSXToken::NullishCoalescing,
"??=" => TSXToken::NullishCoalescingAssign,
"!=" => TSXToken::NotEqual,
"!==" => TSXToken::StrictNotEqual,
"<" => TSXToken::OpenChevron,
">" => TSXToken::CloseChevron,
"<=" => TSXToken::LessThanEqual,
">=" => TSXToken::GreaterThanEqual,
"<<" => TSXToken::BitwiseShiftLeft,
"<<=" => TSXToken::BitwiseShiftLeftAssign,
">>" => TSXToken::BitwiseShiftRight,
">>=" => TSXToken::BitwiseShiftRightAssign,
">>>" => TSXToken::BitwiseShiftRightUnsigned,
">>>=" => TSXToken::BitwiseShiftRightUnsignedAssign,
"." => TSXToken::Dot,
"..." => TSXToken::Spread,
)]
#[cfg_attr(feature = "extras", automaton_mappings(
">!" => TSXToken::InvertAssign,
"/%" => TSXToken::DividesOperator,
"<@>" => TSXToken::ComposeOperator,
"|>" => TSXToken::PipeOperator,
))]
#[rustfmt::skip]
pub enum TSXToken {
Identifier(String),
Keyword(TSXKeyword),
NumberLiteral(String),
StringLiteral(String, Quoted),
MultiLineComment(String), Comment(String),
RegexLiteral(String), RegexFlagLiteral(String),
TemplateLiteralStart, TemplateLiteralChunk(String), TemplateLiteralEnd,
TemplateLiteralExpressionStart, TemplateLiteralExpressionEnd,
Comma, SemiColon, Colon, Dot,
At,
Spread, Assign,
Arrow,
OpenParentheses,
CloseParentheses,
OpenBrace,
CloseBrace,
OpenBracket,
CloseBracket,
OpenChevron,
CloseChevron,
Add, Subtract, Multiply, Divide,
QuestionMark, Exponent, Modulo,
AddAssign, SubtractAssign, MultiplyAssign, DivideAssign, ExponentAssign, ModuloAssign,
Increment, Decrement,
BitwiseShiftLeft, BitwiseShiftRight, BitwiseShiftRightUnsigned,
BitwiseShiftLeftAssign, BitwiseShiftRightAssign, BitwiseShiftRightUnsignedAssign,
BitwiseOr, BitwiseXOr, BitwiseAnd, BitwiseNot,
BitwiseOrAssign, BitwiseAndAssign, BitwiseXorAssign,
LogicalOr, LogicalAnd, LogicalNot,
LogicalOrAssign, LogicalAndAssign,
Equal, NotEqual, StrictEqual, StrictNotEqual,
GreaterThanEqual, LessThanEqual,
OptionalChain, OptionalCall, OptionalIndex, NullishCoalescing, NullishCoalescingAssign,
OptionalMember,
NonOptionalMember,
HashTag,
JSXOpeningTagStart, JSXTagName(String), JSXOpeningTagEnd,
JSXClosingTagStart,
JSXClosingTagName(String),
JSXSelfClosingTag,
JSXAttributeKey(String), JSXAttributeAssign, JSXAttributeValue(String),
JSXContent(String), JSXContentLineBreak,
JSXExpressionStart, JSXExpressionEnd,
JSXFragmentStart, JSXFragmentEnd,
JSXComment(String),
#[cfg(feature = "extras")]
DividesOperator,
#[cfg(feature = "extras")]
InvertAssign,
#[cfg(feature = "extras")]
ComposeOperator,
#[cfg(feature = "extras")]
PipeOperator,
Cursor(crate::EmptyCursorId),
EOS
}
impl tokenizer_lib::TokenTrait for TSXToken {
fn is_skippable(&self) -> bool {
matches!(self, TSXToken::Cursor(_))
}
}
impl tokenizer_lib::sized_tokens::SizedToken for TSXToken {
fn length(&self) -> u32 {
match self {
TSXToken::Keyword(kw) => kw.to_str().len() as u32,
TSXToken::JSXClosingTagName(lit)
| TSXToken::TemplateLiteralChunk(lit)
| TSXToken::JSXAttributeKey(lit)
| TSXToken::JSXAttributeValue(lit)
| TSXToken::JSXContent(lit)
| TSXToken::JSXComment(lit)
| TSXToken::JSXTagName(lit)
| TSXToken::Identifier(lit)
| TSXToken::NumberLiteral(lit)
| TSXToken::RegexFlagLiteral(lit) => lit.len() as u32,
TSXToken::MultiLineComment(comment) => comment.len() as u32 + 4,
TSXToken::StringLiteral(comment, _) | TSXToken::Comment(comment) => {
comment.len() as u32 + 2
}
TSXToken::RegexLiteral(regex) => regex.len() as u32 + 2,
TSXToken::Comma
| TSXToken::SemiColon
| TSXToken::Colon
| TSXToken::At
| TSXToken::Assign
| TSXToken::OpenParentheses
| TSXToken::CloseParentheses
| TSXToken::OpenBrace
| TSXToken::CloseBrace
| TSXToken::OpenBracket
| TSXToken::CloseBracket
| TSXToken::OpenChevron
| TSXToken::CloseChevron
| TSXToken::Add
| TSXToken::Subtract
| TSXToken::Multiply
| TSXToken::Divide
| TSXToken::Modulo
| TSXToken::QuestionMark
| TSXToken::BitwiseOr
| TSXToken::BitwiseXOr
| TSXToken::BitwiseAnd
| TSXToken::BitwiseNot
| TSXToken::HashTag
| TSXToken::Dot
| TSXToken::TemplateLiteralStart
| TSXToken::TemplateLiteralEnd
| TSXToken::TemplateLiteralExpressionEnd
| TSXToken::JSXOpeningTagStart
| TSXToken::JSXOpeningTagEnd
| TSXToken::JSXExpressionStart
| TSXToken::JSXExpressionEnd
| TSXToken::JSXAttributeAssign => 1,
TSXToken::AddAssign
| TSXToken::SubtractAssign
| TSXToken::MultiplyAssign
| TSXToken::DivideAssign
| TSXToken::ModuloAssign
| TSXToken::Exponent
| TSXToken::ExponentAssign
| TSXToken::Increment
| TSXToken::Decrement
| TSXToken::Equal
| TSXToken::GreaterThanEqual
| TSXToken::LessThanEqual
| TSXToken::OptionalChain
| TSXToken::NullishCoalescing
| TSXToken::OptionalMember
| TSXToken::NonOptionalMember
| TSXToken::BitwiseOrAssign
| TSXToken::BitwiseAndAssign
| TSXToken::BitwiseXorAssign
| TSXToken::LogicalOr
| TSXToken::LogicalAnd
| TSXToken::LogicalNot
| TSXToken::Arrow
| TSXToken::BitwiseShiftLeft
| TSXToken::BitwiseShiftRight
| TSXToken::TemplateLiteralExpressionStart
| TSXToken::JSXFragmentStart => 2,
TSXToken::Spread
| TSXToken::StrictEqual
| TSXToken::OptionalCall
| TSXToken::OptionalIndex
| TSXToken::NullishCoalescingAssign
| TSXToken::LogicalOrAssign
| TSXToken::LogicalAndAssign
| TSXToken::NotEqual
| TSXToken::BitwiseShiftLeftAssign
| TSXToken::BitwiseShiftRightAssign
| TSXToken::StrictNotEqual
| TSXToken::BitwiseShiftRightUnsigned
| TSXToken::JSXFragmentEnd => 3,
TSXToken::BitwiseShiftRightUnsignedAssign => 4,
TSXToken::JSXClosingTagStart
| TSXToken::JSXSelfClosingTag
| TSXToken::JSXContentLineBreak
| TSXToken::EOS
| TSXToken::Cursor(_) => 0,
#[cfg(feature = "extras")]
TSXToken::InvertAssign | TSXToken::DividesOperator | TSXToken::PipeOperator => 2,
#[cfg(feature = "extras")]
TSXToken::ComposeOperator => 3,
}
}
}
impl Eq for TSXToken {}
pub trait TSXKeywordNode: Into<TSXKeyword> + Copy + Default {}
#[derive(Debug, PartialEq, Eq, EnumVariantsStrings, EnumVariantType)]
#[enum_variants_strings_transform(transform = "lower_case")]
#[evt(module = "tsx_keywords", implement_marker_traits(TSXKeywordNode), derive(Clone, Copy, PartialEq, Eq, Debug, Default))]
#[rustfmt::skip]
pub enum TSXKeyword {
Const, Var, Let,
If, Else, For, While, Do, Switch,
Class, Function, Constructor,
New, This, Super,
Case, Yield, Return, Continue, Break,
Import, Export, Default, From,
In, Of,
TypeOf, InstanceOf, Void, Delete,
Debugger,
Try, Catch, Finally, Throw,
Async, Await,
Static,
Get, Set,
Extends,
Null,
True, False,
Abstract, Implements,
Enum, Interface, Type,
Private, Public, Protected,
As, Declare, Readonly, Infer, Is, Satisfies, Namespace, KeyOf,
#[cfg(feature = "extras")] Module,
#[cfg(feature = "extras")] Server, #[cfg(feature = "extras")] Worker,
#[cfg(feature = "extras")] Nominal, #[cfg(feature = "extras")] Performs,
#[cfg(feature = "extras")]
Generator,
#[cfg(feature = "extras")]
Deferred
}
impl TSXKeyword {
#[cfg(feature = "extras")]
pub(crate) fn is_special_function_header(&self) -> bool {
matches!(self, TSXKeyword::Worker | TSXKeyword::Server | TSXKeyword::Generator)
}
#[cfg(not(feature = "extras"))]
pub(crate) fn is_special_function_header(&self) -> bool {
false
}
pub(crate) fn is_in_function_header(&self) -> bool {
matches!(self, TSXKeyword::Function | TSXKeyword::Async)
}
}
impl std::fmt::Display for TSXKeyword {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self, f)
}
}
impl std::fmt::Display for TSXToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TSXToken::Keyword(kw) => std::fmt::Debug::fmt(kw, f),
TSXToken::NumberLiteral(num) => std::fmt::Display::fmt(num, f),
TSXToken::Identifier(value) => std::fmt::Display::fmt(value, f),
_ => std::fmt::Debug::fmt(&self, f),
}
}
}
impl TSXToken {
#[must_use]
pub fn is_comment(&self) -> bool {
matches!(self, TSXToken::Comment(_) | TSXToken::MultiLineComment(_))
}
pub fn try_into_comment(
token: Token<TSXToken, TokenStart>,
) -> Result<(String, Span), Token<TSXToken, TokenStart>> {
if let Token(TSXToken::MultiLineComment(c), d) = token {
let len = c.len();
Ok((c, d.with_length(len + 4)))
} else if let Token(TSXToken::Comment(c), d) = token {
let len = c.len();
Ok((c, d.with_length(len + 2)))
} else {
Err(token)
}
}
#[must_use]
pub fn is_expression_prefix(&self) -> bool {
matches!(
self,
TSXToken::Keyword(TSXKeyword::Return | TSXKeyword::Yield | TSXKeyword::Throw)
| TSXToken::Assign
| TSXToken::Arrow
| TSXToken::OpenParentheses
| TSXToken::OpenBrace
| TSXToken::JSXExpressionStart
| TSXToken::QuestionMark
| TSXToken::Colon
| TSXToken::LogicalNot
| TSXToken::LogicalAnd
| TSXToken::LogicalOr
)
}
#[must_use]
pub fn from_slice(slice: &str) -> Self {
match TSXKeyword::from_str(slice) {
Ok(keyword_token) => TSXToken::Keyword(keyword_token),
Err(_) => TSXToken::Identifier(slice.to_owned()),
}
}
pub(crate) fn is_symbol(&self) -> bool {
!matches!(self, TSXToken::Keyword(_) | TSXToken::Identifier(..))
}
}
pub(crate) fn token_as_identifier(
token: Token<TSXToken, TokenStart>,
at_location: &str,
) -> Result<(String, Span), ParseError> {
let position = token.get_span();
let name = match token.0 {
TSXToken::Identifier(value) => value,
TSXToken::Keyword(keyword) => EnumVariantsStrings::to_str(&keyword).to_owned(),
token_type => {
return Err(ParseError::new(
crate::ParseErrors::ExpectedIdent { found: token_type, at_location },
position,
));
}
};
Ok((name, position))
}