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
#![warn(missing_docs)]
//! Generally useful methods to convert a WAG to Rust code.
//!
//! A WAG may be converted into code in any number of ways for any number of reasons. This crate intends to hold
//! code that is generally useful, regardless of the purpose of the final generated code.

/// Codegen for parts of the [`wagon-parser`] AST that are generally useful.
pub mod nodes;
/// A datastructure that represents a structure and data to write to disk.
mod filestructure;

use std::rc::Rc;
use proc_macro2::{TokenStream, Ident};
use wagon_parser::{parser::Parse, SpannableNode};
pub use filestructure::{FileStructure, FileType};

/// A quick type alias to represent a [`wagon_ident::Ident`] with span information.
pub type SpannableIdent = SpannableNode<wagon_ident::Ident>;

/// A trait for anything that does codegen while having to keep track of some state object `U`.
pub trait ToTokensState<U> {
    /// A method to do codegen based on state and possibly modify that state.
    ///
    /// This method takes a given mutable state `U`, as well as a reference to some [`proc_macro2::Ident`] and a function to modify the state.
    /// It then potentially calls this function to modify the state and returns a `TokenStream` for the generated code.
    ///
    /// # Example
    /// ```
    /// # use wagon_parser::SpannableNode;
    /// # use proc_macro2::TokenStream;
    /// # use wagon_codegen::{SpannableIdent, ToTokensState};
    /// # use std::rc::Rc;
    /// struct A;
    /// struct State { toggle: bool }
    /// impl State {
    ///     fn new() -> Self {
    ///         Self { toggle: false }  
    ///     }
    ///     fn toggle(&mut self, _: Rc<proc_macro2::Ident>, _: SpannableIdent) {
    ///         self.toggle = true;
    ///     }   
    /// }
    /// impl ToTokensState<State> for A {
    ///     fn to_tokens(&self, state: &mut State, label: Rc<proc_macro2::Ident>, attr_fun: fn(&mut State, Rc<proc_macro2::Ident>, SpannableIdent)) -> TokenStream {
    ///         attr_fun(state, label, SpannableNode::from(wagon_ident::Ident::default()));
    ///         TokenStream::new()
    ///     }
    /// }
    /// let a = A;
    /// let mut state = State { toggle: false };
    /// let label = Rc::new(proc_macro2::Ident::new("label", proc_macro2::Span::call_site()));
    /// a.to_tokens(&mut state, label, State::toggle);
    /// assert!(state.toggle) // this is now true
    /// ```
    ///
    /// For practical examples. Look at the implementations in this crate as well as how they are called in the [`wagon-codegen-gll`] crate.
	fn to_tokens(&self, state: &mut U, label: Rc<Ident>, attr_fun: fn(&mut U, Rc<Ident>, SpannableIdent)) -> TokenStream;
}

impl<U, T: Parse + ToTokensState<U>> ToTokensState<U> for SpannableNode<T> {
    fn to_tokens(&self, state: &mut U, label: Rc<Ident>, attr_fun: fn(&mut U, Rc<Ident>, SpannableIdent)) -> TokenStream {
        self.to_inner().to_tokens(state, label, attr_fun)
    }
}