use std::mem::swap;
use pest::iterators::Pair;
use crate::ccarp::error::{rule_err, rule_mismatch, safe_unwrap, CCErr, Result};
use super::{decl::{Declaration, NonEmptyVec}, defs::{list_ast, Rule, AST}, expr::{ConstExpr, Expression}, tt::Identifier};
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Statement {
Labeled(LabeledStmt),
Compound(CompoundStmt),
Expr(ExprStmt),
Selection(SelectionStmt),
Iter(IterStmt),
Jump(JumpStmt)
}
impl AST for Statement {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::stmt => {
let pair=safe_unwrap!(pair.into_inner().next(),"Statement");
match pair.as_rule() {
Rule::labeled_stmt => Ok(Self::Labeled(LabeledStmt::take(pair)?)),
Rule::compound_stmt => Ok(Self::Compound(CompoundStmt::take(pair)?)),
Rule::expr_stmt => Ok(Self::Expr(ExprStmt::take(pair)?)),
Rule::select_stmt => Ok(Self::Selection(SelectionStmt::take(pair)?)),
Rule::iter_stmt => Ok(Self::Iter(IterStmt::take(pair)?)),
Rule::jump_stmt => Ok(Self::Jump(JumpStmt::take(pair)?)),
_ => Err(rule_mismatch!(pair))
}
},
_ => Err(rule_mismatch!(pair,stmt))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LabeledStmt {
Label(Identifier,Box<Statement>), Case(ConstExpr,Box<Statement>), Default(Box<Statement>) }
impl AST for LabeledStmt {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::labeled_stmt => {
let mut inner=pair.into_inner();
let pair=safe_unwrap!(inner.next(),"Labeled Statement");
match pair.as_rule() {
Rule::tok_ident => Ok(Self::Label(Identifier::take(pair)?, Box::new(Statement::take(safe_unwrap!(inner.next(),"Label Statement"))?))),
Rule::const_expr => Ok(Self::Case(ConstExpr::take(pair)?, Box::new(Statement::take(safe_unwrap!(inner.next(),"Case Statement"))?))),
Rule::stmt => Ok(Self::Default(Box::new(Statement::take(pair)?))),
_ => Err(rule_mismatch!(pair))
}
},
_ => Err(rule_mismatch!(pair,labeled_stmt))
}
}
}
impl LabeledStmt {
pub fn push_statement(&mut self,s: Statement) {
match self {
Self::Label(_, statement)|Self::Case(_, statement)|Self::Default(statement) => {
if let Statement::Compound(compound_stmt) = statement.as_mut() {
match &mut compound_stmt.0 {
Some(list) => list.0.push(BlockItem::Stmt(Box::new(s))),
None => compound_stmt.0=Some(BlockItemList(vec![BlockItem::Stmt(Box::new(s))])),
}
} else {
let mut tmp=Box::new(Statement::Compound(CompoundStmt(None)));
swap(&mut tmp, statement);
*statement=Box::new(Statement::Compound(CompoundStmt(Some(BlockItemList(vec![BlockItem::Stmt(tmp),BlockItem::Stmt(Box::new(s))])))));
}
},
}
}
pub fn push_declaration(&mut self, d: Declaration) {
match self {
Self::Label(_, statement)|Self::Case(_, statement)|Self::Default(statement) => {
if let Statement::Compound(compound_stmt) = statement.as_mut() {
match &mut compound_stmt.0 {
Some(list) => list.0.push(BlockItem::Decl(d)),
None => compound_stmt.0=Some(BlockItemList(vec![BlockItem::Decl(d)])),
}
} else {
let mut tmp=Box::new(Statement::Compound(CompoundStmt(None)));
swap(&mut tmp, statement);
*statement=Box::new(Statement::Compound(CompoundStmt(Some(BlockItemList(vec![BlockItem::Stmt(tmp),BlockItem::Decl(d)])))));
}
},
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CompoundStmt(pub Option<BlockItemList>); impl AST for CompoundStmt {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::compound_stmt => {
if let Some(pair)=pair.into_inner().next() {
match pair.as_rule() {
Rule::block_item_list => Ok(Self(Some(BlockItemList::take(pair)?))),
_ => Err(rule_mismatch!(pair,block_item_list))
}
}
else { Ok(Self(None)) }
},
_ => Err(rule_mismatch!(pair,compound_stmt))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct BlockItemList(pub NonEmptyVec<BlockItem>); list_ast!(BlockItemList : BlockItem where block_item_list => block_item);
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum BlockItem {
Decl(Declaration),
Stmt(Box<Statement>)
}
impl AST for BlockItem {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::block_item => {
let pair=safe_unwrap!(pair.into_inner().next(),"Block Item");
match pair.as_rule() {
Rule::decl => Ok(Self::Decl(Declaration::take(pair)?)),
Rule::stmt => Ok(Self::Stmt(Box::new(Statement::take(pair)?))),
_ => Err(rule_mismatch!(pair))
}
},
_ => Err(rule_mismatch!(pair,block_item))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ExprStmt(pub Option<Expression>); impl AST for ExprStmt {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::expr_stmt => {
if let Some(pair)=pair.into_inner().next() {
match pair.as_rule() {
Rule::expr => Ok(Self(Some(Expression::take(pair)?))),
_ => Err(rule_mismatch!(pair))
}
}
else { Ok(Self(None)) }
},
_ => Err(rule_mismatch!(pair,expr_stmt))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum SelectionStmt {
If(Expression,Box<Statement>), IfElse(Expression,Box<Statement>,Box<Statement>), Switch(Expression,Box<Statement>) }
impl AST for SelectionStmt {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::select_stmt => {
let mut inner=pair.into_inner();
let pair=safe_unwrap!(inner.next(),"Selection Statement");
match pair.as_rule() {
Rule::expr => {
let expr=Expression::take(pair)?; let stmt=Statement::take(safe_unwrap!(inner.next(),"If/If Else Statement"))?; if let Some(pair)=inner.next() { Ok(Self::IfElse(expr, Box::new(stmt), Box::new(Statement::take(pair)?))) } else { Ok(Self::If(expr, Box::new(stmt))) } },
Rule::switch => Ok(Self::Switch( Expression::take(safe_unwrap!(inner.next(),"Switch Statement"))?, Box::new(Statement::take(safe_unwrap!(inner.next(),"Switch Statement"))?) )),
_ => Err(rule_mismatch!(pair))
}
},
_ => Err(rule_mismatch!(pair,select_stmt))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum IterStmt {
While(Expression,Box<Statement>), DoWhile(Box<Statement>,Expression), For(Option<Box<Expression>>,Option<Box<Expression>>,Option<Box<Expression>>,Box<Statement>), ForDecl(Box<Declaration>,Option<Box<Expression>>,Option<Box<Expression>>,Box<Statement>) }
impl AST for IterStmt {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::iter_stmt => {
let mut is_do=false; let (mut expr1,mut expr2,mut expr3,mut decl,mut stmt)=(None,None,None,None,None);
for pair in pair.into_inner() {
match pair.as_rule() {
Rule::do2 => is_do=true, Rule::expr => {
if expr1.is_none() { expr1=Some(Expression::take(pair)?) } else if expr2.is_none() { expr2=Some(Expression::take(pair)?) } else if expr3.is_none() { expr3=Some(Expression::take(pair)?) } },
Rule::stmt => stmt=Some(Statement::take(pair)?), Rule::decl => decl=Some(Declaration::take(pair)?), _ => return Err(rule_mismatch!(pair))
}
}
if is_do { Ok(Self::DoWhile(Box::new(safe_unwrap!(stmt,"Do While Statement")), safe_unwrap!(expr1,"Do While Statement"))) }
else if expr3.is_some() { Ok(Self::For(expr1.map(Box::new), expr2.map(Box::new), expr3.map(Box::new), Box::new(safe_unwrap!(stmt,"For Statement")))) }
else if let Some(item)=decl { Ok(Self::ForDecl(Box::new(item), expr1.map(Box::new), expr2.map(Box::new), Box::new(safe_unwrap!(stmt,"For Statement")))) }
else { Ok(Self::While(safe_unwrap!(expr1,"While Statement"), Box::new(safe_unwrap!(stmt,"While Statement")))) }
},
_ => Err(rule_mismatch!(pair,iter_stmt))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum JumpStmt {
Goto(Identifier), Continue, Break, Return(Option<Expression>) }
impl AST for JumpStmt {
fn take(pair: Pair<Rule>) -> Result<Self> {
match pair.as_rule() {
Rule::jump_stmt => {
if let Some(pair)=pair.into_inner().next() {
match pair.as_rule() {
Rule::tok_ident => Ok(Self::Goto(Identifier::take(pair)?)),
Rule::cont => Ok(Self::Continue),
Rule::br => Ok(Self::Break),
Rule::expr => Ok(Self::Return(Some(Expression::take(pair)?))),
_ => Err(rule_mismatch!(pair))
}
}
else { Ok(Self::Return(None)) }
},
_ => Err(rule_mismatch!(pair,jump_stmt))
}
}
}