refactor(es/parser): Remove EnumKind to reduce compile time (#7137)

This commit is contained in:
Donny/강동윤 2023-03-24 11:40:26 +09:00 committed by GitHub
parent 4eef5532a4
commit 915f747cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 142 additions and 828 deletions

View File

@ -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

19
Cargo.lock generated
View File

@ -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",

View File

@ -1,22 +0,0 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
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"

View File

@ -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::<ItemImpl>()
.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::<Expr>()
.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,
}
}
}

View File

@ -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<EnumVar>,
}
///
#[derive(Debug, Default)]
pub struct EnumAttrs {
pub fns: Vec<FnDef>,
pub extras: Vec<Attribute>,
}
/// 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<Expr>,
}
/// 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<VariantAttr>,
pub extras: Vec<Attribute>,
/// Does this variant has `#[kind(delegate)]`?
pub has_delegate: bool,
}
#[derive(Debug)]
pub struct VariantAttr {
pub fn_name: Ident,
pub value: Option<Expr>,
}

View File

@ -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::<syn::DeriveInput>(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()
}

View File

@ -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<DeriveInput> 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<Self> {
let _function: Ident = input.parse()?;
let fns;
let _paren_token = parenthesized!(fns in input);
let fns: Punctuated<FnDef, Token![,]> = fns.parse_terminated(FnDef::parse)?;
Ok(EnumAttrs {
fns: fns.into_iter().collect(),
extras: Default::default(),
})
}
}
impl AddAssign<StdResult<Self, Attribute>> for EnumAttrs {
fn add_assign(&mut self, rhs: StdResult<Self, Attribute>) {
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<Expr> {
if is_bool(ty) {
return Some(Expr::Lit(ExprLit {
attrs: Default::default(),
lit: Lit::Bool(LitBool {
value: false,
span: def_site::<Span>(),
}),
}));
}
None
}
}
impl Parse for FnDef {
fn parse(input: ParseStream<'_>) -> Result<Self> {
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<Variant> 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<Self> {
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<StdResult<Self, Attribute>> for VariantAttrs {
fn add_assign(&mut self, rhs: StdResult<Self, Attribute>) {
#[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<Self> {
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<T>(attrs: Vec<Attribute>) -> T
where
T: Default + Parse + AddAssign<StdResult<T, Attribute>>,
{
/// returns `tokens` where `tts` = `vec![Group(Paren, tokens)]`
fn unwrap_paren<I>(tts: I) -> TokenStream
where
I: IntoIterator<Item = TokenTree>,
{
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<T>(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::<TokenStream>()
.expect("failed to create TokenStream for return type")
.into_iter()
.map(|mut tt| {
tt.set_span(span);
tt
})
.collect::<TokenStream>();
parse(tts.into()).expect("failed to parse string literal")
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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"] }

View File

@ -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<F, Ret>(
syntax: Syntax,

View File

@ -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<Atom>,
},
/// ':'
#[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<BigIntValue>,
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<JsWord> 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"),