ccarp 0.1.2

(trans)Compile C And Rust Partially
Documentation
//! Helper Module
//! 
//! This helper defines some traits and macros which are used inside the module (`ccarp_c`).
//! 
//! Important definitions:
//! - `AST`, which is a trait for creating an Abstract Syntax Tree from parsed structures
//! - `list_ast`, which derives AST generation for lists
//! - `bin_ast`, which derives AST generation for left associative binary expressions
use std::fmt::Display;

use pest::iterators::Pair;
use crate::ccarp::error::Result;

use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "lang.pest"]
pub struct ParserTy;

/// Trait AST (Abstract Syntax Tree)
/// 
/// An interface for building an Abstract Syntax Tree from parsed structures and rules.
/// 
/// ## Methods:
/// ```ignore
/// fn take(pair: Pair<Rule>) -> Self;
/// ```
#[allow(clippy::style)]
pub trait AST : Sized {
    /// Take a `pair` with a `Rule` and make an Abstract Syntax Tree from it
    /// 
    /// Note: This trait should only be implemented for the C AST
    /// 
    /// # Errors
    /// Returns with a `CCErr::RuleError` if rules are not matching or the inner
    /// structure of the rule is shorter than expected.
    fn take(pair: Pair<Rule>) -> Result<Self>;
}

/// Print a slice whose element implement `Display`
/// 
/// Creates a `String` from the elements of slice `v` separated by
/// `sep`.
/// 
/// # Example
/// ```ignore
/// let v=vec![1, 2, 3];
/// assert_eq!(print_vec(&v, ", "), "1, 2, 3".to_string());
/// ```
pub fn print_vec<T: Display>(v: &[T], sep: &str) -> String {
    v.iter().map(ToString::to_string).collect::<Vec<_>>().join(sep)
}

macro_rules! list_ast {
    ($for:ty : $t:ty where $p1:ident => $p2:ident) => {
        impl AST for $for {
            fn take(pair: Pair<Rule>) -> Result<Self> {
                match pair.as_rule() {
                    Rule::$p1 => {
                        let mut v=vec![];
                        for pair in pair.into_inner() {
                            match pair.as_rule() {
                                Rule::$p2 => v.push(<$t>::take(pair)?),
                                _ => return Err(rule_mismatch!(pair,$p2))
                            }
                        }
                        Ok(Self(v))
                    },
                    _ => return Err(rule_mismatch!(pair,$p1))
                }
            }
        }
    };
}
pub(crate) use list_ast;

macro_rules! bin_ast {
    ($for:ty : $t:ty where $p1:ident => $p2:ident, $($sp1:ident => $sp2:expr),+; if $ex:literal) => {
        impl AST for $for {
            fn take(pair: Pair<Rule>) -> Result<Self> {
                match pair.as_rule() {
                    Rule::$p1 => {
                        let mut fst=None;
                        let mut last_op=Default::default();
                        let mut v=vec![];
                        for pair in pair.into_inner() {
                            match pair.as_rule() {
                                Rule::$p2 => {
                                    if fst.is_none() { fst=Some(<$t>::take(pair)?) }
                                    else { v.push((last_op,<$t>::take(pair)?)); }
                                },
                                $(
                                    Rule::$sp1 => last_op=$sp2,
                                )+
                                _ => return Err(rule_mismatch!(pair))
                            }
                        }
                        Ok(Self(Box::new(safe_unwrap!(fst,$ex)),v))
                    },
                    _ => Err(rule_mismatch!(pair,$p1))
                }
            }
        }
    };
}
pub(crate) use bin_ast;