diff options
Diffstat (limited to 'syn/codegen/src/visit.rs')
-rw-r--r-- | syn/codegen/src/visit.rs | 265 |
1 files changed, 0 insertions, 265 deletions
diff --git a/syn/codegen/src/visit.rs b/syn/codegen/src/visit.rs deleted file mode 100644 index 41bc9e9..0000000 --- a/syn/codegen/src/visit.rs +++ /dev/null @@ -1,265 +0,0 @@ -use crate::operand::{Borrowed, Operand, Owned}; -use crate::{file, full, gen}; -use anyhow::Result; -use proc_macro2::{Ident, Span, TokenStream}; -use quote::quote; -use syn::Index; -use syn_codegen::{Data, Definitions, Features, Node, Type}; - -const VISIT_SRC: &str = "../src/gen/visit.rs"; - -fn simple_visit(item: &str, name: &Operand) -> TokenStream { - let ident = gen::under_name(item); - let method = Ident::new(&format!("visit_{}", ident), Span::call_site()); - let name = name.ref_tokens(); - quote! { - v.#method(#name) - } -} - -fn noop_visit(name: &Operand) -> TokenStream { - let name = name.tokens(); - quote! { - skip!(#name) - } -} - -fn visit( - ty: &Type, - features: &Features, - defs: &Definitions, - name: &Operand, -) -> Option<TokenStream> { - match ty { - Type::Box(t) => { - let name = name.owned_tokens(); - visit(t, features, defs, &Owned(quote!(*#name))) - } - Type::Vec(t) => { - let operand = Borrowed(quote!(it)); - let val = visit(t, features, defs, &operand)?; - let name = name.ref_tokens(); - Some(quote! { - for it in #name { - #val - } - }) - } - Type::Punctuated(p) => { - let operand = Borrowed(quote!(it)); - let val = visit(&p.element, features, defs, &operand)?; - let name = name.ref_tokens(); - Some(quote! { - for el in Punctuated::pairs(#name) { - let (it, p) = el.into_tuple(); - #val; - if let Some(p) = p { - tokens_helper(v, &p.spans); - } - } - }) - } - Type::Option(t) => { - let it = Borrowed(quote!(it)); - let val = visit(t, features, defs, &it)?; - let name = name.owned_tokens(); - Some(quote! { - if let Some(it) = &#name { - #val - } - }) - } - Type::Tuple(t) => { - let mut code = TokenStream::new(); - for (i, elem) in t.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.extend(val); - code.extend(quote!(;)); - } - Some(code) - } - Type::Token(t) => { - let name = name.tokens(); - let repr = &defs.tokens[t]; - let is_keyword = repr.chars().next().unwrap().is_alphabetic(); - let spans = if is_keyword { - quote!(span) - } else { - quote!(spans) - }; - Some(quote! { - tokens_helper(v, &#name.#spans) - }) - } - Type::Group(_) => { - let name = name.tokens(); - Some(quote! { - tokens_helper(v, &#name.span) - }) - } - Type::Syn(t) => { - fn requires_full(features: &Features) -> bool { - features.any.contains("full") && features.any.len() == 1 - } - let mut res = simple_visit(t, name); - let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap(); - if requires_full(&target.features) && !requires_full(features) { - res = quote!(full!(#res)); - } - Some(res) - } - Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)), - Type::Ext(_) | Type::Std(_) => None, - } -} - -fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) { - let under_name = gen::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 { - 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.extend(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.extend(quote! { - #binding, - }); - - let borrowed_binding = Borrowed(quote!(#binding)); - - visit_fields.extend( - visit(ty, &s.features, defs, &borrowed_binding) - .unwrap_or_else(|| noop_visit(&borrowed_binding)), - ); - - visit_fields.extend(quote!(;)); - } - - visit_variants.extend(quote! { - #ty::#variant_ident(#bind_visit_fields) => { - #visit_fields - } - }); - } - } - - let nonexhaustive = if s.exhaustive { - None - } else { - Some(quote!(_ => unreachable!())) - }; - - visit_impl.extend(quote! { - match node { - #visit_variants - #nonexhaustive - } - }); - } - Data::Struct(fields) => { - for (field, ty) in fields { - if let Type::Syn(ty) = ty { - if ty == "Reserved" { - continue; - } - } - - let id = Ident::new(&field, Span::call_site()); - let ref_toks = Owned(quote!(node.#id)); - let visit_field = visit(&ty, &s.features, defs, &ref_toks) - .unwrap_or_else(|| noop_visit(&ref_toks)); - visit_impl.extend(quote! { - #visit_field; - }); - } - } - Data::Private => { - if ty == "Ident" { - visit_impl.extend(quote! { - v.visit_span(&node.span()); - }); - } - } - } - - let ast_lifetime = if s.ident == "Span" { - None - } else { - Some(quote!('ast)) - }; - - traits.extend(quote! { - fn #visit_fn(&mut self, i: &#ast_lifetime #ty) { - #visit_fn(self, i) - } - }); - - impls.extend(quote! { - pub fn #visit_fn<'ast, V>(v: &mut V, node: &#ast_lifetime #ty) - where - V: Visit<'ast> + ?Sized, - { - #visit_impl - } - }); -} - -pub fn generate(defs: &Definitions) -> Result<()> { - let (traits, impls) = gen::traverse(defs, node); - let full_macro = full::get_macro(); - file::write( - VISIT_SRC, - quote! { - #![allow(unused_variables)] - - use crate::*; - #[cfg(any(feature = "full", feature = "derive"))] - use crate::punctuated::Punctuated; - use proc_macro2::Span; - #[cfg(any(feature = "full", feature = "derive"))] - use crate::gen::helper::visit::*; - - #full_macro - - #[cfg(any(feature = "full", feature = "derive"))] - macro_rules! skip { - ($($tt:tt)*) => {}; - } - - /// Syntax tree traversal to walk a shared borrow of a syntax tree. - /// - /// See the [module documentation] for details. - /// - /// [module documentation]: self - /// - /// *This trait is available if Syn is built with the `"visit"` feature.* - pub trait Visit<'ast> { - #traits - } - - #impls - }, - )?; - Ok(()) -} |