diff options
Diffstat (limited to 'syn/codegen/src/fold.rs')
-rw-r--r-- | syn/codegen/src/fold.rs | 284 |
1 files changed, 0 insertions, 284 deletions
diff --git a/syn/codegen/src/fold.rs b/syn/codegen/src/fold.rs deleted file mode 100644 index 6914d76..0000000 --- a/syn/codegen/src/fold.rs +++ /dev/null @@ -1,284 +0,0 @@ -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 FOLD_SRC: &str = "../src/gen/fold.rs"; - -fn simple_visit(item: &str, name: &TokenStream) -> TokenStream { - let ident = gen::under_name(item); - let method = Ident::new(&format!("fold_{}", ident), Span::call_site()); - quote! { - f.#method(#name) - } -} - -fn visit( - ty: &Type, - features: &Features, - defs: &Definitions, - name: &TokenStream, -) -> Option<TokenStream> { - match ty { - Type::Box(t) => { - let res = visit(t, features, defs, "e!(*#name))?; - Some(quote! { - Box::new(#res) - }) - } - Type::Vec(t) => { - let operand = quote!(it); - let val = visit(t, features, defs, &operand)?; - Some(quote! { - FoldHelper::lift(#name, |it| { #val }) - }) - } - Type::Punctuated(p) => { - let operand = quote!(it); - let val = visit(&p.element, features, defs, &operand)?; - Some(quote! { - FoldHelper::lift(#name, |it| { #val }) - }) - } - Type::Option(t) => { - let it = quote!(it); - let val = visit(t, features, defs, &it)?; - Some(quote! { - (#name).map(|it| { #val }) - }) - } - Type::Tuple(t) => { - let mut code = TokenStream::new(); - for (i, elem) in t.iter().enumerate() { - let i = Index::from(i); - let it = quote!((#name).#i); - let val = visit(elem, features, defs, &it).unwrap_or(it); - code.extend(val); - code.extend(quote!(,)); - } - Some(quote! { - (#code) - }) - } - Type::Token(t) => { - let repr = &defs.tokens[t]; - let is_keyword = repr.chars().next().unwrap().is_alphabetic(); - let spans = if is_keyword { - quote!(span) - } else { - quote!(spans) - }; - let ty = if repr == "await" { - quote!(crate::token::Await) - } else { - syn::parse_str(&format!("Token![{}]", repr)).unwrap() - }; - Some(quote! { - #ty(tokens_helper(f, &#name.#spans)) - }) - } - Type::Group(t) => { - let ty = Ident::new(t, Span::call_site()); - Some(quote! { - #ty(tokens_helper(f, &#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 fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site()); - - let mut fold_impl = TokenStream::new(); - - match &s.data { - Data::Enum(variants) => { - let mut fold_variants = TokenStream::new(); - - for (variant, fields) in variants { - let variant_ident = Ident::new(variant, Span::call_site()); - - if fields.is_empty() { - fold_variants.extend(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.extend(quote! { - #binding, - }); - - let owned_binding = quote!(#binding); - - fold_fields.extend( - visit(ty, &s.features, defs, &owned_binding).unwrap_or(owned_binding), - ); - - fold_fields.extend(quote!(,)); - } - - fold_variants.extend(quote! { - #ty::#variant_ident(#bind_fold_fields) => { - #ty::#variant_ident( - #fold_fields - ) - } - }); - } - } - - let nonexhaustive = if s.exhaustive { - None - } else { - Some(quote!(_ => unreachable!())) - }; - - fold_impl.extend(quote! { - match node { - #fold_variants - #nonexhaustive - } - }); - } - 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!(node.#id); - - if let Type::Syn(ty) = ty { - if ty == "Reserved" { - fold_fields.extend(quote! { - #id: #ref_toks, - }); - continue; - } - } - - let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks); - - fold_fields.extend(quote! { - #id: #fold, - }); - } - - if !fields.is_empty() { - fold_impl.extend(quote! { - #ty { - #fold_fields - } - }) - } else { - if ty == "Ident" { - fold_impl.extend(quote! { - let mut node = node; - let span = f.fold_span(node.span()); - node.set_span(span); - }); - } - fold_impl.extend(quote! { - node - }); - } - } - Data::Private => { - if ty == "Ident" { - fold_impl.extend(quote! { - let mut node = node; - let span = f.fold_span(node.span()); - node.set_span(span); - }); - } - fold_impl.extend(quote! { - node - }); - } - } - - let fold_span_only = - s.data == Data::Private && !gen::TERMINAL_TYPES.contains(&s.ident.as_str()); - if fold_span_only { - fold_impl = quote! { - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node - }; - } - - traits.extend(quote! { - fn #fold_fn(&mut self, i: #ty) -> #ty { - #fold_fn(self, i) - } - }); - - impls.extend(quote! { - pub fn #fold_fn<F>(f: &mut F, node: #ty) -> #ty - where - F: Fold + ?Sized, - { - #fold_impl - } - }); -} - -pub fn generate(defs: &Definitions) -> Result<()> { - let (traits, impls) = gen::traverse(defs, node); - let full_macro = full::get_macro(); - file::write( - FOLD_SRC, - quote! { - // Unreachable code is generated sometimes without the full feature. - #![allow(unreachable_code, unused_variables)] - - use crate::*; - #[cfg(any(feature = "full", feature = "derive"))] - use crate::token::{Brace, Bracket, Paren, Group}; - use proc_macro2::Span; - #[cfg(any(feature = "full", feature = "derive"))] - use crate::gen::helper::fold::*; - - #full_macro - - /// Syntax tree traversal to transform the nodes of an owned syntax tree. - /// - /// See the [module documentation] for details. - /// - /// [module documentation]: self - /// - /// *This trait is available if Syn is built with the `"fold"` feature.* - pub trait Fold { - #traits - } - - #impls - }, - )?; - Ok(()) -} |