mirror of
https://github.com/swc-project/swc.git
synced 2024-11-24 02:06:08 +03:00
refactor(es/parser): Remove EnumKind
to reduce compile time (#7137)
This commit is contained in:
parent
4eef5532a4
commit
915f747cb7
3
.github/workflows/CI.yml
vendored
3
.github/workflows/CI.yml
vendored
@ -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
19
Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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>,
|
||||
}
|
@ -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()
|
||||
}
|
@ -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")
|
||||
}
|
@ -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
|
||||
}
|
@ -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,
|
||||
}
|
@ -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"] }
|
||||
|
@ -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,
|
||||
|
@ -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"),
|
||||
|
Loading…
Reference in New Issue
Block a user