diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2e7524f47d5f..8ce3554c1ec8 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -216,9 +216,6 @@ jobs: - crate: dbg-swc os: ubuntu-latest runner: ubuntu-latest - - crate: enum_kind - os: ubuntu-latest - runner: ubuntu-latest - crate: from_variant os: ubuntu-latest runner: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 2052982f1767..b87a8923b4d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -982,16 +982,6 @@ dependencies = [ "syn", ] -[[package]] -name = "enum_kind" -version = "0.2.2" -dependencies = [ - "pmutil", - "proc-macro2", - "swc_macros_common", - "syn", -] - [[package]] name = "enumset" version = "1.0.12" @@ -2056,9 +2046,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "openssl" -version = "0.10.43" +version = "0.10.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376" +checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -2088,9 +2078,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.79" +version = "0.9.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4" +checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b" dependencies = [ "autocfg", "cc", @@ -3727,7 +3717,6 @@ version = "0.130.9" dependencies = [ "criterion", "either", - "enum_kind", "lexical", "num-bigint", "pretty_assertions", diff --git a/crates/enum_kind/Cargo.toml b/crates/enum_kind/Cargo.toml deleted file mode 100644 index 297549042bd3..000000000000 --- a/crates/enum_kind/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["강동윤 "] -description = "Easily manage values related to enum." -documentation = "https://rustdoc.swc.rs/enum_kind/" -edition = "2021" -license = "Apache-2.0" -name = "enum_kind" -repository = "https://github.com/swc-project/swc.git" -version = "0.2.2" - -[lib] -bench = false -proc-macro = true - -[dependencies] -pmutil = "0.5.1" -proc-macro2 = "1" -swc_macros_common = {version = "0.3.7", path = "../swc_macros_common"} - -[dependencies.syn] -features = ["full", "parsing", "printing", "extra-traits"] -version = "1" diff --git a/crates/enum_kind/src/expand.rs b/crates/enum_kind/src/expand.rs deleted file mode 100644 index 4c37f7a8c93a..000000000000 --- a/crates/enum_kind/src/expand.rs +++ /dev/null @@ -1,213 +0,0 @@ -use pmutil::{smart_quote, Quote, SpanExt}; -use swc_macros_common::prelude::*; -use syn::*; - -use crate::{input::*, util::is_bool}; - -pub fn expand( - Input { - attrs, - name, - variants, - generics, - vis, - }: Input, -) -> Item { - // verify variant attributes. - { - for v in &variants { - if v.attrs.has_delegate { - match v.data { - Fields::Named(FieldsNamed { - named: ref fields, .. - }) - | Fields::Unnamed(FieldsUnnamed { - unnamed: ref fields, - .. - }) if fields.len() == 1 => {} - _ => panic!( - "currently #[kind(delegate)] can be applied to variant with only one field" - ), - } - } - for value in &v.attrs.fn_values { - let used = attrs - .fns - .iter() - .map(|f| &f.name) - .any(|fn_name| value.fn_name == *fn_name || value.fn_name == "delegate"); - if !used { - panic!("Unknown function `{}` on variant {}", value.fn_name, v.name) - } - } - } - } - - let items = attrs - .fns - .into_iter() - .map(|f| f.expand(&name, vis.clone(), &variants)) - .map(ImplItem::Method) - .fold(TokenStream::new(), |mut t, i| { - i.to_tokens(&mut t); - t - }); - - Quote::new_call_site() - .quote_with(smart_quote!( - Vars { - Type: name, - items, - }, - { - impl Type { - items - } - } - )) - .parse::() - .with_generics(generics) - .into() -} - -impl FnDef { - fn expand(self, enum_name: &Ident, vis: Visibility, variants: &[EnumVar]) -> ImplItemMethod { - let FnDef { - name, - return_type, - default_value, - } = self; - - let name_span = name.span(); - - let arms = - variants - .iter() - .map(|v| -> Arm { - // Bind this variant. - let (pat, mut fields) = - VariantBinder::new(Some(enum_name), &v.name, &v.data, &v.attrs.extras) - .bind("_", Some(call_site()), None); - - let body = { - let value = match v - .attrs - .fn_values - .iter() - .find(|fn_val| fn_val.fn_name == name) - .map(|attr| attr.value.clone()) - { - Some(Some(value)) => Some(value), - - // not specified, but has `#[kind(delegate)]` - None if v.attrs.has_delegate => { - assert_eq!(fields.len(), 1); - let field = fields.remove(0); - Some( - Quote::new_call_site() - .quote_with(smart_quote!( - Vars { - field, - method: &name, - }, - { field.method() } - )) - .parse(), - ) - } - - // if return type is bool and attribute is specified, value is true. - Some(None) if is_bool(&return_type) => Some(Expr::Lit(ExprLit { - attrs: Default::default(), - lit: Lit::Bool(LitBool { - value: true, - span: Span::call_site(), - }), - })), - _ => None, - }; - - value - .or_else(|| default_value.clone()) - .map(Box::new) - .unwrap_or_else(|| { - panic!( - "value of {fn_name} for {variant} is not specified.", - fn_name = name, - variant = v.name - ); - }) - }; - - Arm { - pat, - body, - - // Forward cfg attributes. - attrs: v - .attrs - .extras - .iter() - .filter(|attr| is_attr_name(attr, "cfg")) - .cloned() - .collect(), - fat_arrow_token: call_site(), - comma: Some(call_site()), - guard: None, - } - }) - .collect(); - - // match self {} - let match_expr = Expr::Match(ExprMatch { - attrs: Default::default(), - match_token: call_site(), - brace_token: call_site(), - - expr: Quote::new_call_site() - .quote_with(smart_quote!(Vars {}, { self })) - .parse::() - .into(), - - arms, - }); - - ImplItemMethod { - // fn (&self) -> ReturnTpe - sig: Signature { - asyncness: None, - constness: None, - unsafety: None, - abi: None, - fn_token: name.span().as_token(), - paren_token: name.span().as_token(), - inputs: vec![ - // TODO - Element::End(FnArg::Receiver(Receiver { - reference: Some((name_span.as_token(), None)), - self_token: name_span.as_token(), - mutability: None, - attrs: Default::default(), - })), - ] - .into_iter() - .collect(), - ident: name, - generics: Default::default(), - variadic: None, - output: ReturnType::Type(name_span.as_token(), Box::new(return_type)), - }, - - block: Block { - brace_token: call_site(), - stmts: vec![Stmt::Expr(match_expr)], - }, - - // TODO - vis, - - attrs: Default::default(), - defaultness: None, - } - } -} diff --git a/crates/enum_kind/src/input.rs b/crates/enum_kind/src/input.rs deleted file mode 100644 index b7db6c16d263..000000000000 --- a/crates/enum_kind/src/input.rs +++ /dev/null @@ -1,56 +0,0 @@ -use syn::*; - -/// Parsed input. -#[derive(Debug)] -pub struct Input { - pub attrs: EnumAttrs, - /// Name of enum. - pub name: Ident, - pub vis: Visibility, - pub generics: Generics, - - pub variants: Vec, -} - -/// -#[derive(Debug, Default)] -pub struct EnumAttrs { - pub fns: Vec, - pub extras: Vec, -} - -/// Function to generate. -/// -/// `#[kind(function(name = "bool"))]` -#[derive(Debug)] -pub struct FnDef { - /// Name of function. - pub name: Ident, - pub return_type: Type, - - pub default_value: Option, -} - -/// Variant of enum. -#[derive(Debug)] -pub struct EnumVar { - /// Name of variant. - pub name: Ident, - pub attrs: VariantAttrs, - pub data: Fields, -} - -/// Parsed attributes. -#[derive(Debug, Default)] -pub struct VariantAttrs { - pub fn_values: Vec, - pub extras: Vec, - /// Does this variant has `#[kind(delegate)]`? - pub has_delegate: bool, -} - -#[derive(Debug)] -pub struct VariantAttr { - pub fn_name: Ident, - pub value: Option, -} diff --git a/crates/enum_kind/src/lib.rs b/crates/enum_kind/src/lib.rs deleted file mode 100644 index ee8edc39c250..000000000000 --- a/crates/enum_kind/src/lib.rs +++ /dev/null @@ -1,149 +0,0 @@ -extern crate proc_macro; - -use swc_macros_common::prelude::*; - -mod expand; -mod input; -mod parse; -mod util; - -/// # Attributes on enum -/// ## functions -/// `#[kind(functions(name = "return_type"))]` -/// -/// ```rust,ignore -/// #[macro_use] -/// extern crate enum_kind; -/// -/// /// You can split attributes if you want. -/// #[derive(Kind)] -/// #[kind(functions(is_a = "bool", is_b = "bool"))] -/// #[kind(functions(is_a_or_b = "bool", num = "u8"))] -/// pub enum E { -/// #[kind(is_a, is_a_or_b, num = "1")] -/// A, -/// /// You can split attributes if you want. -/// #[kind(is_b)] -/// #[kind(is_a_or_b)] -/// #[kind(num = "2")] -/// B(u8), -/// /// Default value of bool is false if not specified and true if specified. -/// /// -/// /// Both struct like variant and tuple like variant are supported. -/// #[kind(num = "3")] -/// C {}, -/// } -/// -/// # fn main() { -/// assert!(E::A.is_a() && E::A.is_a_or_b() && !E::A.is_b()); -/// assert_eq!(E::A.num(), 1); -/// -/// assert!(!E::B(0).is_a() && E::B(0).is_a_or_b() && E::B(0).is_b()); -/// assert_eq!(E::B(0).num(), 2); -/// -/// assert!(!E::C {}.is_a() && !E::C {}.is_a_or_b() && !E::C {}.is_b()); -/// assert_eq!(E::C {}.num(), 3); -/// -/// # } -/// ``` -/// -/// ----- -/// -/// # Real usecase -/// -/// ```rust,ignore -/// #[macro_use] -/// extern crate enum_kind; -/// -/// #[derive(Kind, Debug, Clone, Eq, PartialEq, Hash)] -/// #[kind(function(precedence = "u8"))] -/// pub enum BinOpToken { -/// /// `==` -/// #[kind(precedence = "6")] -/// EqEq, -/// /// `!=` -/// #[kind(precedence = "6")] -/// NotEq, -/// /// `===` -/// #[kind(precedence = "6")] -/// EqEqEq, -/// /// `!==` -/// #[kind(precedence = "6")] -/// NotEqEq, -/// /// `<` -/// #[kind(precedence = "7")] -/// Lt, -/// /// `<=` -/// #[kind(precedence = "7")] -/// LtEq, -/// /// `>` -/// #[kind(precedence = "7")] -/// Gt, -/// #[kind(precedence = "7")] -/// /// `>=` -/// #[kind(precedence = "7")] -/// GtEq, -/// /// `<<` -/// #[kind(precedence = "8")] -/// LShift, -/// /// `>>` -/// #[kind(precedence = "8")] -/// RShift, -/// /// `>>>` -/// #[kind(precedence = "8")] -/// ZeroFillRShift, -/// /// `+` -/// #[kind(precedence = "9")] -/// Plus, -/// /// `-` -/// #[kind(precedence = "9")] -/// Minus, -/// /// `*` -/// #[kind(precedence = "10")] -/// Mul, -/// /// `/` -/// #[kind(precedence = "10")] -/// Div, -/// /// `%` -/// #[kind(precedence = "10")] -/// Mod, -/// /// `|` -/// #[kind(precedence = "3")] -/// BitOr, -/// /// `^` -/// #[kind(precedence = "4")] -/// BitXor, -/// /// `&` -/// #[kind(precedence = "5")] -/// BitAnd, -/// /// `in` -/// #[kind(precedence = "7")] -/// In, -/// /// `instanceof` -/// #[kind(precedence = "7")] -/// InstanceOf, -/// /// `**` -/// #[kind(precedence = "10")] -/// Exp, -/// /// `||` -/// #[kind(precedence = "1")] -/// LogicalOr, -/// /// `&&` -/// #[kind(precedence = "2")] -/// LogicalAnd, -/// } -/// -/// # fn main() {} -/// ``` -#[proc_macro_derive(Kind, attributes(kind))] -pub fn derive_kind(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = syn::parse::(input) - .map(From::from) - .expect("failed to parse derive input"); - let item = expand::expand(input); - let tokens = item.into_token_stream(); - - // println!("Expanded:{}", tokens); - - tokens.into() -} diff --git a/crates/enum_kind/src/parse.rs b/crates/enum_kind/src/parse.rs deleted file mode 100644 index 51ecece57a00..000000000000 --- a/crates/enum_kind/src/parse.rs +++ /dev/null @@ -1,231 +0,0 @@ -use std::{fmt::Display, ops::AddAssign, result::Result as StdResult}; - -use swc_macros_common::prelude::*; -use syn::{ - parse::{Parse, ParseStream}, - *, -}; - -use crate::{input::*, util::is_bool}; - -impl From for Input { - fn from( - DeriveInput { - ident: name, - vis, - attrs, - generics, - data, - }: DeriveInput, - ) -> Self { - let variants = match data { - Data::Enum(data) => data.variants.into_iter().map(From::from).collect(), - _ => panic!("#[derive(Kind)] only works for enums"), - }; - - Input { - name, - vis, - generics, - attrs: parse_attrs(attrs), - variants, - } - } -} - -impl Parse for EnumAttrs { - fn parse(input: ParseStream<'_>) -> Result { - let _function: Ident = input.parse()?; - - let fns; - let _paren_token = parenthesized!(fns in input); - - let fns: Punctuated = fns.parse_terminated(FnDef::parse)?; - Ok(EnumAttrs { - fns: fns.into_iter().collect(), - extras: Default::default(), - }) - } -} - -impl AddAssign> for EnumAttrs { - fn add_assign(&mut self, rhs: StdResult) { - match rhs { - Ok(attr) => { - self.fns.extend(attr.fns); - self.extras.extend(attr.extras); - } - Err(attr) => self.extras.push(attr), - } - } -} - -impl FnDef { - fn def_value_for_type(ty: &Type) -> Option { - if is_bool(ty) { - return Some(Expr::Lit(ExprLit { - attrs: Default::default(), - lit: Lit::Bool(LitBool { - value: false, - span: def_site::(), - }), - })); - } - - None - } -} - -impl Parse for FnDef { - fn parse(input: ParseStream<'_>) -> Result { - let name: Ident = input.parse()?; - let _: Token!(=) = input.parse()?; - let return_type: LitStr = input.parse()?; - - if name == "delegate" { - panic!("function name cannot be `delegate`") - } - - let return_type = parse_str_as_tokens(return_type); - Ok(FnDef { - default_value: FnDef::def_value_for_type(&return_type), - name, - return_type, - }) - } -} - -impl From for EnumVar { - fn from( - Variant { - attrs, - fields, - ident: name, - .. - }: Variant, - ) -> Self { - EnumVar { - name, - data: fields, - attrs: parse_attrs(attrs), - } - } -} - -impl Parse for VariantAttrs { - fn parse(input: ParseStream<'_>) -> Result { - let fn_values: Punctuated<_, token::Comma> = Punctuated::parse_terminated(input)?; - let has_delegate = fn_values - .iter() - .any(|f: &VariantAttr| f.fn_name == "delegate"); - Ok(VariantAttrs { - fn_values: fn_values.into_iter().collect(), - extras: Default::default(), - has_delegate, - }) - } -} - -impl AddAssign> for VariantAttrs { - fn add_assign(&mut self, rhs: StdResult) { - #[allow(clippy::suspicious_op_assign_impl)] - match rhs { - Ok(attr) => { - self.fn_values.extend(attr.fn_values); - self.extras.extend(attr.extras); - self.has_delegate = self.has_delegate || attr.has_delegate; - } - Err(attr) => self.extras.push(attr), - } - } -} - -impl Parse for VariantAttr { - fn parse(input: ParseStream<'_>) -> Result { - let fn_name: Ident = input.parse()?; - - let lookahead = input.lookahead1(); - let value = if lookahead.peek(Token![=]) { - let _: Token![=] = input.parse()?; - Some(input.parse().map(parse_str_as_tokens)?) - } else { - None - }; - - Ok(VariantAttr { fn_name, value }) - } -} - -/// Parse kind attr as MetaItem. -fn parse_attrs(attrs: Vec) -> T -where - T: Default + Parse + AddAssign>, -{ - /// returns `tokens` where `tts` = `vec![Group(Paren, tokens)]` - fn unwrap_paren(tts: I) -> TokenStream - where - I: IntoIterator, - { - let mut tts = tts.into_iter(); - let tt = tts.next(); - - match tt { - Some(TokenTree::Group(ref g)) if g.delimiter() == Delimiter::Parenthesis => { - if tts.next().is_none() { - return g.stream(); - } - g.stream() - } - tt => panic!( - "expected tokens to be wrapped in a paren like #[kind(tokens)]\ngot {}", - match tt { - Some(ref tt) => tt as &dyn Display, - None => &"None" as &dyn Display, - } - ), - } - } - - let mut res = Default::default(); - for attr in attrs { - if is_attr_name(&attr, "doc") { - continue; - } - - if is_attr_name(&attr, "kind") { - let tts = unwrap_paren(attr.tokens); - let parsed: T = parse(tts.into()) - .unwrap_or_else(|err| panic!("failed to parse attribute: {}", err)); - - res += Ok(parsed); - } else { - res += Err(attr) - } - } - - res -} - -/// Parse content of string literal. -fn parse_str_as_tokens(lit: LitStr) -> T -where - T: Parse, -{ - let span = lit.span(); - // WTF? Literal does not provide a way to get string... - let tt = lit.value(); - - // TODO:Remove '"' only for first and last. - let tts = tt - .replace('\"', "") - .parse::() - .expect("failed to create TokenStream for return type") - .into_iter() - .map(|mut tt| { - tt.set_span(span); - tt - }) - .collect::(); - - parse(tts.into()).expect("failed to parse string literal") -} diff --git a/crates/enum_kind/src/util.rs b/crates/enum_kind/src/util.rs deleted file mode 100644 index 1395a27cb609..000000000000 --- a/crates/enum_kind/src/util.rs +++ /dev/null @@ -1,19 +0,0 @@ -use syn::*; - -pub fn is_bool(ty: &Type) -> bool { - if let Type::Path(TypePath { - qself: None, - path: Path { - leading_colon: None, - ref segments, - }, - }) = ty - { - // check for bool - if segments.len() == 1 && segments.first().unwrap().ident == "bool" { - return true; - } - } - - false -} diff --git a/crates/enum_kind/tests/usage.rs b/crates/enum_kind/tests/usage.rs deleted file mode 100644 index 76c63dbbaaa0..000000000000 --- a/crates/enum_kind/tests/usage.rs +++ /dev/null @@ -1,41 +0,0 @@ -use enum_kind::*; - -#[derive(Debug, Kind)] -#[kind(functions(is_a = "bool", prec = "u8"))] -pub enum Tokens { - #[kind(is_a)] - #[kind(prec = "7")] - A, - #[kind(prec = "6")] - StructLike {}, - #[kind(prec = "5")] - TupleLike(u8), - - #[kind(prec = "6")] - #[cfg(feature = "not-used")] - Unused, -} - -#[test] -fn simple_bool() { - assert!(Tokens::A.is_a()); - assert!(!Tokens::StructLike {}.is_a()); - assert!(!Tokens::TupleLike(5).is_a()); -} - -#[derive(Debug, Kind)] -#[kind(functions(wanted = "bool"))] -pub enum Delegate { - #[kind(wanted)] - Wanted, - #[kind(delegate)] - May(Del), -} - -#[derive(Debug, Kind)] -#[kind(functions(wanted = "bool"))] -pub enum Del { - #[kind(wanted)] - Yes, - No, -} diff --git a/crates/swc_ecma_parser/Cargo.toml b/crates/swc_ecma_parser/Cargo.toml index 5c2783f16b8c..83dc0503fad8 100644 --- a/crates/swc_ecma_parser/Cargo.toml +++ b/crates/swc_ecma_parser/Cargo.toml @@ -25,7 +25,6 @@ verify = ["swc_ecma_visit"] [dependencies] either = { version = "1.4" } -enum_kind = { version = "0.2.2", path = "../enum_kind" } lexical = { version = "6.1.0", features = ["power-of-two"] } num-bigint = "0.4" serde = { version = "1", features = ["derive"] } diff --git a/crates/swc_ecma_parser/src/lexer/state.rs b/crates/swc_ecma_parser/src/lexer/state.rs index 357162e661fc..363b8d6edbd7 100644 --- a/crates/swc_ecma_parser/src/lexer/state.rs +++ b/crates/swc_ecma_parser/src/lexer/state.rs @@ -1,6 +1,5 @@ use std::mem::take; -use enum_kind::Kind; use swc_common::{BytePos, Span}; use tracing::trace; @@ -62,7 +61,7 @@ enum TokenType { } impl TokenType { #[inline] - fn before_expr(self) -> bool { + const fn before_expr(self) -> bool { match self { TokenType::JSXName | TokenType::JSXTagStart @@ -760,35 +759,49 @@ impl TokenContexts { /// given point in the program is loosely based on sweet.js' approach. /// See https://github.com/mozilla/sweet.js/wiki/design #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Kind)] -#[kind(function(is_expr = "bool", preserve_space = "bool"))] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TokenContext { BraceStmt, - #[kind(is_expr)] BraceExpr, - #[kind(is_expr)] TplQuasi, ParenStmt { /// Is this `for` loop? is_for_loop: bool, }, - #[kind(is_expr)] ParenExpr, - #[kind(is_expr, preserve_space)] Tpl { /// Start of a template literal. start: BytePos, }, - #[kind(is_expr)] FnExpr, - #[kind(is_expr)] ClassExpr, JSXOpeningTag, JSXClosingTag, - #[kind(is_expr, preserve_space)] JSXExpr, } +impl TokenContext { + pub(crate) const fn is_expr(&self) -> bool { + matches!( + self, + Self::BraceExpr + | Self::TplQuasi + | Self::ParenExpr + | Self::Tpl { .. } + | Self::FnExpr + | Self::ClassExpr + | Self::JSXExpr + ) + } + + pub(crate) const fn preserve_space(&self) -> bool { + match self { + Self::Tpl { .. } | Self::JSXExpr => true, + _ => false, + } + } +} + #[cfg(test)] pub(crate) fn with_lexer( syntax: Syntax, diff --git a/crates/swc_ecma_parser/src/token.rs b/crates/swc_ecma_parser/src/token.rs index 01fa2ca725e8..f5ca0e42defa 100644 --- a/crates/swc_ecma_parser/src/token.rs +++ b/crates/swc_ecma_parser/src/token.rs @@ -6,7 +6,6 @@ use std::{ fmt::{self, Debug, Display, Formatter}, }; -use enum_kind::Kind; use num_bigint::BigInt as BigIntValue; use swc_atoms::{js_word, Atom, JsWord}; use swc_common::{Span, Spanned}; @@ -16,17 +15,14 @@ use swc_ecma_ast::BinaryOp; pub(crate) use self::{AssignOpToken::*, BinOpToken::*, Keyword::*, Token::*}; use crate::{error::Error, lexer::LexResult}; -#[derive(Kind, Clone, PartialEq)] -#[kind(functions(starts_expr = "bool", before_expr = "bool"))] +#[derive(Clone, PartialEq)] pub enum Token { /// Identifier, "null", "true", "false". /// /// Contains `null` and `` - #[kind(delegate)] Word(Word), /// '=>' - #[kind(before_expr)] Arrow, /// '#' @@ -38,93 +34,72 @@ pub enum Token { Dot, /// '...' - #[kind(before_expr)] DotDotDot, /// '!' - #[kind(before_expr, starts_expr)] Bang, /// '(' - #[kind(before_expr, starts_expr)] LParen, /// ')' RParen, /// `[` - #[kind(before_expr, starts_expr)] LBracket, /// ']' RBracket, /// '{' - #[kind(before_expr, starts_expr)] LBrace, /// '}' RBrace, /// ';' - #[kind(before_expr)] Semi, /// ',' - #[kind(before_expr)] Comma, /// '`' - #[kind(starts_expr)] BackQuote, Template { raw: Atom, cooked: LexResult, }, /// ':' - #[kind(before_expr)] Colon, /// '::' - #[kind(before_expr)] ColonColon, /// - #[kind(delegate)] BinOp(BinOpToken), /// - #[kind(before_expr)] AssignOp(AssignOpToken), /// '${' - #[kind(before_expr, starts_expr)] DollarLBrace, /// '?' - #[kind(before_expr)] QuestionMark, /// `++` - #[kind(before_expr, starts_expr)] PlusPlus, /// `--` - #[kind(before_expr, starts_expr)] MinusMinus, /// `~` - #[kind(before_expr, starts_expr)] Tilde, /// String literal. Span of this token contains quote. - #[kind(starts_expr)] Str { value: JsWord, raw: Atom, }, /// Regexp literal. - #[kind(starts_expr)] Regex(Atom, Atom), /// TODO: Make Num as enum and separate decimal, binary, ..etc - #[kind(starts_expr)] Num { value: f64, raw: Atom, }, - #[kind(starts_expr)] BigInt { value: Box, raw: Atom, @@ -133,11 +108,9 @@ pub enum Token { JSXName { name: JsWord, }, - #[kind(before_expr)] JSXText { raw: Atom, }, - #[kind(starts_expr)] JSXTagStart, JSXTagEnd, @@ -145,8 +118,56 @@ pub enum Token { Error(Error), } -#[derive(Kind, Debug, Clone, Copy, Eq, PartialEq, Hash)] -#[kind(functions(starts_expr = "bool"))] +impl Token { + pub(crate) const fn before_expr(&self) -> bool { + match self { + Self::Word(w) => w.before_expr(), + Self::BinOp(w) => w.before_expr(), + Self::Arrow + | Self::DotDotDot + | Self::Bang + | Self::LParen + | Self::LBrace + | Self::LBracket + | Self::Semi + | Self::Comma + | Self::Colon + | Self::ColonColon + | Self::AssignOp(..) + | Self::DollarLBrace + | Self::QuestionMark + | Self::PlusPlus + | Self::MinusMinus + | Self::Tilde + | Self::JSXText { .. } => true, + _ => false, + } + } + + pub(crate) const fn starts_expr(&self) -> bool { + match self { + Self::Word(w) => w.starts_expr(), + Self::BinOp(w) => w.starts_expr(), + Self::Bang + | Self::LParen + | Self::LBrace + | Self::LBracket + | Self::BackQuote + | Self::DollarLBrace + | Self::PlusPlus + | Self::MinusMinus + | Self::Tilde + | Self::Str { .. } + | Self::Regex(..) + | Self::Num { .. } + | Self::BigInt { .. } + | Self::JSXTagStart => true, + _ => false, + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum BinOpToken { /// `==` EqEq, @@ -172,10 +193,8 @@ pub enum BinOpToken { ZeroFillRShift, /// `+` - #[kind(starts_expr)] Add, /// `-` - #[kind(starts_expr)] Sub, /// `*` Mul, @@ -210,7 +229,11 @@ pub enum BinOpToken { } impl BinOpToken { - pub const fn before_expr(self) -> bool { + pub(crate) const fn starts_expr(&self) -> bool { + matches!(self, Self::Add | Self::Sub) + } + + pub(crate) const fn before_expr(self) -> bool { true } } @@ -230,23 +253,33 @@ impl Spanned for TokenAndSpan { } } -#[derive(Kind, Clone, PartialEq, Eq, Hash)] -#[kind(functions(starts_expr = "bool", before_expr = "bool"))] +#[derive(Clone, PartialEq, Eq, Hash)] pub enum Word { - #[kind(delegate)] Keyword(Keyword), - #[kind(starts_expr)] Null, - #[kind(starts_expr)] True, - #[kind(starts_expr)] False, - #[kind(starts_expr)] Ident(JsWord), } +impl Word { + pub(crate) const fn before_expr(&self) -> bool { + match self { + Word::Keyword(k) => k.before_expr(), + _ => false, + } + } + + pub(crate) const fn starts_expr(&self) -> bool { + match self { + Word::Keyword(k) => k.starts_expr(), + _ => true, + } + } +} + impl From for Word { fn from(i: JsWord) -> Self { match i { @@ -377,40 +410,30 @@ impl Debug for Word { } /// Keywords -#[derive(Kind, Clone, Copy, PartialEq, Eq, Hash)] -#[kind(function(before_expr = "bool", starts_expr = "bool"))] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum Keyword { /// Spec says this might be identifier. - #[kind(before_expr, starts_expr)] Await, - Break, - #[kind(before_expr)] Case, Catch, Continue, Debugger, - #[kind(before_expr)] Default_, - #[kind(before_expr)] Do, - #[kind(before_expr)] Else, Finally, For, - #[kind(starts_expr)] Function, If, - #[kind(before_expr)] Return, Switch, - #[kind(before_expr, starts_expr)] Throw, Try, @@ -420,44 +443,68 @@ pub enum Keyword { While, With, - #[kind(before_expr, starts_expr)] New, - #[kind(starts_expr)] This, - #[kind(starts_expr)] Super, - #[kind(starts_expr)] Class, - #[kind(before_expr)] Extends, Export, - #[kind(starts_expr)] Import, /// Spec says this might be identifier. - #[kind(before_expr, starts_expr)] Yield, - #[kind(before_expr)] In, - #[kind(before_expr)] InstanceOf, - - #[kind(before_expr, starts_expr)] TypeOf, - - #[kind(before_expr, starts_expr)] Void, - - #[kind(before_expr, starts_expr)] Delete, } impl Keyword { - pub(crate) fn into_js_word(self) -> JsWord { + pub(crate) const fn before_expr(&self) -> bool { + matches!( + self, + Self::Await + | Self::Case + | Self::Default_ + | Self::Do + | Self::Else + | Self::Return + | Self::Throw + | Self::New + | Self::Extends + | Self::Yield + | Self::In + | Self::InstanceOf + | Self::TypeOf + | Self::Void + | Self::Delete + ) + } + + pub(crate) const fn starts_expr(&self) -> bool { + matches!( + self, + Self::Await + | Self::Function + | Self::Throw + | Self::New + | Self::This + | Self::Super + | Self::Class + | Self::Import + | Self::Yield + | Self::TypeOf + | Self::Void + | Self::Delete + ) + } + + pub(crate) const fn into_js_word(self) -> JsWord { match self { Await => js_word!("await"), Break => js_word!("break"),