ccarp 0.1.2

(trans)Compile C And Rust Partially
Documentation
//! C Translation Units
//! 
//! This module defines types associated with top level statements
//! (or translation units). Important definitions:
//! - `TranslationUnit`, which signifies a list of top level statements (a C program)
//! - `ExternalDeclaration`, which signifies a single top level statement
//! - `FunctionDef`, which signifies a C function definition (not just declaration)
use pest::iterators::Pair;

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

use super::{decl::{Declaration, DeclarationSpecifiers, Declarator, NonEmptyVec}, defs::{list_ast, Rule, AST}, stmt::CompoundStmt};

/// C Translation Unit
/// 
/// These signify the top level statements found in C99.
/// 
/// These consist of:
/// - External Declarations - `extern-decl`
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TranslationUnit(pub NonEmptyVec<ExternalDeclaration>);
list_ast!(TranslationUnit : ExternalDeclaration where trans_unit => extern_decl);

/// C External Declaration
/// 
/// These can be:
/// - Function Definitions - `fn-def`
/// - or Declarations - `decl`
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ExternalDeclaration {
    Fn(FunctionDef),    // fn-def
    Decl(Declaration)   // decl
}
impl AST for ExternalDeclaration {
    fn take(pair: Pair<Rule>) -> Result<Self> {
        match pair.as_rule() {
            Rule::extern_decl => {
                let pair=safe_unwrap!(pair.into_inner().next(),"External Declaration");
                match pair.as_rule() {
                    Rule::fn_def => Ok(Self::Fn(FunctionDef::take(pair)?)), // fn-def
                    Rule::decl => Ok(Self::Decl(Declaration::take(pair)?)), // decl
                    _ => Err(rule_mismatch!(pair))
                }
            },
            _ => Err(rule_mismatch!(pair,extern_decl))
        }
    }
}

/// C Dunction Definition
/// 
/// These consist of:
/// - Declaration Specifiers followed by a Declarator (type and name),
///   an optional Declaration List (parameter types) and a Compound Statement (body) - `specifiers declarator declaration-list? compound-stmt`
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FunctionDef(pub Box<DeclarationSpecifiers>, pub Box<Declarator>, pub Option<Box<DeclarationList>>, pub Box<CompoundStmt>);
impl AST for FunctionDef {
    fn take(pair: Pair<Rule>) -> Result<Self> {
        match pair.as_rule() {
            Rule::fn_def => {
                let mut inner=pair.into_inner();
                let spec=DeclarationSpecifiers::take(safe_unwrap!(inner.next(),"Function Type"))?;  // specifiers
                let decl=Declarator::take(safe_unwrap!(inner.next(),"Function Name"))?;     // declarator
                let pair=safe_unwrap!(inner.next(),"Function Definition");
                match pair.as_rule() {
                    Rule::decl_list => {
                        let decl_list=DeclarationList::take(pair)?; // declaration-list
                        let pair=safe_unwrap!(inner.next(),"Function Definition");
                        Ok(Self(Box::new(spec),Box::new(decl),Some(Box::new(decl_list)),Box::new(CompoundStmt::take(pair)?)))   // specifiers declarator declaration-list compound-stmt
                    }
                    Rule::compound_stmt => Ok(Self(Box::new(spec),Box::new(decl),None,Box::new(CompoundStmt::take(pair)?))),    // specifiers declarator compound-stmt
                    _ => Err(rule_mismatch!(pair))
                }
            },
            _ => Err(rule_mismatch!(pair,fn_def))
        }
    }
}

/// C Declaration List
/// 
/// These consist of:
/// - Declarations - `decl decl ...`
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DeclarationList(pub NonEmptyVec<Declaration>);   // decl decl ...
list_ast!(DeclarationList : Declaration where decl_list => decl);