ccarp 0.1.2

(trans)Compile C And Rust Partially
Documentation
//! Rust Top Level Statements
//! 
//! This module contains definitions associated with C top level statements interpreted inside Rust.
//! 
//! Important definitions:
//! - `RTransUnit`, which signifies a C style Rust translation unit/program
//! - `RExtDecl`, which signifies a C style Rust external declaration
//! - `RFnDef`, which signifies a function definition
use std::{fmt::Display, mem::swap};

use crate::ccarp::error::{c2rust_err, unimpl_err, safe_remove, CCErr, Result};
use crate::ccarp::translator::CompilerFlags;

use crate::ccarp_c::decl::IdentifierList;
use crate::ccarp_c::{decl::{DeclPostfix, Declarator, DirectDeclarator, TypeQualifier},trans_unit::*, tt::Identifier};
use super::{defs::{print_vec, Context, RFrom, RInto}, rustdecl::{apply_decl_postfix_to_ty, Generic, Let, Qualifier, RDecl, RDeclSingle, RParam, RParamList, RType, TypeOrTypedef}, rustprimitives::RIdent, ruststmt::CompoundRStmt};

/// Rust Translation Unit
/// 
/// Signifies top level statements and consitst of External Declarations.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RTransUnit(pub Vec<RExtDecl>);
impl RFrom<TranslationUnit> for RTransUnit {
    fn rfrom(value: TranslationUnit,context: &mut Context) -> Result<Self> {
        let mut decls=vec![];
        for ext in value.0 {
            match ext {
                ExternalDeclaration::Fn(function_def) => {
                    let (decl,fun)=<(Option<RDecl>,RFnDef)>::rfrom(function_def, context)?;
                    if let Some(declaration)=decl { decls.push(RExtDecl::Decl(declaration)); }
                    decls.push(RExtDecl::Fn(Box::new(fun)));
                },
                ExternalDeclaration::Decl(declaration) => {
                    decls.push(RExtDecl::Decl(RDecl::rfrom(declaration, context)?));
                },
            }
        }
        Ok(Self(decls))
    }
}
impl Display for RTransUnit {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f,"{}",print_vec(&self.0, "\n"))
    }
}
impl RTransUnit {
    pub fn contains_main(&self) -> bool {
        self.0.iter().any(RExtDecl::contains_main)
    }
}

/// Rust External Declaration
/// 
/// Can be either:
/// - A Function Definition
/// - or a Declaration
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RExtDecl {
    Fn(Box<RFnDef>),
    Decl(RDecl)
}
impl Display for RExtDecl {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Fn(rfn_def) => write!(f,"{rfn_def}"),
            Self::Decl(rdecl) => write!(f,"{}",rdecl.print_without_fn_decl()),
        }
    }
}
impl RExtDecl {
    pub fn contains_main(&self) -> bool {
        match self {
            Self::Fn(rfn_def) => rfn_def.1.0.as_str()=="main",
            Self::Decl(_) => false,
        }
    }
}

/// Rust Function Definition
/// 
/// Consists of an optional Qualifier (inline or nothing), an Identifier (function name),
/// a List of Generics, a List of Arguments (or Parameters), a return Type and a Compound
/// Statement (body of the function).
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RFnDef(pub Option<Qualifier>, pub RIdent, pub Vec<Generic>, pub RParamList, pub RType, pub CompoundRStmt);
impl RFrom<FunctionDef> for (Option<RDecl>,RFnDef) {
    fn rfrom(value: FunctionDef, context: &mut Context) -> Result<Self> {
        let FunctionDef(specs,declarator,list,body)=value;
        if let TypeOrTypedef::A(ty,q)=TypeOrTypedef::rfrom(*specs, context)? {
            context.top_level=false;
            let (decl,mut param_list,rident,ty)=parameter_list_from_declarator(ty,*declarator,list.map(|x| *x),context)?;
            if rident.0.as_str()=="main" { context.inside_main=true; }
            context.return_type=ty.clone();
            if let RType::Typedef(_,def)=&context.return_type { context.return_type = *def.clone(); }
            let mut generics=vec![];
            for i in &mut param_list.0 {
                if let Some(val)=&i.1 {
                    context.scope.0.push(RDeclSingle::Let(Let(i.0,val.clone(),i.2.clone(),None)));
                }
                let mut tmp=RType::default();
                swap(&mut tmp, &mut i.2);
                i.2=tmp.transform(context.flags, &mut generics);
            }
            context.scope.0.push(RDeclSingle::Let(Let(Qualifier::Static, rident.clone(), RType::Function(param_list.0.iter().map(|x| x.2.clone()).collect(), Box::new(ty.clone())), None)));
            let body=(*body).rinto(context)?;
            context.inside_main=false;
            context.top_level=true;
            context.return_type=RType::Unit;
            Ok((decl,RFnDef(if matches!(q,Qualifier::Inline) { Some(q) } else { None },rident,generics,param_list,ty,body)))
        }
        else { Err(c2rust_err!("Tried to typedef the return type of a function definition!")) }
    }
}
impl Display for RFnDef {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self(q,ident,generics,params,ty,body)=self;
        let ty=
        if ident.0.as_str()=="main" && ty.is_numeric() { "std::process::ExitCode".to_string() }
        else { ty.to_string() };
        if generics.is_empty() {
            match q {
                Some(q) => write!(f,"{q}pub fn {ident}({}) -> {ty} {body}",params.print_fn_params()),
                None => write!(f,"pub fn {ident}({}) -> {ty} {body}",params.print_fn_params()),
            }
        }
        else {
            match q {
                Some(q) => write!(f,"{q}pub fn {ident}<{}>({}) -> {ty} {body}",print_vec(generics, ", "),params.print_fn_params()),
                None => write!(f,"pub fn {ident}<{}>({}) -> {ty} {body}",print_vec(generics, ", "),params.print_fn_params()),
            }
        }
    }
}

fn get_ident_and_ret_ty(direct: DirectDeclarator,mut ret_ty: RType,postfix: &mut Vec<DeclPostfix>, flags: CompilerFlags) -> (Identifier,RType) {
    match direct {
        DirectDeclarator::Ident(identifier, mut items) => {
            items.reverse();
            postfix.append(&mut items);
            (identifier,ret_ty)
        },
        DirectDeclarator::Decl(mut declarator, mut items) => {
            items.reverse();
            postfix.append(&mut items);
            let ident;
            loop {
                if let Some(pointer)=declarator.0 {
                    for i in pointer.0 {
                        match i {
                            Some(ty) => {
                                ret_ty=
                                if ty.0.contains(&TypeQualifier::Const) { ret_ty.unsized_array(flags) }
                                else { ret_ty.unsized_array_mut(flags) }
                            },
                            None => ret_ty=ret_ty.unsized_array_mut(flags),
                        }
                    }
                }
                match *declarator.1 {
                    DirectDeclarator::Ident(identifier, mut items) => {
                        items.reverse();
                        postfix.append(&mut items);
                        ident=identifier;
                        break;
                    },
                    DirectDeclarator::Decl(decl, mut items) => {
                        items.reverse();
                        postfix.append(&mut items);
                        declarator=decl;
                    },
                }
            }
            (ident,ret_ty)
        },
    }
}

fn ident_list(identifier_list: Option<IdentifierList>, r_decl_let: &[Let], decl: Option<RDecl>, ident: RIdent, ret_ty: RType) -> Result<(Option<RDecl>,RParamList,RIdent,RType)> {
    let mut params=vec![];
    match identifier_list {
        Some(list) => {
            for ident in list.0 {
                let rident=RIdent::from(ident);
                if let Some((q,ty))=r_decl_let.iter().find(|x| x.1==rident).map(|x| (x.0,x.2.clone())) {
                    params.push(RParam(q,Some(rident),ty));
                }
                else { return Err(c2rust_err!("Identifier '{rident}' inside identifier list does not have an accessible type!")) }
            }
            Ok((decl,RParamList(params),ident,ret_ty))
        },
        None => Ok((decl,RParamList(params),ident,ret_ty)),
    }
}

fn parameter_list_from_declarator(ret_ty: RType, decl: Declarator, list: Option<DeclarationList>, context: &mut Context) -> Result<(Option<RDecl>,RParamList,RIdent,RType)> {
    let mut postfix=vec![];
    let mut tmp =vec![];
    for x in list.unwrap_or(DeclarationList(vec![])).0 {
        tmp.push(RDecl::rfrom(x, context)?);
    }
    let mut r_decl_let=vec![];
    let mut r_decls=vec![];
    for decl in tmp {
        for d in decl.0 {
            match d {
                RDeclSingle::Let(let_) => r_decl_let.push(let_),
                _ => r_decls.push(d),
            }
        }
    }
    let (ident,mut ret_ty)=get_ident_and_ret_ty(*decl.1,ret_ty,&mut postfix,context.flags);
    postfix.iter().position(|x| matches!(x,DeclPostfix::Param(_)|DeclPostfix::IdentList(_))).map_or_else(|| Err(c2rust_err!("Function lacks a valid argument list!")), |pos| {
        let params=safe_remove(&mut postfix, pos, c2rust_err!("Found argument list outside the bounds of its container in function declaration!"))?;
        for item in postfix {
            ret_ty=apply_decl_postfix_to_ty(item, ret_ty, context)?;
        }
        let ident=RIdent::from(ident);
        let decl=if r_decls.is_empty() { None } else { Some(RDecl(r_decls)) };
        match params {
            DeclPostfix::Param(parameter_type_list) => {
                let params=RParamList::rfrom(parameter_type_list.clone(), context);
                if let Ok(params)=params { Ok((decl,params,ident,ret_ty)) }
                else { ident_list(Some(parameter_type_list.into()),&r_decl_let,decl,ident,ret_ty) }
            },
            DeclPostfix::IdentList(identifier_list) => ident_list(identifier_list,&r_decl_let,decl,ident,ret_ty),
            _ => Err(unimpl_err!("Unreachable!"))
        }
    })
}