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};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TranslationUnit(pub NonEmptyVec<ExternalDeclaration>);
list_ast!(TranslationUnit : ExternalDeclaration where trans_unit => extern_decl);
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ExternalDeclaration {
Fn(FunctionDef), Decl(Declaration) }
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)?)), Rule::decl => Ok(Self::Decl(Declaration::take(pair)?)), _ => Err(rule_mismatch!(pair))
}
},
_ => Err(rule_mismatch!(pair,extern_decl))
}
}
}
#[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"))?; let decl=Declarator::take(safe_unwrap!(inner.next(),"Function Name"))?; let pair=safe_unwrap!(inner.next(),"Function Definition");
match pair.as_rule() {
Rule::decl_list => {
let decl_list=DeclarationList::take(pair)?; 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)?))) }
Rule::compound_stmt => Ok(Self(Box::new(spec),Box::new(decl),None,Box::new(CompoundStmt::take(pair)?))), _ => Err(rule_mismatch!(pair))
}
},
_ => Err(rule_mismatch!(pair,fn_def))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DeclarationList(pub NonEmptyVec<Declaration>); list_ast!(DeclarationList : Declaration where decl_list => decl);