ccarp 0.1.2

(trans)Compile C And Rust Partially
Documentation
//! C Tokentree
//! 
//! This module defines types associated with C tokenisation, as such it includes:
//! - `TokenTree`, which represents a full C99 tokentree (without macros)
//! - `Literal`, which represents a C99 constant, or string literal
//! - `Identifier`, which represents a C99 identifier (name of variable/field/etc.)
use std::fmt::{Debug, Display};

use pest::iterators::Pair;

use crate::ccarp::error::{rule_err, rule_mismatch, safe_unwrap, CCErr, Result};

use super::defs::{list_ast, print_vec, Rule, AST};

/// A C token tree
/// 
/// It consists of C Tokens
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct TokenTree(pub Vec<Token>);
list_ast!(TokenTree : Token where tokentree => token);
impl Display for TokenTree {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f,"{}",print_vec(&self.0, " "))
    }
}

/// A C token
/// 
/// Possible variants:
/// - `Keyword` - keywords in the C language, such as `auto` or `int`
/// - `Identifier` - identifiers, as in variable names, method names, field names, etc.
/// - `Literal` - literals, as in constant values specified by the programmer (e.g. `13` or `"Hello World!"`)
/// - `Punctuator` - operators and separators, e.g. `+`, `=` or `{}`
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Token {
    Keyword(Keyword),
    Identifier(Identifier),
    Literal(Literal),
    Punctuator(Punctuator),
    Include(Include)
}
impl AST for Token {
    fn take(pair: Pair<Rule>) -> Result<Self> {
        match pair.as_rule() {
            Rule::token => {
                let pair=safe_unwrap!(pair.into_inner().next(),"Token");
                match pair.as_rule() {
                    Rule::keyword => Ok(Self::Keyword(Keyword::take(pair)?)),
                    Rule::ident => Ok(Self::Identifier(Identifier::take(pair)?)),
                    Rule::lit => Ok(Self::Literal(Literal::take(pair)?)),
                    Rule::punct => Ok(Self::Punctuator(Punctuator::take(pair)?)),
                    Rule::include => Ok(Self::Include(Include::take(pair)?)),
                    _ => Err(rule_mismatch!(pair))
                }
            },
            _ => Err(rule_mismatch!(pair,token))
        }
    }
}
impl Display for Token {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Keyword(keyword) => write!(f,"{keyword}"),
            Self::Identifier(identifier) => write!(f,"{identifier}"),
            Self::Literal(literal) => write!(f,"{literal}"),
            Self::Punctuator(punctuator) => write!(f,"{punctuator}"),
            Self::Include(_) => write!(f,"")
        }
    }
}

/// A C keyword
/// 
/// A representation of keywords in the C language, such as `auto` or `int`.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Keyword(pub String);
impl AST for Keyword {
    fn take(pair: Pair<Rule>) -> Result<Self> {
        match pair.as_rule() {
            Rule::keyword => Ok(Self(pair.as_str().to_string())),
            _ => Err(rule_mismatch!(pair,keyword))
        }
    }
}
impl Display for Keyword {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f,"{}",self.0)
    }
}

/// A C literal
/// 
/// A representation of C literals, as in constant values specified by the programmer (e.g. `13` or `"Hello World!"`).
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Literal {
    Int(String),
    Float(String),
    Char(String),
    String(String)
}
impl AST for Literal {
    fn take(mut pair: Pair<Rule>) -> Result<Self> {
        if pair.as_rule()==Rule::tok_lit { pair=safe_unwrap!(pair.into_inner().next(),"Literal token"); }
        match pair.as_rule() {
            Rule::lit => {
                pair=safe_unwrap!(pair.into_inner().next(),"Literal");
                match pair.as_rule() {
                    Rule::float => Ok(Self::Float(pair.as_str().to_string())),
                    Rule::int => Ok(Self::Int(pair.as_str().to_string())),
                    Rule::char => Ok(Self::Char(pair.as_str().to_string())),
                    Rule::string => Ok(Self::String(pair.as_str().to_string())),
                    _ => Err(rule_mismatch!(pair))
                }
            },
            _ => Err(rule_mismatch!(pair,lit))
        }
    }
}
impl Display for Literal {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Int(lit)|Self::Float(lit)|Self::Char(lit)|Self::String(lit) => write!(f,"#l{lit}#l"),
        }
    }
}

/// A C identifier
/// 
/// A representation of C identifiers, as in variable names, method names, field names, etc.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Identifier(pub String);
impl AST for Identifier {
    fn take(mut pair: Pair<Rule>) -> Result<Self> {
        if pair.as_rule()==Rule::tok_ident { pair=safe_unwrap!(pair.into_inner().next(),"Identifier token"); }
        match pair.as_rule() {
            Rule::ident => Ok(Self(pair.as_str().to_string())),
            _ => Err(rule_mismatch!(pair,ident))
        }
    }
}
impl Display for Identifier {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f,"#i{}#i",self.0)
    }
}

/// A C punctuator
/// 
/// A representation of operators and separators, e.g. `+`, `=` or `{}`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Punctuator(pub String);
impl AST for Punctuator {
    fn take(pair: Pair<Rule>) -> Result<Self> {
        match pair.as_rule() {
            Rule::punct => Ok(Self(pair.as_str().to_string())),
            _ => Err(rule_mismatch!(pair,punct))
        }
    }
}
impl Display for Punctuator {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f,"#p{}#p",self.0)
    }
}


#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Include(pub String);
impl AST for Include {
    fn take(pair: Pair<Rule>) -> Result<Self> {
        match pair.as_rule() {
            Rule::include => {
                let pair=safe_unwrap!(pair.into_inner().next(),"Include");
                match pair.as_rule() {
                    Rule::header_name => Ok(Self(pair.as_str().to_string())),
                    _ => Err(rule_mismatch!(pair,header_name))
                }
            },
            _ => Err(rule_mismatch!(pair,include))
        }
    }
}
impl Include {
    pub fn get_name(self) -> String {
        let mut out=self.0.chars();
        out.next();
        out.next_back();
        out.collect()
    }
}