Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/ast_node/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/ast_node/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"9011d1577db9a906ff2b62847293ac8c0992e13495cc175eb3a00d52893d4a90","src/ast_node_macro.rs":"9989e80bbc6506a04dee26bddd7c1d6a91ef73dfb20a8f3f38c0919e9bffa167","src/enum_deserialize.rs":"d6b78a6b8fdd2825ed5c4f73e38d4f0d6cb58a5e97e8f9d8aeca7dc5ae863e66","src/lib.rs":"770de4bd5e7df7c402ecc2226b17fa6520c0f7cca72c1702891801a6453a33a9","src/spanned.rs":"5142d4026fa5b415269e792fccb6907fe2e92de24b0b4c3dac8b1db32591a25f"},"package":"c09c69dffe06d222d072c878c3afe86eee2179806f20503faec97250268b4c24"}
|
||||
47
third-party/vendor/ast_node/Cargo.toml
vendored
Normal file
47
third-party/vendor/ast_node/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "ast_node"
|
||||
version = "0.9.5"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Macros for ast nodes."
|
||||
documentation = "https://rustdoc.swc.rs/ast_node/"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
resolver = "1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.pmutil]
|
||||
version = "0.6.1"
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1"
|
||||
|
||||
[dependencies.swc_macros_common]
|
||||
version = "0.3.8"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "2"
|
||||
features = [
|
||||
"derive",
|
||||
"fold",
|
||||
"parsing",
|
||||
"printing",
|
||||
"visit-mut",
|
||||
]
|
||||
171
third-party/vendor/ast_node/src/ast_node_macro.rs
vendored
Normal file
171
third-party/vendor/ast_node/src/ast_node_macro.rs
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
use pmutil::{smart_quote, Quote};
|
||||
use swc_macros_common::prelude::*;
|
||||
use syn::{
|
||||
self,
|
||||
parse::{Parse, ParseStream},
|
||||
*,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Args {
|
||||
pub ty: Literal,
|
||||
}
|
||||
|
||||
impl Parse for Args {
|
||||
fn parse(i: ParseStream<'_>) -> syn::Result<Self> {
|
||||
Ok(Args { ty: i.parse()? })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_struct(args: Args, i: DeriveInput) -> Vec<ItemImpl> {
|
||||
let mut items = vec![];
|
||||
let generics = i.generics.clone();
|
||||
// let item_ident = Ident::new("Item", i.ident.span());
|
||||
|
||||
items.push(
|
||||
Quote::new_call_site()
|
||||
.quote_with(smart_quote!(
|
||||
Vars {
|
||||
Type: i.ident.clone(),
|
||||
type_str: args.ty
|
||||
},
|
||||
{
|
||||
impl ::swc_common::AstNode for Type {
|
||||
const TYPE: &'static str = type_str;
|
||||
}
|
||||
}
|
||||
))
|
||||
.parse::<ItemImpl>()
|
||||
.with_generics(generics),
|
||||
);
|
||||
|
||||
// let ident = i.ident.clone();
|
||||
// let cloned = i.clone();
|
||||
|
||||
// items.push({
|
||||
// let (fields, item_data) = match i.data {
|
||||
// Data::Struct(DataStruct {
|
||||
// struct_token,
|
||||
// semi_token,
|
||||
// fields: Fields::Named(FieldsNamed { brace_token, named }),
|
||||
// }) => {
|
||||
// let fields: Punctuated<_, token::Comma> = named
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .map(|field| FieldValue {
|
||||
// member: Member::Named(field.ident.clone().unwrap()),
|
||||
// expr: Quote::new_call_site()
|
||||
// .quote_with(smart_quote!(
|
||||
// Vars {
|
||||
// field: &field.ident
|
||||
// },
|
||||
// { node.node.field }
|
||||
// ))
|
||||
// .parse(),
|
||||
|
||||
// attrs: field
|
||||
// .attrs
|
||||
// .into_iter()
|
||||
// .filter(|attr| is_attr_name(attr, "cfg"))
|
||||
// .collect(),
|
||||
// colon_token: Some(call_site()),
|
||||
// })
|
||||
// .collect();
|
||||
|
||||
// let item_data = Data::Struct(DataStruct {
|
||||
// struct_token,
|
||||
// semi_token,
|
||||
// fields: Fields::Named(FieldsNamed {
|
||||
// brace_token,
|
||||
// named: named
|
||||
// .into_pairs()
|
||||
// .map(|pair| {
|
||||
// let handle = |v: Field| Field {
|
||||
// vis: Visibility::Inherited,
|
||||
// attrs: v
|
||||
// .attrs
|
||||
// .into_iter()
|
||||
// .filter(|attr| {
|
||||
// is_attr_name(attr, "serde") ||
|
||||
// is_attr_name(attr, "cfg") })
|
||||
// .collect(),
|
||||
// ..v
|
||||
// };
|
||||
|
||||
// match pair {
|
||||
// Pair::End(v) => Pair::End(handle(v)),
|
||||
// Pair::Punctuated(v, p) =>
|
||||
// Pair::Punctuated(handle(v), p), }
|
||||
// })
|
||||
// .collect(),
|
||||
// }),
|
||||
// });
|
||||
|
||||
// (fields, item_data)
|
||||
// }
|
||||
// _ => unreachable!("enum / tuple struct / union with
|
||||
// #[ast_node(\"Foo\")]"), };
|
||||
|
||||
// let convert_item_to_self =
|
||||
// Quote::new_call_site().quote_with(smart_quote!( Vars {
|
||||
// fields,
|
||||
// Type: &ident
|
||||
// },
|
||||
// { Type { fields } }
|
||||
// ));
|
||||
|
||||
// let body = Quote::new_call_site().quote_with(smart_quote!(
|
||||
// Vars {
|
||||
// convert_item_to_self
|
||||
// },
|
||||
// {
|
||||
// let node =
|
||||
// ::swc_common::serializer::Node::<Item>::deserialize(deserializer)?;
|
||||
|
||||
// if node.ty != <Self as ::swc_common::AstNode>::TYPE {
|
||||
// return Err(D::Error::unknown_variant(
|
||||
// &node.ty,
|
||||
// &[<Self as ::swc_common::AstNode>::TYPE],
|
||||
// ));
|
||||
// }
|
||||
|
||||
// Ok(convert_item_to_self)
|
||||
// }
|
||||
// ));
|
||||
|
||||
// let item = DeriveInput {
|
||||
// vis: Visibility::Inherited,
|
||||
// ident: item_ident,
|
||||
// attrs: vec![],
|
||||
// data: item_data,
|
||||
// ..cloned
|
||||
// };
|
||||
// Quote::new_call_site()
|
||||
// .quote_with(smart_quote!(
|
||||
// Vars {
|
||||
// // A new item which implements Deserialize
|
||||
// item,
|
||||
// Type: ident,
|
||||
// body
|
||||
// },
|
||||
// {
|
||||
// impl<'de> ::serde::Deserialize<'de> for Type {
|
||||
// fn deserialize<D>(deserializer: D) -> Result<Self,
|
||||
// D::Error> where
|
||||
// D: ::serde::Deserializer<'de>,
|
||||
// {
|
||||
// use ::serde::de::Error;
|
||||
// #[derive(::serde::Deserialize)]
|
||||
// #[serde(rename_all = "camelCase")]
|
||||
// ite
|
||||
// body
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ))
|
||||
// .parse::<ItemImpl>()
|
||||
// .with_generics(generics)
|
||||
// });
|
||||
|
||||
items
|
||||
}
|
||||
442
third-party/vendor/ast_node/src/enum_deserialize.rs
vendored
Normal file
442
third-party/vendor/ast_node/src/enum_deserialize.rs
vendored
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
use pmutil::{q, smart_quote, Quote, SpanExt};
|
||||
use swc_macros_common::prelude::*;
|
||||
use syn::{
|
||||
self,
|
||||
parse::{Parse, ParseStream},
|
||||
*,
|
||||
};
|
||||
|
||||
struct VariantAttr {
|
||||
tags: Punctuated<Lit, Token![,]>,
|
||||
}
|
||||
|
||||
impl Parse for VariantAttr {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
Ok(VariantAttr {
|
||||
tags: input.call(Punctuated::parse_terminated)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand(
|
||||
DeriveInput {
|
||||
generics,
|
||||
ident,
|
||||
data,
|
||||
..
|
||||
}: DeriveInput,
|
||||
) -> ItemImpl {
|
||||
let data = match data {
|
||||
Data::Enum(data) => data,
|
||||
_ => unreachable!("expand_enum is called with none-enum item"),
|
||||
};
|
||||
|
||||
let mut has_wildcard = false;
|
||||
|
||||
let deserialize = {
|
||||
let mut all_tags: Punctuated<_, token::Comma> = Default::default();
|
||||
let tag_match_arms = data
|
||||
.variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let field_type = match variant.fields {
|
||||
Fields::Unnamed(ref fields) => {
|
||||
assert_eq!(
|
||||
fields.unnamed.len(),
|
||||
1,
|
||||
"#[ast_node] enum cannot contain variant with multiple fields"
|
||||
);
|
||||
|
||||
fields.unnamed.last().unwrap().ty.clone()
|
||||
}
|
||||
_ => {
|
||||
unreachable!("#[ast_node] enum cannot contain named fields or unit variant")
|
||||
}
|
||||
};
|
||||
let tags = variant
|
||||
.attrs
|
||||
.iter()
|
||||
.filter_map(|attr| -> Option<VariantAttr> {
|
||||
if !is_attr_name(attr, "tag") {
|
||||
return None;
|
||||
}
|
||||
let tokens = match &attr.meta {
|
||||
Meta::List(meta) => meta.tokens.clone(),
|
||||
_ => {
|
||||
panic!("#[tag] attribute must be in form of #[tag(..)]")
|
||||
}
|
||||
};
|
||||
let tags = parse2(tokens).expect("failed to parse #[tag] attribute");
|
||||
|
||||
Some(tags)
|
||||
})
|
||||
.flat_map(|v| v.tags)
|
||||
.collect::<Punctuated<_, token::Comma>>();
|
||||
|
||||
assert!(
|
||||
!tags.is_empty(),
|
||||
"All #[ast_node] enum variants have one or more tag"
|
||||
);
|
||||
|
||||
// TODO: Clean up this code
|
||||
if tags.len() == 1
|
||||
&& match tags.first() {
|
||||
Some(Lit::Str(s)) => &*s.value() == "*",
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
has_wildcard = true;
|
||||
} else {
|
||||
for tag in tags.iter() {
|
||||
all_tags.push(tag.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Arm {
|
||||
attrs: Default::default(),
|
||||
pat: Pat::Path(
|
||||
q!(
|
||||
Vars {
|
||||
Variant: &variant.ident
|
||||
},
|
||||
(__TypeVariant::Variant)
|
||||
)
|
||||
.parse(),
|
||||
),
|
||||
guard: Default::default(),
|
||||
fat_arrow_token: variant.ident.span().as_token(),
|
||||
body: q!(
|
||||
Vars {
|
||||
Variant: &variant.ident,
|
||||
FieldType: field_type,
|
||||
},
|
||||
{
|
||||
swc_common::private::serde::Result::map(
|
||||
<FieldType as serde::Deserialize>::deserialize(
|
||||
swc_common::private::serde::de::ContentDeserializer::<
|
||||
__D::Error,
|
||||
>::new(__content),
|
||||
),
|
||||
Self::Variant,
|
||||
)
|
||||
}
|
||||
)
|
||||
.parse(),
|
||||
comma: Some(variant.ident.span().as_token()),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Arm>>();
|
||||
|
||||
let tag_expr = {
|
||||
let mut visit_str_arms = vec![];
|
||||
let mut visit_bytes_arms = vec![];
|
||||
|
||||
for variant in &data.variants {
|
||||
let tags = variant
|
||||
.attrs
|
||||
.iter()
|
||||
.filter_map(|attr| -> Option<VariantAttr> {
|
||||
if !is_attr_name(attr, "tag") {
|
||||
return None;
|
||||
}
|
||||
let tokens = match &attr.meta {
|
||||
Meta::List(meta) => meta.tokens.clone(),
|
||||
_ => {
|
||||
panic!("#[tag] attribute must be in form of #[tag(..)]")
|
||||
}
|
||||
};
|
||||
let tags = parse2(tokens).expect("failed to parse #[tag] attribute");
|
||||
|
||||
Some(tags)
|
||||
})
|
||||
.flat_map(|v| v.tags)
|
||||
.collect::<Punctuated<_, token::Comma>>();
|
||||
|
||||
assert!(
|
||||
!tags.is_empty(),
|
||||
"All #[ast_node] enum variants have one or more tag"
|
||||
);
|
||||
let (str_pat, bytes_pat) = {
|
||||
if tags.len() == 1
|
||||
&& match tags.first() {
|
||||
Some(Lit::Str(s)) => &*s.value() == "*",
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
(
|
||||
Pat::Wild(PatWild {
|
||||
attrs: Default::default(),
|
||||
underscore_token: variant.ident.span().as_token(),
|
||||
}),
|
||||
Pat::Wild(PatWild {
|
||||
attrs: Default::default(),
|
||||
underscore_token: variant.ident.span().as_token(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
fn make_pat(lit: Lit) -> (Pat, Pat) {
|
||||
let s = match lit.clone() {
|
||||
Lit::Str(s) => s.value(),
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
(
|
||||
Pat::Lit(PatLit {
|
||||
attrs: Default::default(),
|
||||
lit,
|
||||
}),
|
||||
Pat::Lit(PatLit {
|
||||
attrs: Default::default(),
|
||||
lit: Lit::ByteStr(LitByteStr::new(s.as_bytes(), call_site())),
|
||||
}),
|
||||
)
|
||||
}
|
||||
if tags.len() == 1 {
|
||||
make_pat(tags.first().unwrap().clone())
|
||||
} else {
|
||||
let mut str_cases = Punctuated::new();
|
||||
let mut bytes_cases = Punctuated::new();
|
||||
|
||||
for tag in tags {
|
||||
let (str_pat, bytes_pat) = make_pat(tag.clone());
|
||||
str_cases.push(str_pat);
|
||||
bytes_cases.push(bytes_pat);
|
||||
}
|
||||
|
||||
(
|
||||
Pat::Or(PatOr {
|
||||
attrs: Default::default(),
|
||||
leading_vert: Default::default(),
|
||||
cases: str_cases,
|
||||
}),
|
||||
Pat::Or(PatOr {
|
||||
attrs: Default::default(),
|
||||
leading_vert: Default::default(),
|
||||
cases: bytes_cases,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
visit_str_arms.push(Arm {
|
||||
attrs: Default::default(),
|
||||
pat: str_pat,
|
||||
guard: None,
|
||||
fat_arrow_token: variant.ident.span().as_token(),
|
||||
body: q!(
|
||||
Vars {
|
||||
Variant: &variant.ident,
|
||||
},
|
||||
{ Ok(__TypeVariant::Variant) }
|
||||
)
|
||||
.parse(),
|
||||
comma: Some(variant.ident.span().as_token()),
|
||||
});
|
||||
visit_bytes_arms.push(Arm {
|
||||
attrs: Default::default(),
|
||||
pat: bytes_pat,
|
||||
guard: None,
|
||||
fat_arrow_token: variant.ident.span().as_token(),
|
||||
body: q!(
|
||||
Vars {
|
||||
Variant: &variant.ident,
|
||||
},
|
||||
{ Ok(__TypeVariant::Variant) }
|
||||
)
|
||||
.parse(),
|
||||
comma: Some(variant.ident.span().as_token()),
|
||||
});
|
||||
}
|
||||
|
||||
if !has_wildcard {
|
||||
visit_str_arms.push(Arm {
|
||||
attrs: Default::default(),
|
||||
pat: Pat::Wild(PatWild {
|
||||
attrs: Default::default(),
|
||||
underscore_token: ident.span().as_token(),
|
||||
}),
|
||||
guard: None,
|
||||
fat_arrow_token: ident.span().as_token(),
|
||||
body: q!({
|
||||
swc_common::private::serde::Err(serde::de::Error::unknown_variant(
|
||||
__value, VARIANTS,
|
||||
))
|
||||
})
|
||||
.parse(),
|
||||
comma: Some(ident.span().as_token()),
|
||||
});
|
||||
visit_bytes_arms.push(Arm {
|
||||
attrs: Default::default(),
|
||||
pat: Pat::Wild(PatWild {
|
||||
attrs: Default::default(),
|
||||
underscore_token: ident.span().as_token(),
|
||||
}),
|
||||
guard: None,
|
||||
fat_arrow_token: ident.span().as_token(),
|
||||
body: q!({
|
||||
{
|
||||
let __value = &swc_common::private::serde::from_utf8_lossy(__value);
|
||||
swc_common::private::serde::Err(serde::de::Error::unknown_variant(
|
||||
__value, VARIANTS,
|
||||
))
|
||||
}
|
||||
})
|
||||
.parse(),
|
||||
comma: Some(ident.span().as_token()),
|
||||
});
|
||||
}
|
||||
|
||||
let visit_str_body = Expr::Match(ExprMatch {
|
||||
attrs: Default::default(),
|
||||
match_token: call_site(),
|
||||
expr: q!((__value)).parse(),
|
||||
brace_token: call_site(),
|
||||
arms: visit_str_arms,
|
||||
});
|
||||
let visit_bytes_body = Expr::Match(ExprMatch {
|
||||
attrs: Default::default(),
|
||||
match_token: call_site(),
|
||||
expr: q!((__value)).parse(),
|
||||
brace_token: call_site(),
|
||||
arms: visit_bytes_arms,
|
||||
});
|
||||
|
||||
q!(
|
||||
Vars {
|
||||
visit_str_body,
|
||||
visit_bytes_body,
|
||||
all_tags: &all_tags,
|
||||
},
|
||||
{
|
||||
{
|
||||
static VARIANTS: &[&str] = &[all_tags];
|
||||
|
||||
struct __TypeVariantVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for __TypeVariantVisitor {
|
||||
type Value = __TypeVariant;
|
||||
fn expecting(
|
||||
&self,
|
||||
__formatter: &mut swc_common::private::serde::Formatter,
|
||||
) -> swc_common::private::serde::fmt::Result
|
||||
{
|
||||
swc_common::private::serde::Formatter::write_str(
|
||||
__formatter,
|
||||
"variant identifier",
|
||||
)
|
||||
}
|
||||
|
||||
fn visit_str<__E>(
|
||||
self,
|
||||
__value: &str,
|
||||
) -> swc_common::private::serde::Result<Self::Value, __E>
|
||||
where
|
||||
__E: serde::de::Error,
|
||||
{
|
||||
visit_str_body
|
||||
}
|
||||
|
||||
fn visit_bytes<__E>(
|
||||
self,
|
||||
__value: &[u8],
|
||||
) -> swc_common::private::serde::Result<Self::Value, __E>
|
||||
where
|
||||
__E: serde::de::Error,
|
||||
{
|
||||
visit_bytes_body
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for __TypeVariant {
|
||||
#[inline]
|
||||
fn deserialize<__D>(
|
||||
__deserializer: __D,
|
||||
) -> swc_common::private::serde::Result<Self, __D::Error>
|
||||
where
|
||||
__D: serde::Deserializer<'de>,
|
||||
{
|
||||
serde::Deserializer::deserialize_identifier(
|
||||
__deserializer,
|
||||
__TypeVariantVisitor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let ty = swc_common::serializer::Type::deserialize(
|
||||
swc_common::private::serde::de::ContentRefDeserializer::<__D::Error>::new(
|
||||
&__content,
|
||||
),
|
||||
)?;
|
||||
|
||||
let __tagged = __TypeVariant::deserialize(
|
||||
swc_common::private::serde::de::ContentDeserializer::<__D::Error>::new(
|
||||
swc_common::private::serde::de::Content::Str(&ty.ty),
|
||||
)
|
||||
)?;
|
||||
|
||||
__tagged
|
||||
}
|
||||
}
|
||||
)
|
||||
.parse::<Expr>()
|
||||
};
|
||||
|
||||
let match_type_expr = Expr::Match(ExprMatch {
|
||||
attrs: Default::default(),
|
||||
match_token: call_site(),
|
||||
expr: q!({ __tagged }).parse(),
|
||||
brace_token: call_site(),
|
||||
arms: tag_match_arms,
|
||||
});
|
||||
|
||||
let variants: Punctuated<Variant, Token![,]> = {
|
||||
data.variants
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|variant| Variant {
|
||||
attrs: Default::default(),
|
||||
fields: Fields::Unit,
|
||||
..variant
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
Quote::new_call_site()
|
||||
.quote_with(smart_quote!(
|
||||
Vars {
|
||||
match_type_expr,
|
||||
Enum: &ident,
|
||||
tag_expr,
|
||||
variants
|
||||
},
|
||||
{
|
||||
#[cfg(feature = "serde-impl")]
|
||||
impl<'de> serde::Deserialize<'de> for Enum {
|
||||
#[allow(unreachable_code)]
|
||||
fn deserialize<__D>(
|
||||
__deserializer: __D,
|
||||
) -> ::std::result::Result<Self, __D::Error>
|
||||
where
|
||||
__D: serde::Deserializer<'de>,
|
||||
{
|
||||
enum __TypeVariant {
|
||||
variants,
|
||||
}
|
||||
|
||||
let __content = <swc_common::private::serde::de::Content as serde::Deserialize>::deserialize(
|
||||
__deserializer,
|
||||
)?;
|
||||
|
||||
let __tagged = tag_expr;
|
||||
|
||||
match_type_expr
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
.parse::<ItemImpl>()
|
||||
.with_generics(generics)
|
||||
};
|
||||
|
||||
deserialize
|
||||
}
|
||||
308
third-party/vendor/ast_node/src/lib.rs
vendored
Normal file
308
third-party/vendor/ast_node/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
#![deny(clippy::all)]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use pmutil::{smart_quote, Quote, ToTokensExt};
|
||||
use swc_macros_common::prelude::*;
|
||||
use syn::{self, visit_mut::VisitMut, *};
|
||||
|
||||
mod ast_node_macro;
|
||||
mod enum_deserialize;
|
||||
mod spanned;
|
||||
|
||||
/// Derives [`swc_common::Spanned`]. See [`swc_common::Spanned`] for
|
||||
/// documentation.
|
||||
#[proc_macro_derive(Spanned, attributes(span))]
|
||||
pub fn derive_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");
|
||||
|
||||
let item = self::spanned::derive(input);
|
||||
|
||||
print("derive(Spanned)", item.dump())
|
||||
}
|
||||
|
||||
/// Derives `serde::Deserialize` which is aware of `tag` based deserialization.
|
||||
#[proc_macro_derive(DeserializeEnum, attributes(tag))]
|
||||
pub fn derive_deserialize_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");
|
||||
|
||||
let item = enum_deserialize::expand(input);
|
||||
|
||||
print("derive(DeserializeEnum)", item.dump())
|
||||
}
|
||||
|
||||
/// Derives `serde::Serialize` and `serde::Deserialize`.
|
||||
///
|
||||
/// # Struct attributes
|
||||
///
|
||||
/// `#[ast_serde("A")]` adds `"type": "A"` to json when serialized, and
|
||||
/// deserializes as the type only if `type` field of json string is `A`.
|
||||
///
|
||||
/// # Enum attributes
|
||||
////
|
||||
/// ## Type-level attributes
|
||||
///
|
||||
/// This macro does not accept arguments if used on enum.
|
||||
///
|
||||
/// ## Variant attributes
|
||||
///
|
||||
/// ### `#[tag("Expr")]`
|
||||
///
|
||||
/// You can tell "Use this variant if `type` is `Expr`".
|
||||
///
|
||||
/// This attribute can be applied multiple time, if a variant consumes multiple
|
||||
/// `type`s.
|
||||
///
|
||||
/// For example, `Lit` of swc_ecma_ast is an enum, but `Expr`, which contains
|
||||
/// `Lit` as a variant, is also an enum.
|
||||
/// So the `Lit` variant has multiple `#[tag]`-s like
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// enum Expr {
|
||||
/// #[tag("StringLiteral")]
|
||||
/// #[tag("NumericLiteral")]
|
||||
/// #[tag("BooleanLiteral")]
|
||||
/// Lit(Lit),
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// so the deserializer can decide which variant to use.
|
||||
///
|
||||
///
|
||||
/// `#[tag]` also supports wildcard like `#[tag("*")]`. You can use this if
|
||||
/// there are two many variants.
|
||||
#[proc_macro_attribute]
|
||||
pub fn ast_serde(
|
||||
args: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput");
|
||||
|
||||
// we should use call_site
|
||||
let mut item = Quote::new(Span::call_site());
|
||||
item = match input.data {
|
||||
Data::Enum(..) => {
|
||||
if !args.is_empty() {
|
||||
panic!("#[ast_serde] on enum does not accept any argument")
|
||||
}
|
||||
|
||||
item.quote_with(smart_quote!(Vars { input }, {
|
||||
#[derive(::serde::Serialize, ::swc_common::DeserializeEnum)]
|
||||
#[serde(untagged)]
|
||||
input
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
let args: Option<ast_node_macro::Args> = if args.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(parse(args).expect("failed to parse args of #[ast_serde]"))
|
||||
};
|
||||
|
||||
let serde_tag = match input.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(..),
|
||||
..
|
||||
}) => {
|
||||
if args.is_some() {
|
||||
Some(Quote::new_call_site().quote_with(smart_quote!(Vars {}, {
|
||||
#[serde(tag = "type")]
|
||||
})))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let serde_rename = args.as_ref().map(|args| {
|
||||
Quote::new_call_site().quote_with(smart_quote!(Vars { name: &args.ty },{
|
||||
#[serde(rename = name)]
|
||||
}))
|
||||
});
|
||||
|
||||
item.quote_with(smart_quote!(Vars { input, serde_tag, serde_rename }, {
|
||||
#[derive(::serde::Serialize, ::serde::Deserialize)]
|
||||
serde_tag
|
||||
#[serde(rename_all = "camelCase")]
|
||||
serde_rename
|
||||
input
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
print("ast_serde", item.into())
|
||||
}
|
||||
|
||||
struct AddAttr;
|
||||
|
||||
impl VisitMut for AddAttr {
|
||||
fn visit_field_mut(&mut self, f: &mut Field) {
|
||||
f.attrs
|
||||
.push(parse_quote!(#[cfg_attr(feature = "__rkyv", omit_bounds)]));
|
||||
}
|
||||
}
|
||||
|
||||
/// Alias for
|
||||
/// `#[derive(Spanned, Fold, Clone, Debug, PartialEq)]` for a struct and
|
||||
/// `#[derive(Spanned, Fold, Clone, Debug, PartialEq, FromVariant)]` for an
|
||||
/// enum.
|
||||
#[proc_macro_attribute]
|
||||
pub fn ast_node(
|
||||
args: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let mut input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput");
|
||||
|
||||
AddAttr.visit_data_mut(&mut input.data);
|
||||
|
||||
// we should use call_site
|
||||
let mut item = Quote::new(Span::call_site());
|
||||
item = match input.data {
|
||||
Data::Enum(..) => {
|
||||
struct EnumArgs {
|
||||
clone: bool,
|
||||
}
|
||||
impl parse::Parse for EnumArgs {
|
||||
fn parse(i: parse::ParseStream<'_>) -> syn::Result<Self> {
|
||||
let name: Ident = i.parse()?;
|
||||
if name != "no_clone" {
|
||||
return Err(i.error("unknown attribute"));
|
||||
}
|
||||
Ok(EnumArgs { clone: false })
|
||||
}
|
||||
}
|
||||
let args = if args.is_empty() {
|
||||
EnumArgs { clone: true }
|
||||
} else {
|
||||
parse(args).expect("failed to parse args of #[ast_node]")
|
||||
};
|
||||
|
||||
let clone = if args.clone {
|
||||
Some(Quote::new_call_site().quote_with(smart_quote!(Vars {}, {
|
||||
#[derive(Clone)]
|
||||
})))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
item.quote_with(smart_quote!(Vars { input, clone }, {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[cfg_attr(
|
||||
feature = "serde-impl",
|
||||
derive(
|
||||
::serde::Serialize,
|
||||
)
|
||||
)]
|
||||
#[derive(
|
||||
::swc_common::FromVariant,
|
||||
::swc_common::Spanned,
|
||||
Debug,
|
||||
PartialEq,
|
||||
::swc_common::DeserializeEnum,
|
||||
)]
|
||||
clone
|
||||
#[cfg_attr(
|
||||
feature = "rkyv-impl",
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(u32)))]
|
||||
#[cfg_attr(
|
||||
feature = "rkyv-impl",
|
||||
archive(bound(
|
||||
serialize = "__S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + rkyv::ser::SharedSerializeRegistry",
|
||||
deserialize = "__D: rkyv::de::SharedDeserializeRegistry"
|
||||
))
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "serde-impl",
|
||||
serde(untagged)
|
||||
)]
|
||||
input
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
let args: Option<ast_node_macro::Args> = if args.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(parse(args).expect("failed to parse args of #[ast_node]"))
|
||||
};
|
||||
|
||||
let serde_tag = match input.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(..),
|
||||
..
|
||||
}) => {
|
||||
if args.is_some() {
|
||||
Some(Quote::new_call_site().quote_with(smart_quote!(Vars {}, {
|
||||
#[cfg_attr(
|
||||
feature = "serde-impl",
|
||||
serde(tag = "type")
|
||||
)]
|
||||
})))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let serde_rename = args.as_ref().map(|args| {
|
||||
Quote::new_call_site().quote_with(smart_quote!(Vars { name: &args.ty }, {
|
||||
#[cfg_attr(
|
||||
feature = "serde-impl",
|
||||
serde(rename = name)
|
||||
)]
|
||||
}))
|
||||
});
|
||||
|
||||
let ast_node_impl = args
|
||||
.as_ref()
|
||||
.map(|args| ast_node_macro::expand_struct(args.clone(), input.clone()));
|
||||
|
||||
let mut quote =
|
||||
item.quote_with(smart_quote!(Vars { input, serde_tag, serde_rename }, {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(::swc_common::Spanned, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serde-impl",
|
||||
derive(::serde::Serialize, ::serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "rkyv-impl",
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
#[cfg_attr(
|
||||
feature = "rkyv-impl",
|
||||
archive(
|
||||
bound(
|
||||
serialize = "__S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + rkyv::ser::SharedSerializeRegistry",
|
||||
deserialize = "__D: rkyv::de::SharedDeserializeRegistry"
|
||||
)
|
||||
)
|
||||
)]
|
||||
serde_tag
|
||||
#[cfg_attr(
|
||||
feature = "serde-impl",
|
||||
serde(rename_all = "camelCase")
|
||||
)]
|
||||
serde_rename
|
||||
input
|
||||
}));
|
||||
|
||||
if let Some(items) = ast_node_impl {
|
||||
for item in items {
|
||||
quote.push_tokens(&item);
|
||||
}
|
||||
}
|
||||
|
||||
quote
|
||||
}
|
||||
};
|
||||
|
||||
print("ast_node", item.into())
|
||||
}
|
||||
226
third-party/vendor/ast_node/src/spanned.rs
vendored
Normal file
226
third-party/vendor/ast_node/src/spanned.rs
vendored
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use pmutil::{smart_quote, Quote, ToTokensExt};
|
||||
use swc_macros_common::prelude::*;
|
||||
use syn::{parse::Parse, *};
|
||||
|
||||
struct MyField {
|
||||
/// Name of the field.
|
||||
pub ident: Option<Ident>,
|
||||
/// Type of the field.
|
||||
pub ty: Type,
|
||||
|
||||
/// `#[span(lo)]`
|
||||
pub lo: bool,
|
||||
/// `#[span(hi)]`
|
||||
pub hi: bool,
|
||||
}
|
||||
|
||||
struct InputFieldAttr {
|
||||
kinds: Punctuated<Ident, Token![,]>,
|
||||
}
|
||||
|
||||
impl Parse for InputFieldAttr {
|
||||
fn parse(input: parse::ParseStream) -> Result<Self> {
|
||||
let kinds = input.call(Punctuated::parse_terminated)?;
|
||||
|
||||
Ok(Self { kinds })
|
||||
}
|
||||
}
|
||||
|
||||
impl MyField {
|
||||
fn from_field(f: &Field) -> Self {
|
||||
let mut lo = false;
|
||||
let mut hi = false;
|
||||
|
||||
for attr in &f.attrs {
|
||||
if !is_attr_name(attr, "span") {
|
||||
continue;
|
||||
}
|
||||
|
||||
match &attr.meta {
|
||||
Meta::Path(..) => {}
|
||||
Meta::List(list) => {
|
||||
let input = parse2::<InputFieldAttr>(list.tokens.clone())
|
||||
.expect("failed to parse as `InputFieldAttr`");
|
||||
|
||||
for kind in input.kinds {
|
||||
if kind == "lo" {
|
||||
lo = true
|
||||
} else if kind == "hi" {
|
||||
hi = true
|
||||
} else {
|
||||
panic!("Unknown span attribute: {:?}", kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Unknown span attribute"),
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
ident: f.ident.clone(),
|
||||
ty: f.ty.clone(),
|
||||
lo,
|
||||
hi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn derive(input: DeriveInput) -> ItemImpl {
|
||||
let arms = Binder::new_from(&input)
|
||||
.variants()
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
let (pat, bindings) = v.bind("_", Some(def_site()), None);
|
||||
|
||||
let body = make_body_for_variant(&v, bindings);
|
||||
|
||||
Arm {
|
||||
body,
|
||||
attrs: v
|
||||
.attrs()
|
||||
.iter()
|
||||
.filter(|attr| is_attr_name(attr, "cfg"))
|
||||
.cloned()
|
||||
.collect(),
|
||||
pat,
|
||||
guard: None,
|
||||
fat_arrow_token: def_site(),
|
||||
comma: Some(def_site()),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let body = Expr::Match(ExprMatch {
|
||||
attrs: Default::default(),
|
||||
match_token: def_site(),
|
||||
brace_token: def_site(),
|
||||
expr: Box::new(
|
||||
Quote::new(def_site::<Span>())
|
||||
.quote_with(smart_quote!(Vars {}, { self }))
|
||||
.parse(),
|
||||
),
|
||||
arms,
|
||||
});
|
||||
|
||||
Quote::new(def_site::<Span>())
|
||||
.quote_with(smart_quote!(
|
||||
Vars {
|
||||
Type: &input.ident,
|
||||
body,
|
||||
},
|
||||
{
|
||||
impl swc_common::Spanned for Type {
|
||||
#[inline]
|
||||
fn span(&self) -> swc_common::Span {
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
.parse::<ItemImpl>()
|
||||
.with_generics(input.generics)
|
||||
}
|
||||
|
||||
fn make_body_for_variant(v: &VariantBinder<'_>, bindings: Vec<BindedField<'_>>) -> Box<Expr> {
|
||||
/// `swc_common::Spanned::span(#field)`
|
||||
fn simple_field(field: &dyn ToTokens) -> Box<Expr> {
|
||||
Box::new(
|
||||
Quote::new(def_site::<Span>())
|
||||
.quote_with(smart_quote!(Vars { field }, {
|
||||
swc_common::Spanned::span(field)
|
||||
}))
|
||||
.parse(),
|
||||
)
|
||||
}
|
||||
|
||||
if bindings.is_empty() {
|
||||
panic!("#[derive(Spanned)] requires a field to get span from")
|
||||
}
|
||||
|
||||
if bindings.len() == 1 {
|
||||
if let Fields::Unnamed(..) = *v.data() {
|
||||
// Call self.0.span()
|
||||
return simple_field(&bindings[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle #[span] attribute.
|
||||
if let Some(f) = bindings
|
||||
.iter()
|
||||
.find(|b| has_empty_span_attr(&b.field().attrs))
|
||||
{
|
||||
//TODO: Verify that there's no more #[span]
|
||||
return simple_field(f);
|
||||
}
|
||||
|
||||
// If all fields do not have `#[span(..)]`, check for field named `span`.
|
||||
let has_any_span_attr = bindings
|
||||
.iter()
|
||||
.map(|b| {
|
||||
b.field()
|
||||
.attrs
|
||||
.iter()
|
||||
.any(|attr| is_attr_name(attr, "span"))
|
||||
})
|
||||
.any(|b| b);
|
||||
if !has_any_span_attr {
|
||||
let span_field = bindings
|
||||
.iter()
|
||||
.find(|b| {
|
||||
b.field()
|
||||
.ident
|
||||
.as_ref()
|
||||
.map(|ident| ident == "span")
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"#[derive(Spanned)]: cannot determine span field to use for {}",
|
||||
v.qual_path().dump()
|
||||
)
|
||||
});
|
||||
|
||||
return simple_field(span_field);
|
||||
}
|
||||
|
||||
let fields: Vec<_> = bindings
|
||||
.iter()
|
||||
.map(|b| (b, MyField::from_field(b.field())))
|
||||
.collect();
|
||||
|
||||
// TODO: Only one field should be `#[span(lo)]`.
|
||||
let lo = fields.iter().find(|&(_, f)| f.lo);
|
||||
let hi = fields.iter().find(|&(_, f)| f.hi);
|
||||
|
||||
match (lo, hi) {
|
||||
(Some((lo_field, _)), Some((hi_field, _))) => {
|
||||
// Create a new span from lo_field.lo(), hi_field.hi()
|
||||
Box::new(
|
||||
Quote::new(def_site::<Span>())
|
||||
.quote_with(smart_quote!(Vars { lo_field, hi_field }, {
|
||||
swc_common::Spanned::span(lo_field)
|
||||
.with_hi(swc_common::Spanned::span(hi_field).hi())
|
||||
}))
|
||||
.parse(),
|
||||
)
|
||||
}
|
||||
_ => panic!("#[derive(Spanned)]: #[span(lo)] and #[span(hi)] is required"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Search for `#[span]`
|
||||
fn has_empty_span_attr(attrs: &[Attribute]) -> bool {
|
||||
attrs.iter().any(|attr| {
|
||||
if !is_attr_name(attr, "span") {
|
||||
return false;
|
||||
}
|
||||
|
||||
match &attr.meta {
|
||||
Meta::Path(..) => true,
|
||||
Meta::List(t) => t.tokens.is_empty(),
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue