aboutsummaryrefslogtreecommitdiff
path: root/syn/codegen/src/fold.rs
diff options
context:
space:
mode:
Diffstat (limited to 'syn/codegen/src/fold.rs')
-rw-r--r--syn/codegen/src/fold.rs284
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, &quote!(*#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(())
-}