Flatten private codegen modules
diff --git a/codegen/src/fold.rs b/codegen/src/fold.rs
index adcde21..fabe598 100644
--- a/codegen/src/fold.rs
+++ b/codegen/src/fold.rs
@@ -1,280 +1,259 @@
use crate::{file, full, gen};
-use quote::quote;
+use inflections::Inflect;
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, TokenStreamExt};
+use syn::*;
use syn_codegen as types;
const FOLD_SRC: &str = "../src/gen/fold.rs";
-mod codegen {
- use crate::gen;
- use inflections::Inflect;
- use proc_macro2::{Span, TokenStream};
- use quote::{quote, TokenStreamExt};
- use syn::*;
- use syn_codegen as types;
+#[derive(Default)]
+struct State {
+ fold_trait: TokenStream,
+ fold_impl: TokenStream,
+}
- #[derive(Default)]
- pub struct State {
- pub fold_trait: TokenStream,
- pub fold_impl: TokenStream,
+fn under_name(name: &str) -> Ident {
+ Ident::new(&name.to_snake_case(), Span::call_site())
+}
+
+fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
+ let ident = under_name(item);
+
+ let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
+ quote! {
+ _visitor.#method(#name)
+ }
+}
+
+fn box_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ let res = visit(elem, features, defs, "e!(*#name))?;
+ Some(quote! {
+ Box::new(#res)
+ })
+}
+
+fn vec_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ let operand = quote!(it);
+ let val = visit(elem, features, defs, &operand)?;
+ Some(quote! {
+ FoldHelper::lift(#name, |it| { #val })
+ })
+}
+
+fn punctuated_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ let operand = quote!(it);
+ let val = visit(elem, features, defs, &operand)?;
+ Some(quote! {
+ FoldHelper::lift(#name, |it| { #val })
+ })
+}
+
+fn option_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ let it = quote!(it);
+ let val = visit(elem, features, defs, &it)?;
+ Some(quote! {
+ (#name).map(|it| { #val })
+ })
+}
+
+fn tuple_visit(
+ elems: &[types::Type],
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ if elems.is_empty() {
+ return None;
}
- fn under_name(name: &str) -> Ident {
- Ident::new(&name.to_snake_case(), Span::call_site())
+ let mut code = TokenStream::new();
+ for (i, elem) in elems.iter().enumerate() {
+ let i = Index::from(i);
+ let it = quote!((#name).#i);
+ let val = visit(elem, features, defs, &it).unwrap_or(it);
+ code.append_all(val);
+ code.append_all(quote!(,));
}
+ Some(quote! {
+ (#code)
+ })
+}
- fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
- let ident = under_name(item);
+fn token_punct_visit(repr: &str, name: &TokenStream) -> TokenStream {
+ let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
+ quote! {
+ #ty(tokens_helper(_visitor, &#name.spans))
+ }
+}
- let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
- quote! {
- _visitor.#method(#name)
+fn token_keyword_visit(repr: &str, name: &TokenStream) -> TokenStream {
+ let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
+ quote! {
+ #ty(tokens_helper(_visitor, &#name.span))
+ }
+}
+
+fn token_group_visit(ty: &str, name: &TokenStream) -> TokenStream {
+ let ty = Ident::new(ty, Span::call_site());
+ quote! {
+ #ty(tokens_helper(_visitor, &#name.span))
+ }
+}
+
+fn visit(
+ ty: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ match ty {
+ types::Type::Box(t) => box_visit(&*t, features, defs, name),
+ types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
+ types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
+ types::Type::Option(t) => option_visit(&*t, features, defs, name),
+ types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
+ types::Type::Token(t) => {
+ let repr = &defs.tokens[t];
+ let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+ if is_keyword {
+ Some(token_keyword_visit(repr, name))
+ } else {
+ Some(token_punct_visit(repr, name))
+ }
}
- }
+ types::Type::Group(t) => Some(token_group_visit(&t[..], name)),
+ types::Type::Syn(t) => {
+ fn requires_full(features: &types::Features) -> bool {
+ features.any.contains("full") && features.any.len() == 1
+ }
- fn box_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &TokenStream,
- ) -> Option<TokenStream> {
- let res = visit(elem, features, defs, "e!(*#name))?;
- Some(quote! {
- Box::new(#res)
- })
- }
+ let res = simple_visit(t, name);
- fn vec_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &TokenStream,
- ) -> Option<TokenStream> {
- let operand = quote!(it);
- let val = visit(elem, features, defs, &operand)?;
- Some(quote! {
- FoldHelper::lift(#name, |it| { #val })
- })
- }
+ let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
- fn punctuated_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &TokenStream,
- ) -> Option<TokenStream> {
- let operand = quote!(it);
- let val = visit(elem, features, defs, &operand)?;
- Some(quote! {
- FoldHelper::lift(#name, |it| { #val })
- })
- }
-
- fn option_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &TokenStream,
- ) -> Option<TokenStream> {
- let it = quote!(it);
- let val = visit(elem, features, defs, &it)?;
- Some(quote! {
- (#name).map(|it| { #val })
- })
- }
-
- fn tuple_visit(
- elems: &[types::Type],
- features: &types::Features,
- defs: &types::Definitions,
- name: &TokenStream,
- ) -> Option<TokenStream> {
- if elems.is_empty() {
- return None;
- }
-
- let mut code = TokenStream::new();
- for (i, elem) in elems.iter().enumerate() {
- let i = Index::from(i);
- let it = quote!((#name).#i);
- let val = visit(elem, features, defs, &it).unwrap_or(it);
- code.append_all(val);
- code.append_all(quote!(,));
- }
- Some(quote! {
- (#code)
- })
- }
-
- fn token_punct_visit(repr: &str, name: &TokenStream) -> TokenStream {
- let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
- quote! {
- #ty(tokens_helper(_visitor, &#name.spans))
- }
- }
-
- fn token_keyword_visit(repr: &str, name: &TokenStream) -> TokenStream {
- let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
- quote! {
- #ty(tokens_helper(_visitor, &#name.span))
- }
- }
-
- fn token_group_visit(ty: &str, name: &TokenStream) -> TokenStream {
- let ty = Ident::new(ty, Span::call_site());
- quote! {
- #ty(tokens_helper(_visitor, &#name.span))
- }
- }
-
- fn visit(
- ty: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &TokenStream,
- ) -> Option<TokenStream> {
- match ty {
- types::Type::Box(t) => box_visit(&*t, features, defs, name),
- types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
- types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
- types::Type::Option(t) => option_visit(&*t, features, defs, name),
- types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
- types::Type::Token(t) => {
- let repr = &defs.tokens[t];
- let is_keyword = repr.chars().next().unwrap().is_alphabetic();
- if is_keyword {
- Some(token_keyword_visit(repr, name))
+ Some(
+ if requires_full(&target.features) && !requires_full(features) {
+ quote! {
+ full!(#res)
+ }
} else {
- Some(token_punct_visit(repr, name))
- }
- }
- types::Type::Group(t) => Some(token_group_visit(&t[..], name)),
- types::Type::Syn(t) => {
- fn requires_full(features: &types::Features) -> bool {
- features.any.contains("full") && features.any.len() == 1
- }
-
- let res = simple_visit(t, name);
-
- let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
-
- Some(
- if requires_full(&target.features) && !requires_full(features) {
- quote! {
- full!(#res)
- }
- } else {
- res
- },
- )
- }
- types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => {
- Some(simple_visit(t, name))
- }
- types::Type::Ext(_) | types::Type::Std(_) => None,
+ res
+ },
+ )
}
+ types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+ types::Type::Ext(_) | types::Type::Std(_) => None,
}
+}
- fn visit_features(features: &types::Features) -> TokenStream {
- let features = &features.any;
- match features.len() {
- 0 => quote!(),
- 1 => quote!(#[cfg(feature = #(#features)*)]),
- _ => quote!(#[cfg(any(#(feature = #features),*))]),
- }
+fn visit_features(features: &types::Features) -> TokenStream {
+ let features = &features.any;
+ match features.len() {
+ 0 => quote!(),
+ 1 => quote!(#[cfg(feature = #(#features)*)]),
+ _ => quote!(#[cfg(any(#(feature = #features),*))]),
}
+}
- pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
- let features = visit_features(&s.features);
- let under_name = under_name(&s.ident);
- let ty = Ident::new(&s.ident, Span::call_site());
- let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
+fn node(state: &mut State, s: &types::Node, defs: &types::Definitions) {
+ let features = visit_features(&s.features);
+ let under_name = under_name(&s.ident);
+ let ty = Ident::new(&s.ident, Span::call_site());
+ let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
- let mut fold_impl = TokenStream::new();
+ let mut fold_impl = TokenStream::new();
- match &s.data {
- types::Data::Enum(variants) => {
- let mut fold_variants = TokenStream::new();
+ match &s.data {
+ types::Data::Enum(variants) => {
+ let mut fold_variants = TokenStream::new();
- for (variant, fields) in variants {
- let variant_ident = Ident::new(variant, Span::call_site());
+ for (variant, fields) in variants {
+ let variant_ident = Ident::new(variant, Span::call_site());
- if fields.is_empty() {
- fold_variants.append_all(quote! {
- #ty::#variant_ident => {
- #ty::#variant_ident
- }
- });
- } else {
- let mut bind_fold_fields = TokenStream::new();
- let mut fold_fields = TokenStream::new();
-
- for (idx, ty) in fields.iter().enumerate() {
- let name = format!("_binding_{}", idx);
- let binding = Ident::new(&name, Span::call_site());
-
- bind_fold_fields.append_all(quote! {
- #binding,
- });
-
- let owned_binding = quote!(#binding);
-
- fold_fields.append_all(
- visit(ty, &s.features, defs, &owned_binding)
- .unwrap_or(owned_binding),
- );
-
- fold_fields.append_all(quote!(,));
+ if fields.is_empty() {
+ fold_variants.append_all(quote! {
+ #ty::#variant_ident => {
+ #ty::#variant_ident
}
+ });
+ } else {
+ let mut bind_fold_fields = TokenStream::new();
+ let mut fold_fields = TokenStream::new();
- fold_variants.append_all(quote! {
- #ty::#variant_ident(#bind_fold_fields) => {
- #ty::#variant_ident(
- #fold_fields
- )
- }
+ for (idx, ty) in fields.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_fold_fields.append_all(quote! {
+ #binding,
});
- }
- }
- fold_impl.append_all(quote! {
- match _i {
- #fold_variants
+ let owned_binding = quote!(#binding);
+
+ fold_fields.append_all(
+ visit(ty, &s.features, defs, &owned_binding).unwrap_or(owned_binding),
+ );
+
+ fold_fields.append_all(quote!(,));
}
+
+ fold_variants.append_all(quote! {
+ #ty::#variant_ident(#bind_fold_fields) => {
+ #ty::#variant_ident(
+ #fold_fields
+ )
+ }
+ });
+ }
+ }
+
+ fold_impl.append_all(quote! {
+ match _i {
+ #fold_variants
+ }
+ });
+ }
+ types::Data::Struct(fields) => {
+ let mut fold_fields = TokenStream::new();
+
+ for (field, ty) in fields {
+ let id = Ident::new(&field, Span::call_site());
+ let ref_toks = quote!(_i.#id);
+ let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks);
+
+ fold_fields.append_all(quote! {
+ #id: #fold,
});
}
- types::Data::Struct(fields) => {
- let mut fold_fields = TokenStream::new();
- for (field, ty) in fields {
- let id = Ident::new(&field, Span::call_site());
- let ref_toks = quote!(_i.#id);
- let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks);
-
- fold_fields.append_all(quote! {
- #id: #fold,
- });
- }
-
- if !fields.is_empty() {
- fold_impl.append_all(quote! {
- #ty {
- #fold_fields
- }
- })
- } else {
- if ty == "Ident" {
- fold_impl.append_all(quote! {
- let mut _i = _i;
- let span = _visitor.fold_span(_i.span());
- _i.set_span(span);
- });
+ if !fields.is_empty() {
+ fold_impl.append_all(quote! {
+ #ty {
+ #fold_fields
}
- fold_impl.append_all(quote! {
- _i
- });
- }
- }
- types::Data::Private => {
+ })
+ } else {
if ty == "Ident" {
fold_impl.append_all(quote! {
let mut _i = _i;
@@ -287,34 +266,46 @@
});
}
}
-
- let include_fold_impl = match &s.data {
- types::Data::Private => gen::TERMINAL_TYPES.contains(&s.ident.as_str()),
- types::Data::Struct(_) | types::Data::Enum(_) => true,
- };
-
- state.fold_trait.append_all(quote! {
- #features
- fn #fold_fn(&mut self, i: #ty) -> #ty {
- #fold_fn(self, i)
+ types::Data::Private => {
+ if ty == "Ident" {
+ fold_impl.append_all(quote! {
+ let mut _i = _i;
+ let span = _visitor.fold_span(_i.span());
+ _i.set_span(span);
+ });
}
- });
-
- if include_fold_impl {
- state.fold_impl.append_all(quote! {
- #features
- pub fn #fold_fn<V: Fold + ?Sized>(
- _visitor: &mut V, _i: #ty
- ) -> #ty {
- #fold_impl
- }
+ fold_impl.append_all(quote! {
+ _i
});
}
}
+
+ let include_fold_impl = match &s.data {
+ types::Data::Private => gen::TERMINAL_TYPES.contains(&s.ident.as_str()),
+ types::Data::Struct(_) | types::Data::Enum(_) => true,
+ };
+
+ state.fold_trait.append_all(quote! {
+ #features
+ fn #fold_fn(&mut self, i: #ty) -> #ty {
+ #fold_fn(self, i)
+ }
+ });
+
+ if include_fold_impl {
+ state.fold_impl.append_all(quote! {
+ #features
+ pub fn #fold_fn<V: Fold + ?Sized>(
+ _visitor: &mut V, _i: #ty
+ ) -> #ty {
+ #fold_impl
+ }
+ });
+ }
}
pub fn generate(defs: &types::Definitions) {
- let state = gen::traverse(defs, codegen::generate);
+ let state = gen::traverse(defs, node);
let full_macro = full::get_macro();
let fold_trait = state.fold_trait;
let fold_impl = state.fold_impl;
diff --git a/codegen/src/gen.rs b/codegen/src/gen.rs
index c0bd4d1..30cee0d 100644
--- a/codegen/src/gen.rs
+++ b/codegen/src/gen.rs
@@ -2,14 +2,14 @@
pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
-pub fn traverse<S, F>(defs: &types::Definitions, generate: F) -> S
+pub fn traverse<S, F>(defs: &types::Definitions, node: F) -> S
where
S: Default,
F: Fn(&mut S, &types::Node, &types::Definitions),
{
let mut state = S::default();
for s in &defs.types {
- generate(&mut state, s, defs);
+ node(&mut state, s, defs);
}
for tt in TERMINAL_TYPES {
let s = types::Node {
@@ -17,7 +17,7 @@
features: types::Features::default(),
data: types::Data::Private,
};
- generate(&mut state, &s, defs);
+ node(&mut state, &s, defs);
}
state
}
diff --git a/codegen/src/visit.rs b/codegen/src/visit.rs
index 4679c9f..24c7f76 100644
--- a/codegen/src/visit.rs
+++ b/codegen/src/visit.rs
@@ -1,321 +1,313 @@
use crate::{file, full, gen};
-use quote::quote;
+use inflections::Inflect;
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, TokenStreamExt};
+use syn::*;
use syn_codegen as types;
const VISIT_SRC: &str = "../src/gen/visit.rs";
-mod codegen {
- use crate::gen;
- use inflections::Inflect;
- use proc_macro2::{Span, TokenStream};
- use quote::{quote, TokenStreamExt};
- use syn::*;
- use syn_codegen as types;
+#[derive(Default)]
+struct State {
+ visit_trait: TokenStream,
+ visit_impl: TokenStream,
+}
- #[derive(Default)]
- pub struct State {
- pub visit_trait: TokenStream,
- pub visit_impl: TokenStream,
- }
+fn under_name(name: &str) -> Ident {
+ Ident::new(&name.to_snake_case(), Span::call_site())
+}
- fn under_name(name: &str) -> Ident {
- Ident::new(&name.to_snake_case(), Span::call_site())
- }
+enum Operand {
+ Borrowed(TokenStream),
+ Owned(TokenStream),
+}
- enum Operand {
- Borrowed(TokenStream),
- Owned(TokenStream),
- }
+use self::Operand::*;
- use self::Operand::*;
-
- impl Operand {
- fn tokens(&self) -> &TokenStream {
- match *self {
- Borrowed(ref n) | Owned(ref n) => n,
- }
- }
-
- fn ref_tokens(&self) -> TokenStream {
- match *self {
- Borrowed(ref n) => n.clone(),
- Owned(ref n) => quote!(&#n),
- }
- }
-
- fn owned_tokens(&self) -> TokenStream {
- match *self {
- Borrowed(ref n) => quote!(*#n),
- Owned(ref n) => n.clone(),
- }
+impl Operand {
+ fn tokens(&self) -> &TokenStream {
+ match *self {
+ Borrowed(ref n) | Owned(ref n) => n,
}
}
- fn simple_visit(item: &str, name: &Operand) -> TokenStream {
- let ident = under_name(item);
- let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
- let name = name.ref_tokens();
- quote! {
- _visitor.#method(#name)
+ fn ref_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => n.clone(),
+ Owned(ref n) => quote!(&#n),
}
}
- fn box_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let name = name.owned_tokens();
- let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
- Some(res)
- }
-
- fn vec_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let operand = Borrowed(quote!(it));
- let val = visit(elem, features, defs, &operand)?;
- let name = name.ref_tokens();
- Some(quote! {
- for it in #name {
- #val
- }
- })
- }
-
- fn punctuated_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let operand = Borrowed(quote!(it));
- let val = visit(elem, features, defs, &operand)?;
- let name = name.ref_tokens();
- Some(quote! {
- for el in Punctuated::pairs(#name) {
- let it = el.value();
- #val
- }
- })
- }
-
- fn option_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let it = Borrowed(quote!(it));
- let val = visit(elem, features, defs, &it)?;
- let name = name.owned_tokens();
- Some(quote! {
- if let Some(ref it) = #name {
- #val
- }
- })
- }
-
- fn tuple_visit(
- elems: &[types::Type],
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- if elems.is_empty() {
- return None;
+ fn owned_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => quote!(*#n),
+ Owned(ref n) => n.clone(),
}
-
- let mut code = TokenStream::new();
- for (i, elem) in elems.iter().enumerate() {
- let name = name.tokens();
- let i = Index::from(i);
- let it = Owned(quote!((#name).#i));
- let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
- code.append_all(val);
- code.append_all(quote!(;));
- }
- Some(code)
- }
-
- fn token_punct_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- tokens_helper(_visitor, &#name.spans)
- }
- }
-
- fn token_keyword_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- tokens_helper(_visitor, &#name.span)
- }
- }
-
- fn token_group_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- tokens_helper(_visitor, &#name.span)
- }
- }
-
- fn noop_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- skip!(#name)
- }
- }
-
- fn visit(
- ty: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- match ty {
- types::Type::Box(t) => box_visit(&*t, features, defs, name),
- types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
- types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
- types::Type::Option(t) => option_visit(&*t, features, defs, name),
- types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
- types::Type::Token(t) => {
- let repr = &defs.tokens[t];
- let is_keyword = repr.chars().next().unwrap().is_alphabetic();
- if is_keyword {
- Some(token_keyword_visit(name))
- } else {
- Some(token_punct_visit(name))
- }
- }
- types::Type::Group(_) => Some(token_group_visit(name)),
- types::Type::Syn(t) => {
- fn requires_full(features: &types::Features) -> bool {
- features.any.contains("full") && features.any.len() == 1
- }
-
- let res = simple_visit(t, name);
-
- let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
-
- Some(
- if requires_full(&target.features) && !requires_full(features) {
- quote! {
- full!(#res)
- }
- } else {
- res
- },
- )
- }
- types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => {
- Some(simple_visit(t, name))
- }
- types::Type::Ext(_) | types::Type::Std(_) => None,
- }
- }
-
- fn visit_features(features: &types::Features) -> TokenStream {
- let features = &features.any;
- match features.len() {
- 0 => quote!(),
- 1 => quote!(#[cfg(feature = #(#features)*)]),
- _ => quote!(#[cfg(any(#(feature = #features),*))]),
- }
- }
-
- pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
- let features = visit_features(&s.features);
- let under_name = under_name(&s.ident);
- let ty = Ident::new(&s.ident, Span::call_site());
- let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
-
- let mut visit_impl = TokenStream::new();
-
- match &s.data {
- types::Data::Enum(variants) => {
- let mut visit_variants = TokenStream::new();
-
- for (variant, fields) in variants {
- let variant_ident = Ident::new(variant, Span::call_site());
-
- if fields.is_empty() {
- visit_variants.append_all(quote! {
- #ty::#variant_ident => {}
- });
- } else {
- let mut bind_visit_fields = TokenStream::new();
- let mut visit_fields = TokenStream::new();
-
- for (idx, ty) in fields.iter().enumerate() {
- let name = format!("_binding_{}", idx);
- let binding = Ident::new(&name, Span::call_site());
-
- bind_visit_fields.append_all(quote! {
- ref #binding,
- });
-
- let borrowed_binding = Borrowed(quote!(#binding));
-
- visit_fields.append_all(
- visit(ty, &s.features, defs, &borrowed_binding)
- .unwrap_or_else(|| noop_visit(&borrowed_binding)),
- );
-
- visit_fields.append_all(quote!(;));
- }
-
- visit_variants.append_all(quote! {
- #ty::#variant_ident(#bind_visit_fields) => {
- #visit_fields
- }
- });
- }
- }
-
- visit_impl.append_all(quote! {
- match *_i {
- #visit_variants
- }
- });
- }
- types::Data::Struct(fields) => {
- for (field, ty) in fields {
- let id = Ident::new(&field, Span::call_site());
- let ref_toks = Owned(quote!(_i.#id));
- let visit_field = visit(&ty, &s.features, defs, &ref_toks)
- .unwrap_or_else(|| noop_visit(&ref_toks));
- visit_impl.append_all(quote! {
- #visit_field;
- });
- }
- }
- types::Data::Private => {}
- }
-
- state.visit_trait.append_all(quote! {
- #features
- fn #visit_fn(&mut self, i: &'ast #ty) {
- #visit_fn(self, i)
- }
- });
-
- state.visit_impl.append_all(quote! {
- #features
- pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
- _visitor: &mut V, _i: &'ast #ty
- ) {
- #visit_impl
- }
- });
}
}
+fn simple_visit(item: &str, name: &Operand) -> TokenStream {
+ let ident = under_name(item);
+ let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
+ let name = name.ref_tokens();
+ quote! {
+ _visitor.#method(#name)
+ }
+}
+
+fn box_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let name = name.owned_tokens();
+ let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
+ Some(res)
+}
+
+fn vec_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let operand = Borrowed(quote!(it));
+ let val = visit(elem, features, defs, &operand)?;
+ let name = name.ref_tokens();
+ Some(quote! {
+ for it in #name {
+ #val
+ }
+ })
+}
+
+fn punctuated_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let operand = Borrowed(quote!(it));
+ let val = visit(elem, features, defs, &operand)?;
+ let name = name.ref_tokens();
+ Some(quote! {
+ for el in Punctuated::pairs(#name) {
+ let it = el.value();
+ #val
+ }
+ })
+}
+
+fn option_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let it = Borrowed(quote!(it));
+ let val = visit(elem, features, defs, &it)?;
+ let name = name.owned_tokens();
+ Some(quote! {
+ if let Some(ref it) = #name {
+ #val
+ }
+ })
+}
+
+fn tuple_visit(
+ elems: &[types::Type],
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ if elems.is_empty() {
+ return None;
+ }
+
+ let mut code = TokenStream::new();
+ for (i, elem) in elems.iter().enumerate() {
+ let name = name.tokens();
+ let i = Index::from(i);
+ let it = Owned(quote!((#name).#i));
+ let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
+ code.append_all(val);
+ code.append_all(quote!(;));
+ }
+ Some(code)
+}
+
+fn token_punct_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ tokens_helper(_visitor, &#name.spans)
+ }
+}
+
+fn token_keyword_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ tokens_helper(_visitor, &#name.span)
+ }
+}
+
+fn token_group_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ tokens_helper(_visitor, &#name.span)
+ }
+}
+
+fn noop_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ skip!(#name)
+ }
+}
+
+fn visit(
+ ty: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ match ty {
+ types::Type::Box(t) => box_visit(&*t, features, defs, name),
+ types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
+ types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
+ types::Type::Option(t) => option_visit(&*t, features, defs, name),
+ types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
+ types::Type::Token(t) => {
+ let repr = &defs.tokens[t];
+ let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+ if is_keyword {
+ Some(token_keyword_visit(name))
+ } else {
+ Some(token_punct_visit(name))
+ }
+ }
+ types::Type::Group(_) => Some(token_group_visit(name)),
+ types::Type::Syn(t) => {
+ fn requires_full(features: &types::Features) -> bool {
+ features.any.contains("full") && features.any.len() == 1
+ }
+
+ let res = simple_visit(t, name);
+
+ let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+
+ Some(
+ if requires_full(&target.features) && !requires_full(features) {
+ quote! {
+ full!(#res)
+ }
+ } else {
+ res
+ },
+ )
+ }
+ types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+ types::Type::Ext(_) | types::Type::Std(_) => None,
+ }
+}
+
+fn visit_features(features: &types::Features) -> TokenStream {
+ let features = &features.any;
+ match features.len() {
+ 0 => quote!(),
+ 1 => quote!(#[cfg(feature = #(#features)*)]),
+ _ => quote!(#[cfg(any(#(feature = #features),*))]),
+ }
+}
+
+fn node(state: &mut State, s: &types::Node, defs: &types::Definitions) {
+ let features = visit_features(&s.features);
+ let under_name = under_name(&s.ident);
+ let ty = Ident::new(&s.ident, Span::call_site());
+ let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
+
+ let mut visit_impl = TokenStream::new();
+
+ match &s.data {
+ types::Data::Enum(variants) => {
+ let mut visit_variants = TokenStream::new();
+
+ for (variant, fields) in variants {
+ let variant_ident = Ident::new(variant, Span::call_site());
+
+ if fields.is_empty() {
+ visit_variants.append_all(quote! {
+ #ty::#variant_ident => {}
+ });
+ } else {
+ let mut bind_visit_fields = TokenStream::new();
+ let mut visit_fields = TokenStream::new();
+
+ for (idx, ty) in fields.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_visit_fields.append_all(quote! {
+ ref #binding,
+ });
+
+ let borrowed_binding = Borrowed(quote!(#binding));
+
+ visit_fields.append_all(
+ visit(ty, &s.features, defs, &borrowed_binding)
+ .unwrap_or_else(|| noop_visit(&borrowed_binding)),
+ );
+
+ visit_fields.append_all(quote!(;));
+ }
+
+ visit_variants.append_all(quote! {
+ #ty::#variant_ident(#bind_visit_fields) => {
+ #visit_fields
+ }
+ });
+ }
+ }
+
+ visit_impl.append_all(quote! {
+ match *_i {
+ #visit_variants
+ }
+ });
+ }
+ types::Data::Struct(fields) => {
+ for (field, ty) in fields {
+ let id = Ident::new(&field, Span::call_site());
+ let ref_toks = Owned(quote!(_i.#id));
+ let visit_field = visit(&ty, &s.features, defs, &ref_toks)
+ .unwrap_or_else(|| noop_visit(&ref_toks));
+ visit_impl.append_all(quote! {
+ #visit_field;
+ });
+ }
+ }
+ types::Data::Private => {}
+ }
+
+ state.visit_trait.append_all(quote! {
+ #features
+ fn #visit_fn(&mut self, i: &'ast #ty) {
+ #visit_fn(self, i)
+ }
+ });
+
+ state.visit_impl.append_all(quote! {
+ #features
+ pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V, _i: &'ast #ty
+ ) {
+ #visit_impl
+ }
+ });
+}
+
pub fn generate(defs: &types::Definitions) {
- let state = gen::traverse(defs, codegen::generate);
+ let state = gen::traverse(defs, node);
let full_macro = full::get_macro();
let visit_trait = state.visit_trait;
let visit_impl = state.visit_impl;
diff --git a/codegen/src/visit_mut.rs b/codegen/src/visit_mut.rs
index f32d1c9..3388665 100644
--- a/codegen/src/visit_mut.rs
+++ b/codegen/src/visit_mut.rs
@@ -1,321 +1,313 @@
use crate::{file, full, gen};
-use quote::quote;
+use inflections::Inflect;
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, TokenStreamExt};
+use syn::*;
use syn_codegen as types;
const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
-mod codegen {
- use crate::gen;
- use inflections::Inflect;
- use proc_macro2::{Span, TokenStream};
- use quote::{quote, TokenStreamExt};
- use syn::*;
- use syn_codegen as types;
+#[derive(Default)]
+struct State {
+ visit_mut_trait: TokenStream,
+ visit_mut_impl: TokenStream,
+}
- #[derive(Default)]
- pub struct State {
- pub visit_mut_trait: TokenStream,
- pub visit_mut_impl: TokenStream,
- }
+fn under_name(name: &str) -> Ident {
+ Ident::new(&name.to_snake_case(), Span::call_site())
+}
- fn under_name(name: &str) -> Ident {
- Ident::new(&name.to_snake_case(), Span::call_site())
- }
+enum Operand {
+ Borrowed(TokenStream),
+ Owned(TokenStream),
+}
- enum Operand {
- Borrowed(TokenStream),
- Owned(TokenStream),
- }
+use self::Operand::*;
- use self::Operand::*;
-
- impl Operand {
- fn tokens(&self) -> &TokenStream {
- match *self {
- Borrowed(ref n) | Owned(ref n) => n,
- }
- }
-
- fn ref_mut_tokens(&self) -> TokenStream {
- match *self {
- Borrowed(ref n) => n.clone(),
- Owned(ref n) => quote!(&mut #n),
- }
- }
-
- fn owned_tokens(&self) -> TokenStream {
- match *self {
- Borrowed(ref n) => quote!(*#n),
- Owned(ref n) => n.clone(),
- }
+impl Operand {
+ fn tokens(&self) -> &TokenStream {
+ match *self {
+ Borrowed(ref n) | Owned(ref n) => n,
}
}
- fn simple_visit(item: &str, name: &Operand) -> TokenStream {
- let ident = under_name(item);
- let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
- let name = name.ref_mut_tokens();
- quote! {
- _visitor.#method(#name)
+ fn ref_mut_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => n.clone(),
+ Owned(ref n) => quote!(&mut #n),
}
}
- fn box_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let name = name.owned_tokens();
- let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
- Some(res)
- }
-
- fn vec_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let operand = Borrowed(quote!(it));
- let val = visit(elem, features, defs, &operand)?;
- let name = name.ref_mut_tokens();
- Some(quote! {
- for it in #name {
- #val
- }
- })
- }
-
- fn punctuated_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let operand = Borrowed(quote!(it));
- let val = visit(elem, features, defs, &operand)?;
- let name = name.ref_mut_tokens();
- Some(quote! {
- for mut el in Punctuated::pairs_mut(#name) {
- let it = el.value_mut();
- #val
- }
- })
- }
-
- fn option_visit(
- elem: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- let it = Borrowed(quote!(it));
- let val = visit(elem, features, defs, &it)?;
- let name = name.owned_tokens();
- Some(quote! {
- if let Some(ref mut it) = #name {
- #val
- }
- })
- }
-
- fn tuple_visit(
- elems: &[types::Type],
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- if elems.is_empty() {
- return None;
+ fn owned_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => quote!(*#n),
+ Owned(ref n) => n.clone(),
}
-
- let mut code = TokenStream::new();
- for (i, elem) in elems.iter().enumerate() {
- let name = name.tokens();
- let i = Index::from(i);
- let it = Owned(quote!((#name).#i));
- let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
- code.append_all(val);
- code.append_all(quote!(;));
- }
- Some(code)
- }
-
- fn token_punct_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- tokens_helper(_visitor, &mut #name.spans)
- }
- }
-
- fn token_keyword_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- tokens_helper(_visitor, &mut #name.span)
- }
- }
-
- fn token_group_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- tokens_helper(_visitor, &mut #name.span)
- }
- }
-
- fn noop_visit(name: &Operand) -> TokenStream {
- let name = name.tokens();
- quote! {
- skip!(#name)
- }
- }
-
- fn visit(
- ty: &types::Type,
- features: &types::Features,
- defs: &types::Definitions,
- name: &Operand,
- ) -> Option<TokenStream> {
- match ty {
- types::Type::Box(t) => box_visit(&*t, features, defs, name),
- types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
- types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
- types::Type::Option(t) => option_visit(&*t, features, defs, name),
- types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
- types::Type::Token(t) => {
- let repr = &defs.tokens[t];
- let is_keyword = repr.chars().next().unwrap().is_alphabetic();
- if is_keyword {
- Some(token_keyword_visit(name))
- } else {
- Some(token_punct_visit(name))
- }
- }
- types::Type::Group(_) => Some(token_group_visit(name)),
- types::Type::Syn(t) => {
- fn requires_full(features: &types::Features) -> bool {
- features.any.contains("full") && features.any.len() == 1
- }
-
- let res = simple_visit(t, name);
-
- let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
-
- Some(
- if requires_full(&target.features) && !requires_full(features) {
- quote! {
- full!(#res)
- }
- } else {
- res
- },
- )
- }
- types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => {
- Some(simple_visit(t, name))
- }
- types::Type::Ext(_) | types::Type::Std(_) => None,
- }
- }
-
- fn visit_features(features: &types::Features) -> TokenStream {
- let features = &features.any;
- match features.len() {
- 0 => quote!(),
- 1 => quote!(#[cfg(feature = #(#features)*)]),
- _ => quote!(#[cfg(any(#(feature = #features),*))]),
- }
- }
-
- pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
- let features = visit_features(&s.features);
- let under_name = under_name(&s.ident);
- let ty = Ident::new(&s.ident, Span::call_site());
- let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
-
- let mut visit_mut_impl = TokenStream::new();
-
- match &s.data {
- types::Data::Enum(variants) => {
- let mut visit_mut_variants = TokenStream::new();
-
- for (variant, fields) in variants {
- let variant_ident = Ident::new(variant, Span::call_site());
-
- if fields.is_empty() {
- visit_mut_variants.append_all(quote! {
- #ty::#variant_ident => {}
- });
- } else {
- let mut bind_visit_mut_fields = TokenStream::new();
- let mut visit_mut_fields = TokenStream::new();
-
- for (idx, ty) in fields.iter().enumerate() {
- let name = format!("_binding_{}", idx);
- let binding = Ident::new(&name, Span::call_site());
-
- bind_visit_mut_fields.append_all(quote! {
- ref mut #binding,
- });
-
- let borrowed_binding = Borrowed(quote!(#binding));
-
- visit_mut_fields.append_all(
- visit(ty, &s.features, defs, &borrowed_binding)
- .unwrap_or_else(|| noop_visit(&borrowed_binding)),
- );
-
- visit_mut_fields.append_all(quote!(;));
- }
-
- visit_mut_variants.append_all(quote! {
- #ty::#variant_ident(#bind_visit_mut_fields) => {
- #visit_mut_fields
- }
- });
- }
- }
-
- visit_mut_impl.append_all(quote! {
- match *_i {
- #visit_mut_variants
- }
- });
- }
- types::Data::Struct(fields) => {
- for (field, ty) in fields {
- let id = Ident::new(&field, Span::call_site());
- let ref_toks = Owned(quote!(_i.#id));
- let visit_mut_field = visit(&ty, &s.features, defs, &ref_toks)
- .unwrap_or_else(|| noop_visit(&ref_toks));
- visit_mut_impl.append_all(quote! {
- #visit_mut_field;
- });
- }
- }
- types::Data::Private => {}
- }
-
- state.visit_mut_trait.append_all(quote! {
- #features
- fn #visit_mut_fn(&mut self, i: &mut #ty) {
- #visit_mut_fn(self, i)
- }
- });
-
- state.visit_mut_impl.append_all(quote! {
- #features
- pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
- _visitor: &mut V, _i: &mut #ty
- ) {
- #visit_mut_impl
- }
- });
}
}
+fn simple_visit(item: &str, name: &Operand) -> TokenStream {
+ let ident = under_name(item);
+ let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
+ let name = name.ref_mut_tokens();
+ quote! {
+ _visitor.#method(#name)
+ }
+}
+
+fn box_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let name = name.owned_tokens();
+ let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
+ Some(res)
+}
+
+fn vec_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let operand = Borrowed(quote!(it));
+ let val = visit(elem, features, defs, &operand)?;
+ let name = name.ref_mut_tokens();
+ Some(quote! {
+ for it in #name {
+ #val
+ }
+ })
+}
+
+fn punctuated_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let operand = Borrowed(quote!(it));
+ let val = visit(elem, features, defs, &operand)?;
+ let name = name.ref_mut_tokens();
+ Some(quote! {
+ for mut el in Punctuated::pairs_mut(#name) {
+ let it = el.value_mut();
+ #val
+ }
+ })
+}
+
+fn option_visit(
+ elem: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ let it = Borrowed(quote!(it));
+ let val = visit(elem, features, defs, &it)?;
+ let name = name.owned_tokens();
+ Some(quote! {
+ if let Some(ref mut it) = #name {
+ #val
+ }
+ })
+}
+
+fn tuple_visit(
+ elems: &[types::Type],
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ if elems.is_empty() {
+ return None;
+ }
+
+ let mut code = TokenStream::new();
+ for (i, elem) in elems.iter().enumerate() {
+ let name = name.tokens();
+ let i = Index::from(i);
+ let it = Owned(quote!((#name).#i));
+ let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
+ code.append_all(val);
+ code.append_all(quote!(;));
+ }
+ Some(code)
+}
+
+fn token_punct_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ tokens_helper(_visitor, &mut #name.spans)
+ }
+}
+
+fn token_keyword_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ tokens_helper(_visitor, &mut #name.span)
+ }
+}
+
+fn token_group_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ tokens_helper(_visitor, &mut #name.span)
+ }
+}
+
+fn noop_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ skip!(#name)
+ }
+}
+
+fn visit(
+ ty: &types::Type,
+ features: &types::Features,
+ defs: &types::Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ match ty {
+ types::Type::Box(t) => box_visit(&*t, features, defs, name),
+ types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
+ types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
+ types::Type::Option(t) => option_visit(&*t, features, defs, name),
+ types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
+ types::Type::Token(t) => {
+ let repr = &defs.tokens[t];
+ let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+ if is_keyword {
+ Some(token_keyword_visit(name))
+ } else {
+ Some(token_punct_visit(name))
+ }
+ }
+ types::Type::Group(_) => Some(token_group_visit(name)),
+ types::Type::Syn(t) => {
+ fn requires_full(features: &types::Features) -> bool {
+ features.any.contains("full") && features.any.len() == 1
+ }
+
+ let res = simple_visit(t, name);
+
+ let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+
+ Some(
+ if requires_full(&target.features) && !requires_full(features) {
+ quote! {
+ full!(#res)
+ }
+ } else {
+ res
+ },
+ )
+ }
+ types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+ types::Type::Ext(_) | types::Type::Std(_) => None,
+ }
+}
+
+fn visit_features(features: &types::Features) -> TokenStream {
+ let features = &features.any;
+ match features.len() {
+ 0 => quote!(),
+ 1 => quote!(#[cfg(feature = #(#features)*)]),
+ _ => quote!(#[cfg(any(#(feature = #features),*))]),
+ }
+}
+
+fn node(state: &mut State, s: &types::Node, defs: &types::Definitions) {
+ let features = visit_features(&s.features);
+ let under_name = under_name(&s.ident);
+ let ty = Ident::new(&s.ident, Span::call_site());
+ let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
+
+ let mut visit_mut_impl = TokenStream::new();
+
+ match &s.data {
+ types::Data::Enum(variants) => {
+ let mut visit_mut_variants = TokenStream::new();
+
+ for (variant, fields) in variants {
+ let variant_ident = Ident::new(variant, Span::call_site());
+
+ if fields.is_empty() {
+ visit_mut_variants.append_all(quote! {
+ #ty::#variant_ident => {}
+ });
+ } else {
+ let mut bind_visit_mut_fields = TokenStream::new();
+ let mut visit_mut_fields = TokenStream::new();
+
+ for (idx, ty) in fields.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_visit_mut_fields.append_all(quote! {
+ ref mut #binding,
+ });
+
+ let borrowed_binding = Borrowed(quote!(#binding));
+
+ visit_mut_fields.append_all(
+ visit(ty, &s.features, defs, &borrowed_binding)
+ .unwrap_or_else(|| noop_visit(&borrowed_binding)),
+ );
+
+ visit_mut_fields.append_all(quote!(;));
+ }
+
+ visit_mut_variants.append_all(quote! {
+ #ty::#variant_ident(#bind_visit_mut_fields) => {
+ #visit_mut_fields
+ }
+ });
+ }
+ }
+
+ visit_mut_impl.append_all(quote! {
+ match *_i {
+ #visit_mut_variants
+ }
+ });
+ }
+ types::Data::Struct(fields) => {
+ for (field, ty) in fields {
+ let id = Ident::new(&field, Span::call_site());
+ let ref_toks = Owned(quote!(_i.#id));
+ let visit_mut_field = visit(&ty, &s.features, defs, &ref_toks)
+ .unwrap_or_else(|| noop_visit(&ref_toks));
+ visit_mut_impl.append_all(quote! {
+ #visit_mut_field;
+ });
+ }
+ }
+ types::Data::Private => {}
+ }
+
+ state.visit_mut_trait.append_all(quote! {
+ #features
+ fn #visit_mut_fn(&mut self, i: &mut #ty) {
+ #visit_mut_fn(self, i)
+ }
+ });
+
+ state.visit_mut_impl.append_all(quote! {
+ #features
+ pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
+ _visitor: &mut V, _i: &mut #ty
+ ) {
+ #visit_mut_impl
+ }
+ });
+}
+
pub fn generate(defs: &types::Definitions) {
- let state = gen::traverse(defs, codegen::generate);
+ let state = gen::traverse(defs, node);
let full_macro = full::get_macro();
let visit_mut_trait = state.visit_mut_trait;
let visit_mut_impl = state.visit_mut_impl;