mirror of
https://github.com/swc-project/swc.git
synced 2024-11-21 21:41:48 +03:00
perf(visit): Add linear AST traversal (#9452)
**Description:** Babel decorator pass uses `fastTraverse`, and I think we can have one. **Related issue:** - Closes https://github.com/swc-project/swc/issues/9451
This commit is contained in:
parent
6187fcb134
commit
911d4eaa14
9
.changeset/olive-pianos-lay.md
Normal file
9
.changeset/olive-pianos-lay.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
swc_css_visit: patch
|
||||
swc_ecma_visit: patch
|
||||
swc_html_visit: patch
|
||||
swc_xml_visit: patch
|
||||
swc_core: patch
|
||||
---
|
||||
|
||||
perf(visit): Add linear AST traversal
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -11092,7 +11092,6 @@ pub mod fields {
|
||||
#[doc = "Represents [`TokenAndSpan::token`]"]
|
||||
Token,
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum AstParentKind {
|
||||
Attribute(AttributeField),
|
||||
@ -11131,7 +11130,6 @@ pub mod fields {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AstParentNodeRef<'ast> {
|
||||
Attribute(&'ast Attribute, AttributeField),
|
||||
@ -11176,6 +11174,7 @@ pub mod fields {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
impl<'ast> AstParentNodeRef<'ast> {
|
||||
#[inline]
|
||||
pub fn kind(&self) -> AstParentKind {
|
||||
@ -11202,5 +11201,185 @@ pub mod fields {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Attribute> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Attribute) -> Self {
|
||||
NodeRef::Attribute(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast AttributeToken> for NodeRef<'ast> {
|
||||
fn from(node: &'ast AttributeToken) -> Self {
|
||||
NodeRef::AttributeToken(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Child> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Child) -> Self {
|
||||
NodeRef::Child(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Comment> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Comment) -> Self {
|
||||
NodeRef::Comment(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Document> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Document) -> Self {
|
||||
NodeRef::Document(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast DocumentFragment> for NodeRef<'ast> {
|
||||
fn from(node: &'ast DocumentFragment) -> Self {
|
||||
NodeRef::DocumentFragment(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast DocumentMode> for NodeRef<'ast> {
|
||||
fn from(node: &'ast DocumentMode) -> Self {
|
||||
NodeRef::DocumentMode(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast DocumentType> for NodeRef<'ast> {
|
||||
fn from(node: &'ast DocumentType) -> Self {
|
||||
NodeRef::DocumentType(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Element> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Element) -> Self {
|
||||
NodeRef::Element(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Namespace> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Namespace) -> Self {
|
||||
NodeRef::Namespace(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Raw> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Raw) -> Self {
|
||||
NodeRef::Raw(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Text> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Text) -> Self {
|
||||
NodeRef::Text(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Token> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Token) -> Self {
|
||||
NodeRef::Token(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast TokenAndSpan> for NodeRef<'ast> {
|
||||
fn from(node: &'ast TokenAndSpan) -> Self {
|
||||
NodeRef::TokenAndSpan(node)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum NodeRef<'ast> {
|
||||
Attribute(&'ast Attribute),
|
||||
AttributeToken(&'ast AttributeToken),
|
||||
Child(&'ast Child),
|
||||
Comment(&'ast Comment),
|
||||
Document(&'ast Document),
|
||||
DocumentFragment(&'ast DocumentFragment),
|
||||
DocumentMode(&'ast DocumentMode),
|
||||
DocumentType(&'ast DocumentType),
|
||||
Element(&'ast Element),
|
||||
Namespace(&'ast Namespace),
|
||||
Raw(&'ast Raw),
|
||||
Text(&'ast Text),
|
||||
Token(&'ast Token),
|
||||
TokenAndSpan(&'ast TokenAndSpan),
|
||||
}
|
||||
impl<'ast> NodeRef<'ast> {
|
||||
#[allow(unreachable_patterns)]
|
||||
pub fn raw_children(&'ast self) -> Box<dyn 'ast + Iterator<Item = NodeRef<'ast>>> {
|
||||
match self {
|
||||
NodeRef::Attribute(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>().chain(
|
||||
node.namespace
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Namespace(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::AttributeToken(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Child(node) => match node {
|
||||
Child::DocumentType(v0) => Box::new(::std::iter::once(NodeRef::DocumentType(v0))),
|
||||
Child::Element(v0) => Box::new(::std::iter::once(NodeRef::Element(v0))),
|
||||
Child::Text(v0) => Box::new(::std::iter::once(NodeRef::Text(v0))),
|
||||
Child::Comment(v0) => Box::new(::std::iter::once(NodeRef::Comment(v0))),
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::Comment(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Document(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>()
|
||||
.chain(::std::iter::once(NodeRef::DocumentMode(&node.mode)))
|
||||
.chain(
|
||||
node.children
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Child(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::DocumentFragment(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>().chain(
|
||||
node.children
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Child(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::DocumentMode(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::DocumentType(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Element(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>()
|
||||
.chain(::std::iter::once(NodeRef::Namespace(&node.namespace)))
|
||||
.chain(
|
||||
node.attributes
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Attribute(&item))),
|
||||
)
|
||||
.chain(
|
||||
node.children
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Child(&item))),
|
||||
)
|
||||
.chain(
|
||||
node.content
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::DocumentFragment(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Namespace(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::Raw(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::Text(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Token(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::TokenAndSpan(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>()
|
||||
.chain(::std::iter::once(NodeRef::Token(&node.token)));
|
||||
Box::new(iterator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
pub use self::fields::{AstParentKind, AstParentNodeRef};
|
||||
|
@ -10660,7 +10660,6 @@ pub mod fields {
|
||||
#[doc = "Represents [`TokenAndSpan::token`]"]
|
||||
Token,
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum AstParentKind {
|
||||
Attribute(AttributeField),
|
||||
@ -10699,7 +10698,6 @@ pub mod fields {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AstParentNodeRef<'ast> {
|
||||
Attribute(&'ast Attribute, AttributeField),
|
||||
@ -10744,6 +10742,7 @@ pub mod fields {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
impl<'ast> AstParentNodeRef<'ast> {
|
||||
#[inline]
|
||||
pub fn kind(&self) -> AstParentKind {
|
||||
@ -10770,5 +10769,178 @@ pub mod fields {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Attribute> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Attribute) -> Self {
|
||||
NodeRef::Attribute(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast AttributeToken> for NodeRef<'ast> {
|
||||
fn from(node: &'ast AttributeToken) -> Self {
|
||||
NodeRef::AttributeToken(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast CdataSection> for NodeRef<'ast> {
|
||||
fn from(node: &'ast CdataSection) -> Self {
|
||||
NodeRef::CdataSection(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Child> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Child) -> Self {
|
||||
NodeRef::Child(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Comment> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Comment) -> Self {
|
||||
NodeRef::Comment(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Document> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Document) -> Self {
|
||||
NodeRef::Document(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast DocumentMode> for NodeRef<'ast> {
|
||||
fn from(node: &'ast DocumentMode) -> Self {
|
||||
NodeRef::DocumentMode(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast DocumentType> for NodeRef<'ast> {
|
||||
fn from(node: &'ast DocumentType) -> Self {
|
||||
NodeRef::DocumentType(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Element> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Element) -> Self {
|
||||
NodeRef::Element(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Namespace> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Namespace) -> Self {
|
||||
NodeRef::Namespace(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast ProcessingInstruction> for NodeRef<'ast> {
|
||||
fn from(node: &'ast ProcessingInstruction) -> Self {
|
||||
NodeRef::ProcessingInstruction(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Text> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Text) -> Self {
|
||||
NodeRef::Text(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast Token> for NodeRef<'ast> {
|
||||
fn from(node: &'ast Token) -> Self {
|
||||
NodeRef::Token(node)
|
||||
}
|
||||
}
|
||||
impl<'ast> From<&'ast TokenAndSpan> for NodeRef<'ast> {
|
||||
fn from(node: &'ast TokenAndSpan) -> Self {
|
||||
NodeRef::TokenAndSpan(node)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum NodeRef<'ast> {
|
||||
Attribute(&'ast Attribute),
|
||||
AttributeToken(&'ast AttributeToken),
|
||||
CdataSection(&'ast CdataSection),
|
||||
Child(&'ast Child),
|
||||
Comment(&'ast Comment),
|
||||
Document(&'ast Document),
|
||||
DocumentMode(&'ast DocumentMode),
|
||||
DocumentType(&'ast DocumentType),
|
||||
Element(&'ast Element),
|
||||
Namespace(&'ast Namespace),
|
||||
ProcessingInstruction(&'ast ProcessingInstruction),
|
||||
Text(&'ast Text),
|
||||
Token(&'ast Token),
|
||||
TokenAndSpan(&'ast TokenAndSpan),
|
||||
}
|
||||
impl<'ast> NodeRef<'ast> {
|
||||
#[allow(unreachable_patterns)]
|
||||
pub fn raw_children(&'ast self) -> Box<dyn 'ast + Iterator<Item = NodeRef<'ast>>> {
|
||||
match self {
|
||||
NodeRef::Attribute(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>().chain(
|
||||
node.namespace
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Namespace(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::AttributeToken(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::CdataSection(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Child(node) => match node {
|
||||
Child::DocumentType(v0) => Box::new(::std::iter::once(NodeRef::DocumentType(v0))),
|
||||
Child::Element(v0) => Box::new(::std::iter::once(NodeRef::Element(v0))),
|
||||
Child::Text(v0) => Box::new(::std::iter::once(NodeRef::Text(v0))),
|
||||
Child::CdataSection(v0) => Box::new(::std::iter::once(NodeRef::CdataSection(v0))),
|
||||
Child::Comment(v0) => Box::new(::std::iter::once(NodeRef::Comment(v0))),
|
||||
Child::ProcessingInstruction(v0) => {
|
||||
Box::new(::std::iter::once(NodeRef::ProcessingInstruction(v0)))
|
||||
}
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::Comment(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Document(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>().chain(
|
||||
node.children
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Child(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::DocumentMode(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::DocumentType(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Element(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>()
|
||||
.chain(
|
||||
node.attributes
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Attribute(&item))),
|
||||
)
|
||||
.chain(
|
||||
node.children
|
||||
.iter()
|
||||
.flat_map(|item| ::std::iter::once(NodeRef::Child(&item))),
|
||||
);
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Namespace(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::ProcessingInstruction(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Text(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>();
|
||||
Box::new(iterator)
|
||||
}
|
||||
NodeRef::Token(node) => match node {
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>()),
|
||||
},
|
||||
NodeRef::TokenAndSpan(node) => {
|
||||
let iterator = ::std::iter::empty::<NodeRef<'ast>>()
|
||||
.chain(::std::iter::once(NodeRef::Token(&node.token)));
|
||||
Box::new(iterator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
pub use self::fields::{AstParentKind, AstParentNodeRef};
|
||||
|
@ -1261,14 +1261,71 @@ fn extract_generic<'a>(name: &str, ty: &'a Type) -> Option<&'a Type> {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn to_iter(e: TokenStream, ty: &Type, node_names: &[Ident]) -> Option<Expr> {
|
||||
if let Some(ty) = extract_vec(ty) {
|
||||
let inner_expr = to_iter(quote!(item), ty, node_names)?;
|
||||
return Some(parse_quote!(#e.iter().flat_map(|item| #inner_expr)));
|
||||
}
|
||||
|
||||
if let Some(ty) = extract_generic("Option", ty) {
|
||||
let inner_expr = to_iter(quote!(item), ty, node_names)?;
|
||||
return Some(parse_quote!(#e.iter().flat_map(|item| #inner_expr)));
|
||||
}
|
||||
|
||||
if let Some(ty) = extract_generic("Box", ty) {
|
||||
let inner_expr = to_iter(quote!(item), ty, node_names)?;
|
||||
return Some(parse_quote!({
|
||||
let item = &*#e;
|
||||
#inner_expr
|
||||
}));
|
||||
}
|
||||
|
||||
if let Type::Path(p) = ty {
|
||||
let ty = &p.path.segments.last().unwrap().ident;
|
||||
|
||||
if node_names.contains(ty) {
|
||||
return Some(parse_quote!(::std::iter::once(NodeRef::#ty(&#e))));
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
todo!("to_iter for {:?}", ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
let mut items = Vec::<Item>::new();
|
||||
let mut kind_enum_members = Vec::new();
|
||||
let mut parent_enum_members = Vec::new();
|
||||
let mut node_ref_enum_members = Vec::new();
|
||||
|
||||
let mut kind_set_index_arms = Vec::<Arm>::new();
|
||||
let mut node_ref_set_index_arms = Vec::<Arm>::new();
|
||||
let mut node_ref_kind_arms = Vec::<Arm>::new();
|
||||
let mut node_ref_iter_next_arms = Vec::<Arm>::new();
|
||||
|
||||
let node_names = node_types
|
||||
.iter()
|
||||
.filter_map(|ty| match ty {
|
||||
Item::Enum(data) => Some(data.ident.clone()),
|
||||
Item::Struct(data) => Some(data.ident.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let is_node_ref_raw = |ty: &Type| match ty {
|
||||
Type::Path(p) => node_names.contains(&p.path.segments.last().unwrap().ident),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let is_node_ref = |ty: &Type| {
|
||||
if let Some(ty) = extract_generic("Box", ty) {
|
||||
return is_node_ref_raw(ty);
|
||||
}
|
||||
|
||||
is_node_ref_raw(ty)
|
||||
};
|
||||
|
||||
{
|
||||
let mut defs = Vec::<Item>::new();
|
||||
@ -1330,10 +1387,58 @@ fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
#type_name(#fields_enum_name)
|
||||
));
|
||||
|
||||
node_ref_enum_members.push(quote!(
|
||||
parent_enum_members.push(quote!(
|
||||
#type_name(&'ast #type_name, #fields_enum_name)
|
||||
));
|
||||
|
||||
node_ref_enum_members.push(quote!(
|
||||
#type_name(&'ast #type_name)
|
||||
));
|
||||
|
||||
items.push(parse_quote!(
|
||||
impl<'ast> From<&'ast #type_name> for NodeRef<'ast> {
|
||||
fn from(node: &'ast #type_name) -> Self {
|
||||
NodeRef::#type_name(node)
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
{
|
||||
let mut arms = Vec::<Arm>::new();
|
||||
|
||||
for variant in &data.variants {
|
||||
let variant_name = &variant.ident;
|
||||
|
||||
// TODO: Support all kinds of fields
|
||||
if variant.fields.len() != 1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
for f in variant.fields.iter().filter(|f| is_node_ref(&f.ty)) {
|
||||
let mut ty = &f.ty;
|
||||
if let Some(inner) = extract_generic("Box", ty) {
|
||||
ty = inner;
|
||||
}
|
||||
|
||||
arms.push(parse_quote!(
|
||||
#type_name::#variant_name(v0) => {
|
||||
Box::new(::std::iter::once(NodeRef::#ty(v0)))
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
node_ref_iter_next_arms.push(parse_quote!(
|
||||
NodeRef::#type_name(node) => {
|
||||
match node {
|
||||
#(#arms)*
|
||||
|
||||
_ => Box::new(::std::iter::empty::<NodeRef<'ast>>())
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
defs.push(parse_quote!(
|
||||
impl #fields_enum_name {
|
||||
#[inline(always)]
|
||||
@ -1361,10 +1466,51 @@ fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
#type_name(#fields_enum_name)
|
||||
));
|
||||
|
||||
node_ref_enum_members.push(quote!(
|
||||
parent_enum_members.push(quote!(
|
||||
#type_name(&'ast #type_name, #fields_enum_name)
|
||||
));
|
||||
|
||||
node_ref_enum_members.push(quote!(
|
||||
#type_name(&'ast #type_name)
|
||||
));
|
||||
|
||||
items.push(parse_quote!(
|
||||
impl<'ast> From<&'ast #type_name> for NodeRef<'ast> {
|
||||
fn from(node: &'ast #type_name) -> Self {
|
||||
NodeRef::#type_name(node)
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
{
|
||||
let mut iter: Expr = parse_quote!(::std::iter::empty::<NodeRef<'ast>>());
|
||||
|
||||
match &data.fields {
|
||||
Fields::Named(fields) => {
|
||||
for f in fields.named.iter() {
|
||||
let ident = &f.ident;
|
||||
let iter_expr =
|
||||
to_iter(quote!(node.#ident), &f.ty, &node_names);
|
||||
if let Some(iter_expr) = iter_expr {
|
||||
iter = parse_quote!(#iter.chain(#iter_expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fields::Unnamed(_fields) => {
|
||||
// TODO: Support unnamed fields
|
||||
}
|
||||
Fields::Unit => {}
|
||||
}
|
||||
|
||||
node_ref_iter_next_arms.push(parse_quote!(
|
||||
NodeRef::#type_name(node) => {
|
||||
let iterator = #iter;
|
||||
Box::new(iterator)
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
defs.push(parse_quote!(
|
||||
impl #fields_enum_name {
|
||||
pub(crate) fn set_index(&mut self, index: usize) {
|
||||
@ -1392,7 +1538,6 @@ fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
|
||||
{
|
||||
defs.push(parse_quote!(
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum AstParentKind {
|
||||
#(#kind_enum_members),*
|
||||
@ -1413,9 +1558,14 @@ fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
|
||||
{
|
||||
defs.push(parse_quote!(
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AstParentNodeRef<'ast> {
|
||||
#(#parent_enum_members),*
|
||||
}
|
||||
));
|
||||
items.push(parse_quote!(
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum NodeRef<'ast> {
|
||||
#(#node_ref_enum_members),*
|
||||
}
|
||||
));
|
||||
@ -1437,6 +1587,7 @@ fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
}
|
||||
));
|
||||
defs.push(parse_quote!(
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
impl<'ast> AstParentNodeRef<'ast> {
|
||||
#[inline]
|
||||
pub fn kind(&self) -> AstParentKind {
|
||||
@ -1446,14 +1597,27 @@ fn define_fields(crate_name: &Ident, node_types: &[&Item]) -> Vec<Item> {
|
||||
}
|
||||
}
|
||||
));
|
||||
items.push(parse_quote!(
|
||||
impl<'ast> NodeRef<'ast> {
|
||||
#[allow(unreachable_patterns)]
|
||||
pub fn raw_children(&'ast self) -> Box<dyn 'ast + Iterator<Item = NodeRef<'ast>>> {
|
||||
match self {
|
||||
#(#node_ref_iter_next_arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
items.push(parse_quote!(
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
pub mod fields {
|
||||
#(#defs)*
|
||||
}
|
||||
));
|
||||
items.insert(
|
||||
0,
|
||||
parse_quote!(
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
pub mod fields {
|
||||
#(#defs)*
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
items.push(parse_quote!(
|
||||
#[cfg(any(docsrs, feature = "path"))]
|
||||
|
Loading…
Reference in New Issue
Block a user