use std::{fmt::Display, mem::swap};
use crate::ccarp::error::{c2rust_err, safe_unwrap, unimpl_err, safe_remove, CCErr, Result};
use crate::ccarp::translator::CompilerFlags;
use crate::ccarp_c::{decl::*,tt::Identifier};
use super::defs::sum;
use super::{defs::{print_vec, print_vec2, CastInto, Context, Eval, IsUnsafe, RFrom, RInto}, rustexpr::{RConstExpr, RExpr}, rustprimitives::RIdent};
fn sep_declaration_and_ty(ty: RType) -> (Vec<RDeclSingle>,RType) {
macro_rules! sep {
($ty:expr,$id:ident) => {
{
let (decl,ty)=sep_declaration_and_ty(*$ty);
(decl,RType::$id(Box::new(ty)))
}
};
}
match ty {
RType::Ref(generics,rtype) => {
let (decl,ty)=sep_declaration_and_ty(*rtype);
(decl,RType::Ref(generics,Box::new(ty)))
},
RType::RefMut(generics,rtype) => {
let (decl,ty)=sep_declaration_and_ty(*rtype);
(decl,RType::RefMut(generics,Box::new(ty)))
},
RType::Point(rtype) => sep!(rtype, Point),
RType::PointMut(rtype) => sep!(rtype, PointMut),
RType::ThinPoint(rtype) => sep!(rtype, ThinPoint),
RType::ThinPointMut(rtype) => sep!(rtype, ThinPointMut),
RType::ThinRef(generics,rtype) => {
let (decl,ty)=sep_declaration_and_ty(*rtype);
(decl,RType::ThinRef(generics,Box::new(ty)))
},
RType::ThinRefMut(generics,rtype) => {
let (decl,ty)=sep_declaration_and_ty(*rtype);
(decl,RType::ThinRefMut(generics,Box::new(ty)))
},
RType::GenericArray(rtype, generics) => {
let (decl,ty)=sep_declaration_and_ty(*rtype);
(decl,RType::GenericArray(Box::new(ty),generics))
},
RType::UnsizedArray(rtype) => sep!(rtype, UnsizedArray),
RType::Array(rtype, expr) => {
let (decl,ty)=sep_declaration_and_ty(*rtype);
(decl,RType::Array(Box::new(ty),expr))
},
RType::EnumDecl(enum_decl, rident) => {
(vec![RDeclSingle::Enum(*enum_decl)],RType::Enum(rident))
},
RType::StructDecl(struct_decl, rident) => {
(vec![RDeclSingle::Struct(*struct_decl)],RType::Struct(rident))
},
RType::UnionDecl(struct_decl, rident) => {
(vec![RDeclSingle::Struct(*struct_decl)],RType::Union(rident))
},
RType::Function(rtypes, rtype) => {
let (mut decls,ret_ty)=sep_declaration_and_ty(*rtype);
let args=rtypes.into_iter().map(|x| { let (mut decl,ty)=sep_declaration_and_ty(x); decls.append(&mut decl); ty }).collect::<Vec<_>>();
(decls,RType::Function(args, Box::new(ret_ty)))
},
_ => (vec![],ty)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RDecl(pub Vec<RDeclSingle>);
impl Display for RDecl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",print_vec(&self.0, "\n"))
}
}
impl RDecl {
pub fn print_without_fn_decl(&self) -> String {
print_vec2(&self.0,RDeclSingle::print_without_fn_decl, "\n")
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RDeclSingle {
Typedef(RTypedef),
Enum(EnumDecl),
Struct(StructDecl),
Let(Let)
}
impl RFrom<Declaration> for RDecl {
fn rfrom(value: Declaration, context: &mut Context) -> Result<Self> {
let ty=TypeOrTypedef::rfrom(value.0,context)?;
let (ty,q)=
match ty {
TypeOrTypedef::A(rtype, qualifier) => (rtype,Some(qualifier)), TypeOrTypedef::B(rtype) => (rtype,None), };
let (mut out,ty)=sep_declaration_and_ty(ty);
let clone=context.clone();
context.scope.0.append(&mut out.clone());
if let Some(init) = value.1 {
for i in init.0 {
match i {
InitDeclarator::Decl(declarator) => {
let (mut ty,ident)=type_from_decl(ty.clone(), q.unwrap_or_default(), *declarator, context)?;
if let RType::UnsizedArray(arr_ty)=ty { ty=arr_ty.refer_mut(context.flags); }
match q {
Some(qualifier) => out.push(RDeclSingle::Let(Let(qualifier, ident, ty, None))),
None => out.push(RDeclSingle::Typedef(RTypedef(ident, ty))),
}
},
InitDeclarator::Assign(declarator, initialiser) => {
let (mut ty,ident)=type_from_decl(ty.clone(), q.unwrap_or_default(), *declarator,context)?;
match initialiser {
Initialiser::Assign(assignment_expr) => {
let expr=RExpr::Expr(Box::new(assignment_expr.rinto(context)?)).cast(&ty);
out.push(RDeclSingle::Let(Let(safe_unwrap!(q;"Qualifier","Let Statement"), ident, ty, Some(Box::new(RInit::Expr(expr))))));
},
Initialiser::Init(initialiser_list) => {
if let RType::UnsizedArray(arr_ty)=ty { ty=RType::Array(arr_ty,Box::new(RExpr::from(initialiser_list.0.len()))); }
let init=RInit::rfrom((*initialiser_list,ty.clone()), context)?.cast(&ty);
out.push(RDeclSingle::Let(Let(safe_unwrap!(q;"Qualifier","Let Statement"), ident, ty, Some(Box::new(init)))));
},
}
},
}
}
*context=clone;
context.scope.0.append(&mut out.clone());
}
Ok(Self(out))
}
}
impl Display for RDeclSingle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Typedef(rtypedef) => write!(f,"{rtypedef}"),
Self::Enum(enum_decl) => write!(f,"{enum_decl}"),
Self::Struct(struct_decl) => write!(f,"{struct_decl}"),
Self::Let(let_) => write!(f,"{let_}"),
}
}
}
impl RDeclSingle {
pub fn print_without_fn_decl(&self) -> String {
match self {
Self::Let(let_) => {
match &let_.2 {
RType::Function(..) => String::new(),
_ => format!("{let_}")
}
},
_ => format!("{self}")
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RTypedef(pub RIdent, pub RType);
impl Display for RTypedef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"type {}={};",self.0,self.1)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct REnumConst(pub RIdent);
impl RFrom<EnumConst> for REnumConst {
fn rfrom(value: EnumConst, _context: &mut Context) -> Result<Self> {
Ok(Self(value.0.into()))
}
}
impl Display for REnumConst {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",self.0)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum REnumerator {
Const(REnumConst),
Val(REnumConst,RConstExpr)
}
impl RFrom<Enumerator> for REnumerator {
fn rfrom(value: Enumerator, context: &mut Context) -> Result<Self> {
match value {
Enumerator::Const(enum_const) => Ok(Self::Const(enum_const.rinto(context)?)),
Enumerator::ConstWithVal(enum_const, const_expr) => Ok(Self::Val(enum_const.rinto(context)?, (*const_expr).rinto(context)?)),
}
}
}
impl Display for REnumerator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Const(renum_const) => write!(f,"{renum_const}"),
Self::Val(renum_const, rternary) => write!(f,"{renum_const}={rternary}"),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct EnumDecl(pub RIdent,pub Vec<REnumerator>);
impl RFrom<EnumSpecifier> for RType {
fn rfrom(value: EnumSpecifier, context: &mut Context) -> Result<Self> {
match value {
EnumSpecifier::Full(identifier, enumerator_list) => {
let ident=identifier.unwrap_or_else(|| Identifier(context.new_nameless_enum()));
let mut enum_list=vec![];
for x in enumerator_list.0 { enum_list.push(x.rinto(context)?); }
let decl=EnumDecl(ident.clone().into(), enum_list);
Ok(Self::EnumDecl(Box::new(decl),ident.into()))
},
EnumSpecifier::Decl(identifier) => Ok(Self::Enum(identifier.into()))
}
}
}
impl Display for EnumDecl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]\nenum {} {{ \n#[default]\n{} }}\nuse {0}::*;",self.0,print_vec(&self.1, ",\n"))
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Generic {
Type(String),
Const(String,Box<RType>),
Lifetime(String)
}
impl Display for Generic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Type(s) => write!(f,"{s}"),
Self::Const(s, rtype) => write!(f,"const {s}: {rtype}"),
Self::Lifetime(s) => write!(f,"'{s}")
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct StructDecl(pub StructOrUnion, pub RIdent, pub Vec<Generic>, pub Vec<RStructDeclaration>);
impl RFrom<StructSpecifier> for RType {
fn rfrom(value: StructSpecifier, context: &mut Context) -> Result<Self> {
match value {
StructSpecifier::Full(struct_or_union, ident, struct_declaration_list) => {
let ident: RIdent=ident.unwrap_or_else(|| Identifier(
match struct_or_union {
StructOrUnion::Struct => context.new_nameless_struct(),
StructOrUnion::Union => context.new_nameless_union(),
}
)).into();
let mut list: Vec<RStructDeclaration>=vec![];
for x in struct_declaration_list.0 { list.push(x.rinto(context)?); }
let mut generics=vec![];
for decl in &mut list {
for (_,x) in &mut decl.0 {
let mut tmp=Self::default();
swap(&mut tmp, x);
tmp=tmp.transform(context.flags, &mut generics);
*x=tmp.add_lifetime_to_refs(&mut generics);
}
}
let decl=StructDecl(struct_or_union, ident.clone(), generics, list);
match struct_or_union {
StructOrUnion::Struct => Ok(Self::StructDecl(Box::new(decl),ident)),
StructOrUnion::Union => Ok(Self::UnionDecl(Box::new(decl),ident)),
}
},
StructSpecifier::Decl(struct_or_union, ident) => {
match struct_or_union {
StructOrUnion::Struct => Ok(Self::Struct(ident.into())),
StructOrUnion::Union => Ok(Self::Union(ident.into())),
}
},
}
}
}
impl Display for StructDecl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let derive=format!(
"#[derive({}{}{})]\n",
if matches!(self.0,StructOrUnion::Struct) && !self.3.iter().any(|x| x.0.iter().any(|y| matches!(y.1.clone().get_type_alias(),RType::Union(_)))) { "Debug,PartialEq,Eq," } else { "" },
if matches!(self.0,StructOrUnion::Struct) && self.3.iter().all(|x| x.0.iter().all(|y| y.1.can_derive_default())) { "Default," } else { "" },
if self.3.iter().all(|x| x.0.iter().all(|y| y.1.can_derive_clone())) { "Clone,Copy" } else { "" }
);
if self.2.is_empty() { write!(f,"{derive}pub {} {} {{\n{}\n}}",self.0,self.1,print_vec(&self.3, ",\n")) }
else { write!(f,"{derive}pub {} {}<{}> {{\n{}\n}}",self.0,self.1,print_vec(&self.2, ", "),print_vec(&self.3, ",\n")) }
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RStructDeclaration(pub Vec<(RIdent,RType)>);
impl RFrom<StructDeclaration> for RStructDeclaration {
fn rfrom(value: StructDeclaration, context: &mut Context) -> Result<Self> {
let mut out=vec![];
let (ty,q)=<(RType,Qualifier)>::rfrom(*value.0,context)?;
for i in value.1.0 {
match i {
StructDeclarator::Decl(declarator)|StructDeclarator::Const(Some(declarator), _)=> {
let (ty,ident)=type_from_decl(ty.clone(), q, *declarator, context)?;
out.push((ident,ty));
},
StructDeclarator::Const(..) => {}, }
}
Ok(Self(out))
}
}
impl Display for RStructDeclaration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",print_vec2(&self.0,|x| format!("{}: {}",x.0,x.1), ",\n"))
}
}
fn pointerise(pointer: Pointer, qualif: Qualifier, ty: &mut RType, flags: CompilerFlags) {
for p in pointer.0 {
let mut tmp=RType::default();
swap(&mut tmp, ty);
*ty =
match p {
Some(q) => {
if q.0.contains(&TypeQualifier::Const) {
match qualif {
Qualifier::Static|Qualifier::Const|Qualifier::ExternStatic => tmp.refer(flags),
_ => tmp.refer_mut(flags)
}
}
else {
match qualif {
Qualifier::Static|Qualifier::Const|Qualifier::ExternStatic => tmp.point(flags),
_ => tmp.point_mut(flags)
}
}
},
None => {
match qualif {
Qualifier::Static|Qualifier::Const|Qualifier::ExternStatic => tmp.point(flags),
_ => tmp.point_mut(flags)
}
},
}
}
}
#[allow(clippy::missing_errors_doc)]
pub fn apply_decl_postfix_to_ty(postfix: DeclPostfix, mut rtype: RType, context: &mut Context) -> Result<RType> {
match postfix {
DeclPostfix::Opt(_, assignment_expr) => {
match assignment_expr {
Some(assign) => rtype=RType::Array(Box::new(rtype), Box::new(RExpr::Expr(Box::new((*assign).rinto(context)?)))),
None => rtype=RType::UnsizedArray(Box::new(rtype)),
}
},
DeclPostfix::Static(_, assign) => rtype=RType::Array(Box::new(rtype), Box::new(RExpr::Expr(Box::new((*assign).rinto(context)?)))),
DeclPostfix::Point(_) => rtype=RType::UnsizedArray(Box::new(rtype)),
DeclPostfix::Param(args) => {
rtype=RType::Function(RParamList::rfrom(args,context)?.0.into_iter().map(|x| x.2).collect(), Box::new(rtype));
},
DeclPostfix::IdentList(list) => {
match list {
Some(ident) => return Err(unimpl_err!("Full type information cannot be derived from old C style function definition '{ident:?}'!")), None => rtype=RType::Function(vec![], Box::new(rtype)),
}
},
}
Ok(rtype)
}
fn type_from_decl(mut rtype: RType, qualif: Qualifier, mut declarator: Declarator, context: &mut Context) -> Result<(RType,RIdent)> {
let mut postfix=vec![];
let ident;
loop {
if let Some(point)=declarator.0 {
pointerise(point, qualif,&mut rtype,context.flags);
}
match *declarator.1 {
DirectDeclarator::Ident(identifier, mut items) => {
ident=identifier.into();
items.reverse();
postfix.append(&mut items);
for i in postfix.into_iter().rev() {
rtype=apply_decl_postfix_to_ty(i, rtype, context)?;
}
break;
},
DirectDeclarator::Decl(decl, mut items) => {
declarator = *decl;
items.reverse();
postfix.append(&mut items);
},
}
}
Ok((rtype,ident))
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RParam(pub Qualifier, pub Option<RIdent>, pub RType);
impl RFrom<ParameterDeclaration> for RParam {
fn rfrom(value: ParameterDeclaration, context: &mut Context) -> Result<Self> {
let qual;
let mut rtype;
match value {
ParameterDeclaration::Decl(declaration_specifiers, declarator) => {
if let TypeOrTypedef::A(ty, q)=declaration_specifiers.rinto(context)? {
qual=q;
let (ty,ident)=type_from_decl(ty, qual, *declarator, context)?;
Ok(Self(qual,Some(ident),ty))
}
else { Err(c2rust_err!("Cannot create type from typedef declaration!")) } },
ParameterDeclaration::Abstract(declaration_specifiers, mut abstract_declarator) => {
if let TypeOrTypedef::A(ty, q)=declaration_specifiers.rinto(context)? {
rtype=ty;
qual=q;
let mut postfix=vec![];
while let Some(decl)=abstract_declarator {
match *decl {
AbstractDeclarator::Pointer(pointer) => {
pointerise(pointer,qual,&mut rtype,context.flags);
break
},
AbstractDeclarator::Direct(pointer, direct_abstract_declarator) => {
if let Some(p)=pointer { pointerise(p,qual,&mut rtype,context.flags); }
match *direct_abstract_declarator {
DirectAbstractDeclarator::Abstract(decl) => abstract_declarator=Some(decl),
DirectAbstractDeclarator::Post(decl, mut items) => {
abstract_declarator=decl;
items.reverse();
postfix.append(&mut items);
},
}
},
}
}
for i in postfix.into_iter().rev() {
match i {
DirectAbstractDeclaratorPostfix::Parent(args) => {
match args {
Some(params) => {
rtype=RType::Function(RParamList::rfrom(params,context)?.0.into_iter().map(|x| x.2).collect(), Box::new(rtype));
},
None => rtype=RType::Function(vec![], Box::new(rtype)),
}
},
DirectAbstractDeclaratorPostfix::Assign(assignment_expr) => {
if let Some(assign)=assignment_expr { rtype=RType::Array(Box::new(rtype), Box::new(RExpr::Expr(Box::new(assign.rinto(context)?)))) }
else { rtype=RType::UnsizedArray(Box::new(rtype)) }
},
DirectAbstractDeclaratorPostfix::Pointer => rtype=RType::UnsizedArray(Box::new(rtype)),
}
}
Ok(Self(qual,None,rtype))
}
else { Err(c2rust_err!("Cannot make Rust parameter from typedef!")) } },
}
}
}
impl Display for RParam {
#[allow(clippy::or_fun_call)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.1.as_ref().map_or(write!(f,"{} <MISSING>: {}",self.0,self.2), |ident| write!(f,"{} {ident}: {}",self.0,self.2))
}
}
impl RParam {
pub fn print_fn_params(&self) -> String {
#[allow(clippy::or_fun_call)]
self.1.as_ref().map_or(format!("{} <MISSING>: {}",self.0.print_fn_params(),self.2), |ident| format!("{} {ident}: {}",self.0.print_fn_params(),self.2))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RParamList(pub Vec<RParam>);
impl RFrom<ParameterList> for RParamList {
fn rfrom(value: ParameterList, context: &mut Context) -> Result<Self> {
let mut v=vec![];
for x in value.0 { v.push(x.rinto(context)?); }
Ok(Self(v))
}
}
impl RFrom<ParameterTypeList> for RParamList {
fn rfrom(value: ParameterTypeList, context: &mut Context) -> Result<Self> {
match value {
ParameterTypeList::List(list)|ParameterTypeList::TripleDot(list) => list.rinto(context),
}
}
}
impl Display for RParamList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",print_vec(&self.0, ","))
}
}
impl RParamList {
pub fn print_fn_params(&self) -> String {
print_vec2(&self.0, RParam::print_fn_params, ",")
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Let(pub Qualifier,pub RIdent,pub RType,pub Option<Box<RInit>>);
impl Display for Let {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.3 {
Some(init) => match self.2 {
RType::Struct(_)|RType::Union(_) => write!(f,"{} {}={};",self.0,self.1,init),
_ => write!(f,"{}{} {}: {}={};",if matches!(self.0,Qualifier::Static|Qualifier::StaticMut|Qualifier::ExternStatic|Qualifier::ExternStaticMut) {"pub "} else {""},self.0,self.1,self.2,init)
},
None => {
if matches!(self.0,Qualifier::Static|Qualifier::StaticMut|Qualifier::ExternStatic|Qualifier::ExternStaticMut) { write!(f,"pub {} {}: {}={};",self.0,self.1,self.2,print_default(&self.2))}
else { write!(f,"{} {}: {};",self.0,self.1,self.2) }
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RInit {
Expr(RExpr),
Array(Vec<RInit>, RType),
Struct(RIdent,Vec<(RIdent,RInit)>),
Union(RIdent,(RIdent,Box<RInit>)),
Default(RType)
}
impl RFrom<(Initialiser,RType)> for RInit {
fn rfrom(value: (Initialiser,RType), context: &mut Context) -> Result<Self> {
match value.0 {
Initialiser::Assign(assignment_expr) => Ok(Self::Expr(RExpr::Expr(Box::new(assignment_expr.rinto(context)?)))),
Initialiser::Init(initialiser_list) => Self::rfrom((*initialiser_list,value.1),context),
}
}
}
#[allow(clippy::cast_sign_loss)]
fn initlist_array(rtype: RType, rexpr: RExpr, v: InitialiserList, context: &mut Context) -> Result<RInit> {
let size=rexpr.eval(context).unwrap_or(100) as usize;
let mut out=vec![RInit::Default(rtype.clone());size];
let mut idx=0;
for des_init in v.0 {
if let Some(mut des) = des_init.0 {
if des.0.0.is_empty() {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list! Index is '{idx}' but size is only '{size}'!")) }
out[idx]=(des_init.1,rtype.clone()).rinto(context)?;
}
else {
let fst=des.0.0.remove(0);
match fst {
Designator::Const(const_expr) => {
idx=RConstExpr::rfrom(const_expr,context)?.eval(context)? as usize;
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list! Index is '{idx}' but size is only '{size}'!")) }
out[idx]=(InitialiserList(vec![(Some(des),des_init.1)]),rtype.clone()).rinto(context)?;
},
Designator::Ident(ident) => return Err(c2rust_err!("Tried to use identifier '{ident}' as Array declarator!")),
}
}
} else {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list! Index is '{idx}' but size is only '{size}'!")) }
out[idx]=(des_init.1,rtype.clone()).rinto(context)?;
}
idx+=1;
}
Ok(RInit::Array(out,RType::Array(Box::new(rtype), Box::new(rexpr))))
}
fn index<T: PartialEq>(slice: &[T], elem: &T) -> Option<usize> {
for (i,item) in slice.iter().enumerate() {
if item==elem { return Some(i) }
}
None
}
fn initlist_struct(rident: RIdent, v: InitialiserList, context: &mut Context) -> Result<RInit> {
let fields=context.get_struct_fields(&rident.0).into_iter().map(|x| (x.0.to_string(),x.1.clone())).collect::<Vec<_>>();
let mut out: Vec<(RIdent,RInit)>=vec![];
for field in &fields {
out.push((RIdent(field.0.clone()),RInit::Default(field.1.clone())));
}
let size=out.len();
let mut idx=0;
for des_init in v.0 {
if let Some(mut des) = des_init.0 {
if des.0.0.is_empty() {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of struct '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out[idx].1=(des_init.1,fields[idx].1.clone()).rinto(context)?;
}
else {
let fst=des.0.0.remove(0);
match fst {
Designator::Ident(identifier) => {
let ident=RIdent::from(identifier);
let found=index(&fields.iter().map(|x| &x.0).collect::<Vec<_>>(), &&ident.0);
if let Some(i)=found {
idx=i;
let ty=fields[i].1.clone();
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of struct '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out[idx]=(ident,RInit::rfrom((InitialiserList(vec![(Some(des),des_init.1)]),ty),context)?);
}
else {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of struct '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out[idx].1=RInit::rfrom((InitialiserList(vec![(Some(des),des_init.1)]),fields[idx].1.clone()),context)?;
}
},
Designator::Const(con) => return Err(c2rust_err!("Tried to use constant expression '{con:?}' as Struct declarator!")),
}
}
} else {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of struct '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out[idx].1=(des_init.1,fields[idx].1.clone()).rinto(context)?;
}
idx+=1;
}
Ok(RInit::Struct(rident, out))
}
fn initlist_union(rident: RIdent, v: InitialiserList, context: &mut Context) -> Result<RInit> {
let fields=context.get_struct_fields(&rident.0).into_iter().map(|x| (x.0.to_string(),x.1.clone())).collect::<Vec<_>>();
if fields.is_empty() { return Err(c2rust_err!("Union fields of union '{rident}' cannot be empty!")) }
let mut out=(RIdent(fields[0].0.clone()),RInit::Default(fields[0].1.clone()));
let size=fields.len();
let mut idx=0;
for des_init in v.0 {
if let Some(mut des) = des_init.0 {
if des.0.0.is_empty() {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of union '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out=(RIdent(fields[idx].0.clone()),(des_init.1,fields[idx].1.clone()).rinto(context)?);
}
else {
let fst=safe_remove(&mut des.0.0, 0, c2rust_err!("Designator list cannot be empty inside initialiser list of union '{rident}'!"))?;
match fst {
Designator::Ident(identifier) => {
let ident=RIdent::from(identifier);
let found=index(&fields.iter().map(|x| &x.0).collect::<Vec<_>>(), &&ident.0);
if let Some(i)=found {
idx=i;
let ty=fields[i].1.clone();
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of union '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out=(ident,RInit::rfrom((InitialiserList(vec![(Some(des),des_init.1)]),ty),context)?);
}
else {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of union '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out=(RIdent(fields[idx].0.clone()),RInit::rfrom((InitialiserList(vec![(Some(des),des_init.1)]),fields[idx].1.clone()),context)?);
}
},
Designator::Const(con) => return Err(c2rust_err!("Tried to use constant expression '{con:?}' as Union declarator!")),
}
}
} else {
if idx>=size { return Err(c2rust_err!("Overindexing in initialiser list of union '{rident}'! Index is '{idx}' but size is only '{size}'!")) }
out=(RIdent(fields[idx].0.clone()),(des_init.1,fields[idx].1.clone()).rinto(context)?);
}
idx+=1;
}
Ok(RInit::Union(rident, (out.0,Box::new(out.1))))
}
impl RFrom<(InitialiserList,RType)> for RInit {
fn rfrom(value: (InitialiserList,RType), context: &mut Context) -> Result<Self> {
let lhs=value.1.get_type_alias();
match lhs {
RType::Array(rtype, rexpr) => initlist_array(*rtype, *rexpr, value.0, context),
RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _)|RType::Point(rtype)|RType::PointMut(rtype)|
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::ThinPoint(rtype)|RType::ThinPointMut(rtype)|
RType::ThinRef(_,rtype)|RType::ThinRefMut(_,rtype) => initlist_array(*rtype, RExpr::from(value.0.0.len()), value.0, context),
RType::Struct(rident) => initlist_struct(rident, value.0, context),
RType::Union(rident) => initlist_union(rident, value.0, context),
_ => {
let last=safe_unwrap!(value.0.0.first();"Initialiser List","Initialiser").1.clone();
(last,RType::Unit).rinto(context)
}
}
}
}
impl Display for RInit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Expr(rexpr) => write!(f,"{}",form_unsafe_expr(rexpr)),
Self::Array(rinits,_) => write!(f,"[{}]",print_vec(rinits, ",")),
Self::Struct(rident, items) => write!(f,"{rident} {{ {} }}",print_vec2(items, |x| format!("{}: ({})",x.0,x.1), ",")),
Self::Union(rident, item) => write!(f,"{rident} {{ {}: ({}) }}",item.0,item.1),
Self::Default(rtype) => write!(f,"{}",print_default(rtype)),
}
}
}
pub fn form_unsafe_expr(rexpr: &RExpr) -> String {
if rexpr.is_unsafe() { format!("unsafe {{ ({rexpr}) }}") }
else { format!("({rexpr})") }
}
fn print_default(mut rtype: &RType) -> String {
if let RType::Typedef(_, ty)=rtype { rtype=ty; }
match rtype {
RType::Bool => "false".to_string(),
RType::Unit => "()".to_string(),
RType::ThinPoint(_) => "std::ptr::null()".to_string(),
RType::ThinPointMut(_) => "std::ptr::null_mut()".to_string(),
RType::ThinRef(_,rtype) => format!("&{}",print_default(rtype)),
RType::ThinRefMut(_,rtype) => format!("&mut {}",print_default(rtype)),
RType::Point(_)|RType::Ref(..) => "&[]".to_string(),
RType::PointMut(_)|RType::RefMut(..) => "&mut []".to_string(),
RType::Array(rtype,expr) => {
expr.eval(&Context::default()).map_or_else(|_| "Default::default".to_string(), |val| format!("[{};{}]",print_default(rtype),val))
}
RType::Enum(_)|RType::Struct(_)|RType::Union(_) => "Default::default()".to_string(),
RType::Function(..)|RType::EnumDecl(..)|RType::StructDecl(..)|RType::UnionDecl(..)|RType::Typedef(..) => String::new(), RType::F32|RType::F64 => "0.0".to_string(),
_ => "0".to_string()
}
}
#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub enum RType {
#[default] Unit,
I8, U8, I16, U16, I32, U32, I64, U64, I128, U128, Isize, Usize, F32, F64, BoolI8, Bool,
Ref(Vec<Generic>,Box<RType>), RefMut(Vec<Generic>,Box<RType>), Point(Box<RType>), PointMut(Box<RType>),
ThinRef(Vec<Generic>,Box<RType>), ThinRefMut(Vec<Generic>,Box<RType>), ThinPoint(Box<RType>), ThinPointMut(Box<RType>),
Array(Box<RType>,Box<RExpr>), UnsizedArray(Box<RType>), GenericArray(Box<RType>,Generic),
EnumDecl(Box<EnumDecl>,RIdent), StructDecl(Box<StructDecl>,RIdent),UnionDecl(Box<StructDecl>,RIdent),
Typedef(RIdent,Box<RType>), Function(Vec<RType>,Box<RType>),
Enum(RIdent), Struct(RIdent),Union(RIdent)
}
impl RFrom<SpecifierQualifierList> for (RType,Qualifier) {
fn rfrom(value: SpecifierQualifierList, context: &mut Context) -> Result<Self> {
use TypeSpecifier::*;
use RType::*;
let mut ty=Unit;
let mut q=if context.top_level {Qualifier::StaticMut} else {Qualifier::Mut};
let mut specs=vec![];
for v in value.0 {
match v {
SpecifierQualifier::Spec(type_specifier) => specs.push(type_specifier),
SpecifierQualifier::Typedef(typedef_name) => {
let ident: RIdent=typedef_name.0.into();
let alias=context.get_typedef_alias(&ident.0);
ty=RType::Typedef(ident,Box::new(safe_unwrap!(alias;"Type Alias","SpecifierQualifierList")));
},
SpecifierQualifier::Qualif(type_qualifier) => {
match type_qualifier {
TypeQualifier::Const => q=if context.top_level {Qualifier::Static} else {Qualifier::Const},
TypeQualifier::Restrict|TypeQualifier::Volatile => {}, }
},
}
}
if ty==Unit {
ty =
if specs.contains(&Void) { Unit }
else if specs.contains(&TypeSpecifier::Bool) { BoolI8 }
else if specs.contains(&Char) { if specs.contains(&Signed) { I8 } else { U8 } }
else if specs.contains(&Short) { if specs.contains(&Unsigned) { U16 } else { I16 } }
else if specs.contains(&Complex) { return Err(unimpl_err!("Complex types are unimplemented!")) }
else if specs.contains(&Imaginary) { return Err(unimpl_err!("Imaginary types are unimplemented!")) }
else if specs.contains(&Float) { F32 }
else if specs.contains(&Double) { F64 }
else if specs.contains(&Long) { if specs.contains(&Unsigned) { U64 } else { I64 } }
else if specs.contains(&Int) { if specs.contains(&Unsigned) { U32 } else { I32 } }
else {
let mut inner_ty=Unit;
for i in specs {
match i {
TypeSpecifier::Struct(struct_specifier) => {
inner_ty=(*struct_specifier).rinto(context)?;
break;
},
TypeSpecifier::Enum(enum_specifier) => {
inner_ty=(*enum_specifier).rinto(context)?;
break;
},
_ => {}
}
}
inner_ty
};
}
Ok((ty,q))
}
}
sum!(TypeOrTypedef;RType,Qualifier;RType);
impl RFrom<DeclarationSpecifiers> for TypeOrTypedef {
fn rfrom(value: DeclarationSpecifiers, context: &mut Context) -> Result<Self> {
let mut q=None;
let mut is_typedef=false;
let mut is_type_in_list=false;
let mut spec_qual_list=SpecifierQualifierList(vec![]);
for i in value.0 {
match i {
Specifier::Storage(storage_specifier) => {
match storage_specifier {
StorageSpecifier::Typedef => is_typedef=true,
StorageSpecifier::Extern => if q.is_none()||q==Some(Qualifier::StaticMut) { q=Some(Qualifier::ExternStaticMut) },
StorageSpecifier::Static => if q.is_none() { q=Some(Qualifier::StaticMut) },
StorageSpecifier::Auto|StorageSpecifier::Register => {}, }
},
Specifier::Type(type_specifier) => {
spec_qual_list.0.push(SpecifierQualifier::Spec(type_specifier));
is_type_in_list=true;
},
Specifier::Typedef(typedef_name) => {
if is_type_in_list { return Err(c2rust_err!("Type is already in specifier-qualifier list! Cannot push typedef name '{typedef_name:?}' onto it!")) }
spec_qual_list.0.push(SpecifierQualifier::Typedef(typedef_name));
},
Specifier::TypeQ(type_qualifier) => {
spec_qual_list.0.push(SpecifierQualifier::Qualif(type_qualifier));
},
Specifier::Func(func_specifier) => {
match func_specifier {
FuncSpecifier::Inline => q=Some(Qualifier::Inline),
}
},
}
}
let (ty,q1)=spec_qual_list.rinto(context)?;
let q=
q.map_or(Ok(q1), |qual| match qual {
Qualifier::StaticMut => {
match q1 {
Qualifier::StaticMut|Qualifier::Mut => Ok(Qualifier::StaticMut),
Qualifier::Const|Qualifier::Static => Ok(Qualifier::Static),
_ => Err(unimpl_err!("Unreachable qualifier variant '{q1}' reached!"))
}
},
Qualifier::ExternStaticMut => {
match q1 {
Qualifier::StaticMut|Qualifier::Mut => Ok(Qualifier::ExternStaticMut),
Qualifier::Const|Qualifier::Static => Ok(Qualifier::ExternStatic),
_ => Err(unimpl_err!("Unreachable qualifier variant '{q1}' reached!"))
}
},
Qualifier::Inline => Ok(Qualifier::Inline),
_ => Err(unimpl_err!("Unreachable qualifier variant '{qual}' reached!"))
});
if is_typedef { Ok(Self::B(ty)) }
else { Ok(Self::A(ty, q?)) }
}
}
impl RFrom<TypeName> for (RType,Qualifier) {
fn rfrom(mut value: TypeName, context: &mut Context) -> Result<Self> {
let (mut ty,q)=value.0.rinto(context)?;
let mut it=vec![];
loop {
if let Some(abstr)=value.1 {
match *abstr {
AbstractDeclarator::Pointer(pointer) => {
pointerise(pointer,q,&mut ty,context.flags);
value.1=None;
},
AbstractDeclarator::Direct(pointer, direct_abstract_declarator) => {
if let Some(pointer)=pointer { pointerise(pointer,q,&mut ty,context.flags); }
match *direct_abstract_declarator {
DirectAbstractDeclarator::Abstract(abstract_declarator) => value.1=Some(abstract_declarator),
DirectAbstractDeclarator::Post(abstract_declarator, items) => {
value.1=abstract_declarator;
for i in (items).into_iter().rev() {
it.insert(0, i);
}
},
}
},
}
}
else if !it.is_empty() {
for i in it {
match i {
DirectAbstractDeclaratorPostfix::Parent(parameter_type_list) => {
let mut list=vec![];
if let Some(x)=parameter_type_list {
list.append(&mut RParamList::rfrom(x,context)?.0.into_iter().map(|y| y.2).collect::<Vec<_>>());
}
ty=RType::Function(list, Box::new(ty));
},
DirectAbstractDeclaratorPostfix::Assign(assignment_expr) => {
if let Some(assign)=assignment_expr { ty=RType::Array(Box::new(ty), Box::new(RExpr::Expr(Box::new(assign.rinto(context)?)))) }
else { ty=ty.ref_mut() }
},
DirectAbstractDeclaratorPostfix::Pointer => {
ty=ty.ref_mut();
},
}
}
break;
}
else { break }
}
Ok((ty,q))
}
}
impl Display for RType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::I8|Self::BoolI8 => write!(f,"i8"),
Self::U8 => write!(f,"u8"),
Self::I16 => write!(f,"i16"),
Self::U16 => write!(f,"u16"),
Self::I32 => write!(f,"i32"),
Self::U32 => write!(f,"u32"),
Self::I64 => write!(f,"i64"),
Self::U64 => write!(f,"u64"),
Self::I128 => write!(f,"i128"),
Self::U128 => write!(f,"u128"),
Self::Isize => write!(f,"isize"),
Self::Usize => write!(f,"usize"),
Self::F32 => write!(f,"f32"),
Self::F64 => write!(f,"f64"),
Self::Bool => write!(f,"bool"),
Self::Unit => write!(f,"()"),
Self::Ref(generics,rtype) => write!(f,"&{} [{rtype}]",print_vec(generics, " ")),
Self::ThinRef(generics,rtype) => write!(f,"&{} {rtype}",print_vec(generics, " ")),
Self::RefMut(generics,rtype) => write!(f,"&{} mut [{rtype}]",print_vec(generics, " ")),
Self::ThinRefMut(generics,rtype) => write!(f,"&{} mut {rtype}",print_vec(generics, " ")),
Self::Point(rtype) => write!(f,"*const [{rtype}]"),
Self::ThinPoint(rtype) => write!(f,"*const {rtype}"),
Self::PointMut(rtype) => write!(f,"*mut [{rtype}]"),
Self::ThinPointMut(rtype) => write!(f,"*mut {rtype}"),
Self::Array(rtype, rexpr) => write!(f,"[{rtype};{}]",form_unsafe_expr(rexpr)),
Self::GenericArray(rtype, generic) => write!(f,"[{rtype};{generic}]"),
Self::Typedef(rident,_)|Self::Enum(rident)|Self::Struct(rident)|Self::Union(rident) => write!(f,"{rident}"),
Self::Function(rtypes, rtype) => write!(f,"fn({}) -> {rtype}",print_vec(rtypes, ",")),
Self::UnsizedArray(_)|Self::EnumDecl(..)|Self::StructDecl(..)|Self::UnionDecl(..) => write!(f,"")
}
}
}
impl RType {
#[allow(clippy::cast_sign_loss,clippy::missing_errors_doc)]
pub fn sizeof(&self, context: &Context) -> Result<usize> {
match self {
Self::I8 => Ok(size_of::<i8>()),
Self::U8 => Ok(size_of::<u8>()),
Self::I16 => Ok(size_of::<i16>()),
Self::U16 => Ok(size_of::<u16>()),
Self::I32 => Ok(size_of::<i32>()),
Self::U32 => Ok(size_of::<u32>()),
Self::I64 => Ok(size_of::<i64>()),
Self::U64 => Ok(size_of::<u64>()),
Self::I128 => Ok(size_of::<i128>()),
Self::U128 => Ok(size_of::<u128>()),
Self::Isize => Ok(size_of::<isize>()),
Self::Usize => Ok(size_of::<usize>()),
Self::F32 => Ok(size_of::<f32>()),
Self::F64 => Ok(size_of::<f64>()),
Self::Bool => Ok(size_of::<bool>()),
Self::Unit => Ok(size_of::<()>()),
Self::Ref(..) => Ok(size_of::<&[i32]>()),
Self::RefMut(..) => Ok(size_of::<&mut [i32]>()),
Self::Point(_) => Ok(size_of::<*const [i32]>()),
Self::PointMut(_) => Ok(size_of::<*mut [i32]>()),
Self::ThinRef(..) => Ok(size_of::<&i32>()),
Self::ThinRefMut(..) => Ok(size_of::<&mut i32>()),
Self::ThinPoint(_) => Ok(size_of::<*const i32>()),
Self::ThinPointMut(_) => Ok(size_of::<*mut i32>()),
Self::Array(rtype, rexpr) => Ok(rtype.sizeof(context)?*rexpr.eval(context)? as usize),
Self::Enum(rident) => Ok(context.get_enum_size(&rident.0)),
Self::Struct(_rident) => Err(unimpl_err!("Evaluating struct size inside 'sizeof' is unimplemented!")),
Self::Union(rident) => context.get_union_size(&rident.0),
Self::Typedef(_,ty) => ty.sizeof(context),
Self::Function(..) => Ok(size_of::<&fn()>()),
_ => Err(unimpl_err!("Cannot calculate 'sizeof' type '{self}' during translation!"))
}
}
#[must_use]
pub fn deref(self) -> Self {
match self {
Self::Ref(_,rtype)|Self::RefMut(_,rtype)|Self::Point(rtype)|Self::PointMut(rtype)|
Self::ThinRef(_,rtype)|Self::ThinRefMut(_,rtype)|Self::ThinPoint(rtype)|Self::ThinPointMut(rtype) => *rtype,
_ => self
}
}
#[must_use]
pub fn ref_const(self) -> Self {
Self::ThinPoint(Box::new(self))
}
#[must_use]
pub fn ref_mut(self) -> Self {
Self::ThinPointMut(Box::new(self))
}
pub const fn is_numeric(&self) -> bool {
use RType::*;
matches!(self,I8|U8|I16|U16|I32|U32|I64|U64|I128|U128|Isize|Usize|F32|F64|BoolI8)
}
pub const fn is_pointer(&self) -> bool {
use RType::*;
matches!(self,Point(_)|PointMut(_)|Ref(..)|RefMut(..)|ThinPoint(_)|ThinPointMut(_)|ThinRef(..)|ThinRefMut(..))
}
pub fn can_derive_default(&self) -> bool {
match self {
Self::Ref(..)|Self::RefMut(..)|Self::Point(_)|Self::PointMut(_)|
Self::ThinRef(..)|Self::ThinRefMut(..)|Self::ThinPoint(_)|Self::ThinPointMut(_)|
Self::UnsizedArray(_)|Self::GenericArray(..)|Self::Function(..)|
Self::Union(_)|Self::Struct(_)|Self::StructDecl(..)|Self::UnionDecl(..) => false,
Self::Array(rtype, _)|Self::Typedef(_, rtype) => rtype.can_derive_default(),
_ => true
}
}
pub fn can_derive_clone(&self) -> bool {
match self {
Self::RefMut(..)|Self::ThinRefMut(..)|
Self::Union(_)|Self::Struct(_)|Self::StructDecl(..)|Self::UnionDecl(..) => false,
Self::Typedef(_, rtype)|Self::Ref(_, rtype)|Self::Point(rtype)|Self::PointMut(rtype)|
Self::ThinRef(_, rtype)|Self::ThinPoint(rtype)|Self::ThinPointMut(rtype)|
Self::Array(rtype, _)|Self::UnsizedArray(rtype)|Self::GenericArray(rtype, _) => rtype.can_derive_clone(),
_ => true
}
}
pub const fn is_unsigned(&self) -> bool {
use RType::*;
matches!(self,U8|U16|U32|U64|U128|Usize)
}
#[must_use]
pub fn get_signed_variant(self) -> Self {
match self {
Self::U8 => Self::I8,
Self::U16 => Self::I16,
Self::U32 => Self::I32,
Self::U64 => Self::I64,
Self::U128 => Self::I128,
Self::Usize => Self::Isize,
_ => self
}
}
pub fn stronger(ty1: Self, ty2: Self) -> Option<Self> {
use RType::*;
if ty1.is_numeric() && ty2.is_numeric() {
Some(
match (&ty1,&ty2) {
(U16,U8)|
(I16,I8|U8|BoolI8)|
(U32,U8|U16)|
(I32,I8|U8|I16|U16|BoolI8)|
(U64,U8|U16|U32)|
(I64,I8|U8|I16|U16|I32|U32|BoolI8)|
(U128,U8|U16|U32|U64)|
(I128,I8|U8|I16|U16|I32|U32|I64|U64|BoolI8)|
(Isize|Usize,I8|U8|I16|U16|I32|U32|I64|U64|I128|U128|BoolI8)|
(F32,I8|U8|I16|U16|I32|U32|I64|U64|I128|U128|Isize|Usize|BoolI8)|
(F64,_) => ty1,
(U16,I8|BoolI8)|(I8|BoolI8,U16) => I16,
(U32,I8|I16|BoolI8)|(I8|I16|BoolI8,U32) => I32,
(U64,I8|I16|I32|BoolI8)|(I8|I16|I32|BoolI8,U64) => I64,
(U128,I8|I16|I32|I64|BoolI8)|(I8|I16|I32|I64|BoolI8,U128) => I128,
(BoolI8,I8)|(I8,BoolI8) => BoolI8,
_ => ty2
}
)
}
else if ty1==Bool { Some(ty2) }
else if ty2==Bool { Some(ty1) }
else { None }
}
#[must_use]
pub fn get_type_alias(self) -> Self {
macro_rules! alias {
($rtype:expr) => {
Box::new($rtype.get_type_alias())
};
}
match self {
Self::Ref(generics,rtype) => Self::Ref(generics,alias!(rtype)),
Self::RefMut(generics,rtype) => Self::RefMut(generics,alias!(rtype)),
Self::Point(rtype) => Self::Point(alias!(rtype)),
Self::PointMut(rtype) => Self::PointMut(alias!(rtype)),
Self::ThinRef(generics,rtype) => Self::ThinRef(generics,alias!(rtype)),
Self::ThinRefMut(generics,rtype) => Self::ThinRefMut(generics,alias!(rtype)),
Self::ThinPoint(rtype) => Self::ThinPoint(alias!(rtype)),
Self::ThinPointMut(rtype) => Self::ThinPointMut(alias!(rtype)),
Self::Array(rtype, rexpr) => Self::Array(alias!(rtype),rexpr),
Self::UnsizedArray(rtype) => Self::UnsizedArray(alias!(rtype)),
Self::GenericArray(rtype, generic) => Self::GenericArray(alias!(rtype), generic),
Self::Typedef(_, rtype) => *rtype,
Self::Function(rtypes, rtype) => Self::Function(rtypes.into_iter().map(Self::get_type_alias).collect(),alias!(rtype)),
_ => self
}
}
#[must_use]
pub fn unsized_array(self, flags: CompilerFlags) -> Self {
if flags.contains(CompilerFlags::ArrayAsPoint) { self.point(flags) }
else { self.refer(flags) }
}
#[must_use]
pub fn unsized_array_mut(self, flags: CompilerFlags) -> Self {
if flags.contains(CompilerFlags::ArrayAsPoint) { self.point_mut(flags) }
else { self.refer_mut(flags) }
}
#[must_use]
pub fn point(self, flags: CompilerFlags) -> Self {
if flags.contains(CompilerFlags::UseRefInsteadOfPoint) {
if flags.contains(CompilerFlags::ThinRef) { Self::ThinRef(vec![],Box::new(self)) }
else { Self::Ref(vec![],Box::new(self)) }
}
else if flags.contains(CompilerFlags::ThinPoint) { Self::ThinPoint(Box::new(self)) }
else { Self::Point(Box::new(self)) }
}
#[must_use]
pub fn point_mut(self, flags: CompilerFlags) -> Self {
if flags.contains(CompilerFlags::UseRefInsteadOfPoint) {
if flags.contains(CompilerFlags::ThinRef) { Self::ThinRefMut(vec![],Box::new(self)) }
else { Self::RefMut(vec![],Box::new(self)) }
}
else if flags.contains(CompilerFlags::ThinPoint) { Self::ThinPointMut(Box::new(self)) }
else { Self::PointMut(Box::new(self)) }
}
#[must_use]
pub fn refer(self, flags: CompilerFlags) -> Self {
if flags.contains(CompilerFlags::UsePointInsteadOfRef) {
if flags.contains(CompilerFlags::ThinPoint) { Self::ThinPoint(Box::new(self)) }
else { Self::Point(Box::new(self)) }
}
else if flags.contains(CompilerFlags::ThinRef) { Self::ThinRef(vec![],Box::new(self)) }
else { Self::Ref(vec![],Box::new(self)) }
}
#[must_use]
pub fn refer_mut(self, flags: CompilerFlags) -> Self {
if flags.contains(CompilerFlags::UsePointInsteadOfRef) {
if flags.contains(CompilerFlags::ThinPoint) { Self::ThinPointMut(Box::new(self)) }
else { Self::PointMut(Box::new(self)) }
}
else if flags.contains(CompilerFlags::ThinRef) { Self::ThinRefMut(vec![],Box::new(self)) }
else { Self::RefMut(vec![],Box::new(self)) }
}
#[must_use]
pub fn transform(self, flags: CompilerFlags, generics: &mut Vec<Generic>) -> Self {
match self {
Self::Array(rtype, rexpr) => {
if flags.contains(CompilerFlags::ArrayAsPoint) {
rtype.transform(flags, generics).point_mut(flags)
}
else if flags.contains(CompilerFlags::ArrayAsRef) {
rtype.transform(flags, generics).refer_mut(flags)
}
else { Self::Array(rtype, rexpr) }
},
Self::UnsizedArray(rtype) => {
if flags.contains(CompilerFlags::ArrayAsGeneric) {
let s=format!("N{}",if generics.is_empty() { String::new() } else { generics.len().to_string() });
let generic=Generic::Const(s.clone(), Box::new(Self::Usize));
generics.push(generic);
let generic=Generic::Type(s);
Self::GenericArray(Box::new(rtype.transform(flags,generics)), generic)
}
else if flags.contains(CompilerFlags::ArrayAsPoint) {
rtype.transform(flags, generics).point_mut(flags)
}
else { rtype.transform(flags, generics).refer_mut(flags)
}
},
Self::Typedef(rident, rtype) => Self::Typedef(rident, Box::new(rtype.transform(flags, generics))),
Self::Function(rtypes, rtype) => Self::Function(rtypes.into_iter().map(|x| x.transform(flags, generics)).collect(), Box::new(rtype.transform(flags, generics))),
_ => self
}
}
#[must_use]
pub fn add_lifetime_to_refs(self, generics: &mut Vec<Generic>) -> Self {
let generic=Generic::Lifetime(format!("a{}",if generics.is_empty() { String::new() } else { generics.len().to_string() }));
macro_rules! refer {
($gens:expr,$rtype:expr,$id:ident) => {
{
$gens.push(generic.clone());
generics.insert(0, generic);
Self::$id($gens, Box::new($rtype.add_lifetime_to_refs(generics)))
}
};
}
match self {
Self::Ref(mut gens,rtype) => refer!(gens,rtype,Ref),
Self::RefMut(mut gens,rtype) => refer!(gens,rtype,RefMut),
Self::ThinRef(mut gens,rtype) => refer!(gens,rtype,ThinRef),
Self::ThinRefMut(mut gens,rtype) => refer!(gens,rtype,ThinRefMut),
_ => self
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub enum Qualifier {
Static, ExternStatic,
Const,
#[default]
Mut,
StaticMut, ExternStaticMut,
Inline
}
impl Display for Qualifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Static|Self::ExternStatic => write!(f,"static"),
Self::Const => write!(f,"let"),
Self::Mut => write!(f,"let mut"),
Self::StaticMut|Self::ExternStaticMut => write!(f,"static mut"),
Self::Inline => writeln!(f,"#[inline]"),
}
}
}
impl Qualifier {
pub fn print_fn_params(self) -> String {
match self {
Self::Static|Self::Const|Self::ExternStatic => String::new(),
Self::Mut|Self::StaticMut|Self::ExternStaticMut => "mut".to_string(),
Self::Inline => "#[inline]\n".to_string(),
}
}
}