1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) 2016-2021 Fabian Schuiki

//! Procedural macros for the moore compiler.

extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;

mod accept_visitor;
mod all_node;
mod arena;
mod node;
mod node_data;
mod query;
mod visitor;
mod walk_visitor;

/// Pick the first lifetime from a `syn::Generics`, or create one.
///
/// This either returns the first lifetime in the generics, or adds a new
/// lifetime.
fn first_lifetime(gen: &mut syn::Generics) -> syn::Lifetime {
    // Check if there already is a lifetime that we can use.
    if let Some(ltdef) = gen.lifetimes().next() {
        return ltdef.lifetime.clone();
    }

    // Otherwise generate one.
    let ltdef: syn::LifetimeDef = syn::parse_str("'a").unwrap();
    let lt = ltdef.lifetime.clone();
    gen.params.insert(0, syn::GenericParam::Lifetime(ltdef));
    lt
}

/// Generate an `AcceptVisitor` implementation.
#[proc_macro_derive(AcceptVisitor, attributes(dont_visit))]
pub fn accept_visitor(input: TokenStream) -> TokenStream {
    accept_visitor::accept_visitor(input, false)
}

/// Generate an `AcceptVisitor`, `ForEachNode`, and `ForEachChild` implementation.
#[proc_macro_derive(AcceptVisitorAndForeach, attributes(dont_visit))]
pub fn accept_visitor_and_foreach(input: TokenStream) -> TokenStream {
    accept_visitor::accept_visitor(input, true)
}

/// Wrap a struct or enum in a `Node`.
#[proc_macro_attribute]
pub fn node(args: TokenStream, input: TokenStream) -> TokenStream {
    node::node(args, input)
}

/// Generate an `AnyNodeData` implementation.
#[proc_macro_derive(AnyNodeData, attributes(name, forward, indefinite, definite))]
pub fn node_data(input: TokenStream) -> TokenStream {
    node_data::node_data(input)
}

/// Generate corresponding `*_visit_*` functions in a visitor.
#[proc_macro_attribute]
pub fn walk_visitor(args: TokenStream, input: TokenStream) -> TokenStream {
    walk_visitor::walk_visitor(args, input)
}

/// Convenience macro to derive `AcceptVisitorAndForeach` and `walk_visitor`.
#[proc_macro_attribute]
pub fn visit(_args: TokenStream, input: TokenStream) -> TokenStream {
    let input = proc_macro2::TokenStream::from(input);
    TokenStream::from(quote! {
        #[moore_derive::walk_visitor]
        #[derive(moore_derive::AcceptVisitorAndForeach)]
        #input
    })
}

/// Convenience macro to derive `AcceptVisitor` and `walk_visitor`.
#[proc_macro_attribute]
pub fn visit_without_foreach(_args: TokenStream, input: TokenStream) -> TokenStream {
    let input = proc_macro2::TokenStream::from(input);
    TokenStream::from(quote! {
        #[moore_derive::walk_visitor]
        #[derive(moore_derive::AcceptVisitor)]
        #input
    })
}

/// Generate a `AllNode` enum.
#[proc_macro]
pub fn derive_all_node(input: TokenStream) -> TokenStream {
    all_node::all_node(input)
}

/// Mark a node to be included in the `AllNode` enum.
#[proc_macro_attribute]
pub fn all_node(args: TokenStream, input: TokenStream) -> TokenStream {
    all_node::mark_all_node(args, input)
}

/// Generate a `Visitor` trait.
#[proc_macro]
pub fn derive_visitor(input: TokenStream) -> TokenStream {
    visitor::visitor(input)
}

/// Mark a function as a compiler query.
#[proc_macro_attribute]
pub fn query(args: TokenStream, input: TokenStream) -> TokenStream {
    query::mark_query(args, input)
}

/// Generate a compiler query database.
#[proc_macro]
pub fn derive_query_db(input: TokenStream) -> TokenStream {
    query::derive_query_db(input)
}

/// Generate an arena struct.
#[proc_macro]
pub fn derive_arena(input: TokenStream) -> TokenStream {
    arena::derive_arena(input)
}

/// Mark an item to be allocatable in an arena.
#[proc_macro_attribute]
pub fn arena(args: TokenStream, input: TokenStream) -> TokenStream {
    arena::mark_arena(args, input)
}