use std::{collections::VecDeque, fmt::Display};
use crate::{ccarp::error::{c2rust_err, safe_unwrap, unimpl_err, CCErr, Result}, ccarp_c::stmt::*};
use super::{defs::{print_vec, CastInto, Context, NoReturn, RFrom, RInto}, rustdecl::{form_unsafe_expr, RDecl, RType}, rustexpr::{RConstExpr, RExpr}};
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RStmt {
Compound(CompoundRStmt),
Expr(RExprStmt),
Selection(RSelectionStmt),
Iter(Option<RBlockItem>,RIterStmt),
Jump(RJumpStmt)
}
impl RFrom<Statement> for RStmt {
fn rfrom(value: Statement, context: &mut Context) -> Result<Self> {
match value {
Statement::Compound(compound_stmt) => Ok(Self::Compound(compound_stmt.rinto(context)?)),
Statement::Expr(expr_stmt) => Ok(Self::Expr(expr_stmt.rinto(context)?)),
Statement::Selection(selection_stmt) => Ok(Self::Selection(selection_stmt.rinto(context)?)),
Statement::Iter(iter_stmt) => {
let (block,iter)=iter_stmt.rinto(context)?;
Ok(Self::Iter(block,iter))
},
Statement::Jump(jump_stmt) => Ok(Self::Jump(jump_stmt.rinto(context)?)),
Statement::Labeled(_) => Err(unimpl_err!("Labeled Statements are unimplemented!")),
}
}
}
impl Display for RStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Compound(compound_rstmt) => write!(f,"{compound_rstmt}"),
Self::Expr(rexpr_stmt) => write!(f,"{rexpr_stmt}"),
Self::Selection(rselection_stmt) => write!(f,"{rselection_stmt}"),
Self::Iter(rblock_item, riter_stmt) => {
match rblock_item {
Some(item) => write!(f,"{item}\n{riter_stmt}"),
None => write!(f,"{riter_stmt}"),
}
},
Self::Jump(rjump_stmt) => write!(f,"{rjump_stmt}"),
}
}
}
fn remove_last_break_from_stmt(s: Statement) -> Option<Statement> {
match s {
Statement::Labeled(labeled_stmt) => {
match labeled_stmt {
LabeledStmt::Label(..) => Some(Statement::Labeled(labeled_stmt)),
LabeledStmt::Case(const_expr, statement) => {
let res=remove_last_break_from_stmt(*statement).unwrap_or(Statement::Compound(CompoundStmt(None)));
Some(Statement::Labeled(LabeledStmt::Case(const_expr, Box::new(res))))
},
LabeledStmt::Default(statement) => {
let res=remove_last_break_from_stmt(*statement).unwrap_or(Statement::Compound(CompoundStmt(None)));
Some(Statement::Labeled(LabeledStmt::Default(Box::new(res))))
},
}
},
Statement::Compound(compound_stmt) => {
match compound_stmt.0 {
Some(mut list) => {
if let Some(last)=list.0.pop() {
match last {
BlockItem::Decl(_) => list.0.push(last),
BlockItem::Stmt(statement) => {
if let Some(stmt)=remove_last_break_from_stmt(*statement) {
list.0.push(BlockItem::Stmt(Box::new(stmt)));
}
},
}
}
Some(Statement::Compound(CompoundStmt(Some(list))))
},
None => Some(Statement::Compound(compound_stmt)),
}
},
Statement::Jump(jump_stmt) => {
match jump_stmt {
JumpStmt::Break => None,
_ => Some(Statement::Jump(jump_stmt))
}
},
_ => Some(s)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RLabeledStmt {
Pattern(Vec<RConstExpr>,RStmt),
Default(RStmt)
}
impl RFrom<LabeledStmt> for RLabeledStmt {
fn rfrom(value: LabeledStmt, context: &mut Context) -> Result<Self> {
match value {
LabeledStmt::Label(..) => Err(unimpl_err!("Labeled Statements are unimplemented!")),
LabeledStmt::Case(const_expr, statement) => {
let mut pattern=vec![RConstExpr::rfrom(const_expr, context)?];
let mut q=VecDeque::new();
q.push_back(*statement);
let mut statement=None;
while let Some(stmt)=q.pop_front() {
match stmt {
Statement::Labeled(labeled_stmt) => {
match labeled_stmt {
LabeledStmt::Label(..) => return Err(unimpl_err!("Labeled Statements are unimplemented!")),
LabeledStmt::Case(const_expr, stmt) => {
pattern.push(RConstExpr::rfrom(const_expr, context)?);
q.push_back(*stmt);
},
LabeledStmt::Default(statement) => {
return Ok(Self::Default((*statement).rinto(context)?))
},
}
},
Statement::Compound(compound_stmt) => {
statement=Some(Statement::Compound(compound_stmt.clone()));
if let Some(list)=compound_stmt.0 {
for elem in list.0 {
match elem {
BlockItem::Decl(_) => break,
BlockItem::Stmt(statement) => q.push_back(*statement),
}
}
}
},
_ => {
statement=Some(stmt);
break;
}
}
}
let mut list=BlockItemList(vec![BlockItem::Stmt(Box::new(statement.unwrap_or(Statement::Compound(CompoundStmt(None)))))]);
for stmt in q {
list.0.push(BlockItem::Stmt(Box::new(stmt)));
}
Ok(Self::Pattern(pattern, Statement::Compound(CompoundStmt(Some(list))).rinto(context)?))
},
LabeledStmt::Default(statement) => {
Ok(Self::Default((*statement).rinto(context)?))
},
}
}
}
impl Display for RLabeledStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Pattern(items, rstmt) => write!(f,"{} => {rstmt},",print_vec(items, "|")),
Self::Default(rstmt) => write!(f,"_ => {rstmt},"),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CompoundRStmt(pub Option<RBlockItemList>);
impl RFrom<CompoundStmt> for CompoundRStmt {
fn rfrom(value: CompoundStmt, context: &mut Context) -> Result<Self> {
Ok(Self(value.0.map(|x| x.rinto(context)).transpose()?))
}
}
impl Display for CompoundRStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
Some(list) => write!(f,"{{\n{list}\n}}"),
None => write!(f,"{{}}"),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RBlockItemList(pub Vec<RBlockItem>);
impl RFrom<BlockItemList> for RBlockItemList {
fn rfrom(value: BlockItemList, context: &mut Context) -> Result<Self> {
let mut v=vec![];
for x in value.0 { v.push(x.rinto(context)?); }
Ok(Self(v))
}
}
impl Display for RBlockItemList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",print_vec(&self.0, "\n"))
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RBlockItem {
Decl(RDecl),
Stmt(Box<RStmt>)
}
impl RFrom<BlockItem> for RBlockItem {
fn rfrom(value: BlockItem, context: &mut Context) -> Result<Self> {
match value {
BlockItem::Decl(declaration) => Ok(Self::Decl(declaration.rinto(context)?)),
BlockItem::Stmt(statement) => Ok(Self::Stmt(Box::new((*statement).rinto(context)?))),
}
}
}
impl Display for RBlockItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Decl(rdecl) => write!(f,"{rdecl}"),
Self::Stmt(rstmt) => write!(f,"{rstmt}"),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RExprStmt(pub Option<RExpr>);
impl RFrom<ExprStmt> for RExprStmt {
fn rfrom(value: ExprStmt, context: &mut Context) -> Result<Self> {
Ok(Self(value.0.map(|x| RExpr::rfrom(x, context).map(NoReturn::simplify)).transpose()?))
}
}
impl Display for RExprStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
Some(expr) => write!(f,"{};",form_unsafe_expr(expr)),
None => write!(f,""),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RSelectionStmt {
If(RExpr,Box<RStmt>),
IfElse(RExpr,Box<RStmt>,Box<RStmt>),
Match(RExpr,Vec<RLabeledStmt>)
}
impl RFrom<SelectionStmt> for RSelectionStmt {
fn rfrom(value: SelectionStmt, context: &mut Context) -> Result<Self> {
match value {
SelectionStmt::If(expression, statement) => Ok(Self::If(RExpr::rfrom(expression, context)?.cast(&RType::Bool), Box::new((*statement).rinto(context)?))),
SelectionStmt::IfElse(expression, statement, statement1) => Ok(Self::IfElse(RExpr::rfrom(expression, context)?.cast(&RType::Bool), Box::new((*statement).rinto(context)?), Box::new((*statement1).rinto(context)?))),
SelectionStmt::Switch(expression, statement) => {
let rexpr=RExpr::rfrom(expression, context)?;
if let Statement::Compound(CompoundStmt(Some(list))) = *statement {
let mut arms=vec![];
let mut label_stmt: Option<LabeledStmt>=None;
for item in list.0 {
match &mut label_stmt {
Some(label) => {
match item {
BlockItem::Stmt(statement) => {
let breakless=remove_last_break_from_stmt(*statement.clone()).unwrap_or(Statement::Compound(CompoundStmt(None)));
if *statement==breakless { label.push_statement(breakless); }
else {
label.push_statement(breakless);
arms.push((safe_unwrap!(label_stmt;"Label Statement","Selection Statement")).rinto(context)?);
label_stmt=None;
}
},
BlockItem::Decl(decl) => label.push_declaration(decl),
}
},
None => {
if let BlockItem::Stmt(statement)=item {
if let Statement::Labeled(labeled_stmt) = *statement {
label_stmt=Some(labeled_stmt);
}
}
}
}
}
Ok(Self::Match(rexpr, arms))
}
else { Ok(Self::Match(rexpr, vec![])) }
},
}
}
}
impl Display for RSelectionStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::If(rexpr, rstmt) => write!(f,"if {} {{\n{rstmt}\n}}",form_unsafe_expr(rexpr)),
Self::IfElse(rexpr, rstmt, rstmt1) => {
write!(f,"if {} {{\n{rstmt}\n}} else {{\n{rstmt1}\n}}",form_unsafe_expr(rexpr))
},
Self::Match(rexpr, rlabeled_stmts) => write!(f,"match {} {{\n{}\n}}",form_unsafe_expr(rexpr),print_vec(rlabeled_stmts, "\n")),
}
}
}
macro_rules! embed_last_expr {
($expr:expr,$into:expr) => {
match &mut *$into {
Statement::Compound(compound_stmt) => {
if let Some(val)=&mut compound_stmt.0 {
val.0.push($expr);
}
else { compound_stmt.0=Some(BlockItemList(vec![$expr]))}
},
_ => {
$into=Box::new(Statement::Compound(CompoundStmt(Some(BlockItemList(vec![BlockItem::Stmt($into),$expr])))));
}
}
};
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RIterStmt {
While(RExpr,Box<RStmt>),
Loop(Box<RStmt>,Option<RExpr>)
}
impl RFrom<IterStmt> for (Option<RBlockItem>,RIterStmt) {
fn rfrom(value: IterStmt, context: &mut Context) -> Result<Self> {
match value {
IterStmt::While(expression, statement) => Ok((None,RIterStmt::While(RExpr::rfrom(expression, context)?.cast(&RType::Bool), Box::new((*statement).rinto(context)?)))),
IterStmt::DoWhile(statement, expression) => Ok((None,RIterStmt::Loop(Box::new((*statement).rinto(context)?), Some(RExpr::rfrom(expression, context)?.cast(&RType::Bool))))),
IterStmt::For(expression, expression1, expression2, mut statement) => {
let block=expression.map(|x| BlockItem::Stmt(Box::new(Statement::Expr(ExprStmt(Some(*x))))));
embed_last_expr!(BlockItem::Stmt(Box::new(Statement::Expr(ExprStmt(expression2.map(|x| *x))))),statement);
match expression1 {
Some(expr) => Ok((block.map(|x| x.rinto(context)).transpose()?,RIterStmt::While(RExpr::rfrom(*expr, context)?.cast(&RType::Bool), Box::new(RStmt::rfrom(*statement, context)?)))),
None => Ok((block.map(|x| x.rinto(context)).transpose()?,RIterStmt::Loop(Box::new(RStmt::rfrom(*statement, context)?),None))),
}
},
IterStmt::ForDecl(declaration, expression, expression1, mut statement) => {
let rust_decl=RDecl::rfrom(*declaration, context)?;
embed_last_expr!(BlockItem::Stmt(Box::new(Statement::Expr(ExprStmt(expression1.map(|x| *x))))),statement);
match expression {
Some(expr) => Ok((Some(RBlockItem::Decl(rust_decl)),RIterStmt::While((*expr).rinto(context)?, Box::new(RStmt::rfrom(*statement, context)?)))),
None => Ok((Some(RBlockItem::Decl(rust_decl)),RIterStmt::Loop(Box::new(RStmt::rfrom(*statement, context)?),None))),
}
},
}
}
}
impl Display for RIterStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::While(rexpr, rstmt) => write!(f,"while {} {{\n{rstmt}\n}}",form_unsafe_expr(rexpr)),
Self::Loop(rstmt, rexpr) => {
match rexpr {
Some(expr) => write!(f,"loop {{\n{rstmt}\nif (!{}) {{ break; }}\n}}",form_unsafe_expr(expr)),
None => write!(f,"loop {{\n{rstmt}\n}}"),
}
},
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RJumpStmt {
Continue,
Break,
Return(Option<RExpr>),
ExitcodeReturn(Option<RExpr>)
}
impl RFrom<JumpStmt> for RJumpStmt {
fn rfrom(value: JumpStmt, context: &mut Context) -> Result<Self> {
match value {
JumpStmt::Goto(_) => Err(unimpl_err!("Goto Statements are unimplemented!")),
JumpStmt::Continue => Ok(Self::Continue),
JumpStmt::Break => Ok(Self::Break),
JumpStmt::Return(expression) => {
if matches!(context.return_type,RType::Unit) { Ok(Self::Return(expression.map(|x| x.rinto(context)).transpose()?)) }
else if context.inside_main && context.return_type.is_numeric() {
Ok(Self::ExitcodeReturn(expression.map(|x| RExpr::rfrom(x, context).map(|y| y.cast(&RType::U8))).transpose()?))
}
else { Ok(Self::Return(expression.map(|x| RExpr::rfrom(x, context).map(|y| y.cast(&context.return_type))).transpose()?)) }
}
}
}
}
impl Display for RJumpStmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Continue => write!(f,"continue;"),
Self::Break => write!(f,"break;"),
Self::Return(rexpr) => {
match rexpr {
Some(expr) => write!(f,"return {};",form_unsafe_expr(expr)),
None => write!(f,"return;"),
}
},
Self::ExitcodeReturn(rexpr) => {
match rexpr {
Some(expr) => write!(f,"return std::process::ExitCode::from({});",form_unsafe_expr(expr)),
None => write!(f,"return std::process::ExitCode::from(0);"),
}
}
}
}
}