use std::fmt::Display;
use crate::ccarp::{error::Result, translator::CompilerFlags};
use super::{rustdecl::{EnumDecl, Let, Qualifier, RDecl, RDeclSingle, REnumerator, RInit, RType}, rustexpr::*};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Context {
pub scope: RDecl,
pub return_type: RType,
pub inside_main: bool,
pub top_level: bool,
pub flags: CompilerFlags,
}
impl Context {
pub fn get_const_integers(&self) -> Vec<(&str,i128)> {
let mut out=vec![];
for decl in &self.scope.0 {
if let RDeclSingle::Let(Let(qual,ident,_,init))=decl {
if [Qualifier::Const,Qualifier::Static,Qualifier::ExternStatic].contains(qual) {
if let Some(rin)=init {
if let RInit::Expr(expr)=rin.as_ref() {
if let Ok(val)=expr.eval(self) {
out.push((ident.0.as_str(),val));
}
}
}
}
}
}
out
}
pub fn get_enum_vals(&self) -> Vec<(&str,i128)> {
let mut out=vec![];
for decl in &self.scope.0 {
let mut val=0;
if let RDeclSingle::Enum(enum_decl)=decl {
for enumerator in &enum_decl.1 {
match enumerator {
REnumerator::Const(renum_const) => {
out.push((renum_const.0.0.as_str(),val));
val+=1;
},
REnumerator::Val(renum_const, rternary) => {
if let Ok(eval)=rternary.eval(self) {
val=eval;
out.push((renum_const.0.0.as_str(),val));
val+=1;
}
},
}
}
}
}
out
}
pub fn get_extern_vars(&self) -> Vec<&Let> {
let mut out=vec![];
for decl in &self.scope.0 {
if let RDeclSingle::Let(let_)=decl {
if matches!(let_.0,Qualifier::ExternStatic|Qualifier::ExternStaticMut) {
out.push(let_);
}
}
}
out
}
pub fn get_variable_decl(&self,var: &str) -> Option<&Let> {
for decl in &self.scope.0 {
if let RDeclSingle::Let(let_)=decl {
if let_.1.0==var {
return Some(let_)
}
}
}
None
}
pub fn get_variable_ty(&self,var: &str) -> Option<RType> {
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Let(Let(_,ident,ty,_))=decl {
if ident.0.as_str()==var { return Some(ty.clone()) }
}
else if let RDeclSingle::Enum(EnumDecl(ident,enums))=decl {
for en in enums {
let s=
match en {
REnumerator::Const(renum_const)|REnumerator::Val(renum_const, _) => renum_const.0.0.as_str(),
};
if var==s { return Some(RType::Enum(ident.clone()))}
}
}
}
None
}
pub fn get_struct_fields(&self,struct_name: &str) -> Vec<(&str,&RType)> {
let mut out=vec![];
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Struct(struct_decl)=decl {
if struct_name==struct_decl.1.0.as_str() {
for decl in &struct_decl.3 {
out.append(&mut decl.0.iter().map(|x| (x.0.0.as_str(),&x.1)).collect());
}
}
}
}
out
}
pub fn get_enum_fields(&self,enum_name: &str) -> Vec<&str> {
let mut out=vec![];
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Enum(enum_decl)=decl {
if enum_name==enum_decl.0.0.as_str() {
for decl in &enum_decl.1 {
match decl {
REnumerator::Const(renum_const)|REnumerator::Val(renum_const, _) => {
out.push(renum_const.0.0.as_str());
}
}
}
}
}
}
out
}
pub fn get_typedef_alias(&self,typedef: &str) -> Option<RType> {
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Typedef(rtypedef)=decl {
if rtypedef.0.0.as_str()==typedef {
return Some(rtypedef.1.clone().get_type_alias())
}
}
}
None
}
#[allow(clippy::cast_sign_loss,clippy::cast_possible_truncation,clippy::cast_precision_loss)]
pub fn get_enum_size(&self,enum_name: &str) -> usize {
let len=self.get_enum_fields(enum_name).len();
(len as f64).log2().ceil() as usize/8
}
#[allow(clippy::missing_errors_doc)]
pub fn get_union_size(&self,union_name: &str) -> Result<usize> {
let types=self.get_struct_fields(union_name).into_iter().map(|x| x.1);
let mut max=0;
for ty in types {
max=Ord::max(max, ty.sizeof(self)?);
}
Ok(max)
}
pub fn get_fn_return_value(&self, post: &RPostfixExpr) -> Option<RType> {
if let RPostfixExpr::Field(field)=post {
if let RFieldExpr(RPrimaryExpr::Ident(ident),v,_)=field.as_ref() {
if v.is_empty() {
for i in &self.scope.0 {
if let RDeclSingle::Let(let_)=i {
if let_.1==ident.0 {
match &let_.2 {
RType::Function(_, rtype) => return Some((**rtype).clone()),
_ => return None
}
}
}
}
}
}
}
None
}
pub fn get_field_ty(&self, ty: RType, field: &RField) -> Option<RType> {
let ident=
match &field {
RField::Field(rident)|RField::UnsafeField(rident) => rident,
RField::Method(..)|RField::UnsafeMethod(..) => return None,
};
match ty {
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::Point(rtype)|RType::PointMut(rtype)|
RType::ThinRef(_,rtype)|RType::ThinRefMut(_,rtype)|RType::ThinPoint(rtype)|RType::ThinPointMut(rtype) => self.get_field_ty(*rtype, field),
RType::Typedef(_, ty) => {
self.get_field_ty(*ty, field)
},
RType::Struct(rident)|RType::Union(rident) => {
let fields=self.get_struct_fields(&rident.0);
for (name,ty) in fields {
if name==ident.0 { return Some(ty.clone()) }
}
None
},
_ => None
}
}
pub fn new_nameless_enum(&self) -> String {
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Enum(enum_decl)=decl {
if let Some(opt_num)=enum_decl.0.0.strip_prefix("_NamelessEnum") {
if let Ok(num)=str::parse::<usize>(opt_num) {
return format!("_NamelessEnum{}",num+1)
}
}
}
}
"_NamelessEnum".to_string()
}
pub fn new_nameless_union(&self) -> String {
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Struct(struct_decl)=decl {
if let Some(opt_num)=struct_decl.1.0.strip_prefix("_NamelessUnion") {
if let Ok(num)=str::parse::<usize>(opt_num) {
return format!("_NamelessUnion{}",num+1)
}
}
}
}
"_NamelessUnion".to_string()
}
pub fn new_nameless_struct(&self) -> String {
for decl in self.scope.0.iter().rev() {
if let RDeclSingle::Struct(struct_decl)=decl {
if let Some(opt_num)=struct_decl.1.0.strip_prefix("_NamelessStruct") {
if let Ok(num)=str::parse::<usize>(opt_num) {
return format!("_NamelessStruct{}",num+1)
}
}
}
}
"_NamelessStruct".to_string()
}
pub fn is_variable_mutable_global(&self, name: &str) -> bool {
for decl in &self.scope.0 {
if let RDeclSingle::Let(Let(q, ident,..))=decl {
if ident.0.as_str()==name { return matches!(q,Qualifier::StaticMut|Qualifier::ExternStaticMut); }
}
}
false
}
}
impl Default for Context {
fn default() -> Self {
Self { scope: (RDecl(vec![])), return_type: (RType::default()), inside_main: (false), top_level: (false), flags: (CompilerFlags::empty()) }
}
}
pub trait RFrom<T> where Self : Sized {
fn rfrom(value: T, context: &mut Context) -> Result<Self>;
}
pub trait RInto<U> {
fn rinto(self, context: &mut Context) -> Result<U>;
}
impl<U,T: RFrom<U>> RInto<T> for U {
fn rinto(self, context: &mut Context) -> Result<T> {
T::rfrom(self, context)
}
}
pub trait GetType {
fn get_type(&self) -> RType;
}
pub trait CastInto {
#[must_use]
fn cast(self, ty: &RType) -> Self;
}
macro_rules! sum {
($name:ident; $($t:ty),+; $($u:ty),+) => {
pub enum $name {
A($($t),+),
B($($u),+)
}
};
($name:ident; $($t:ty),+; $($u:ty),+; $($v:ty),+) => {
pub enum $name {
A($($t),+),
B($($u),+),
C($($v),+)
}
};
}
pub(crate) use sum;
pub fn print_vec<T: Display>(v: &[T], sep: &str) -> String {
v.iter().map(ToString::to_string).collect::<Vec<_>>().join(sep)
}
pub fn print_vec2<T>(v: &[T], f: impl Fn(&T) -> String, sep: &str) -> String {
v.iter().map(f).collect::<Vec<_>>().join(sep)
}
pub trait Eval {
fn eval(&self, context: &Context) -> Result<i128>;
}
pub trait IsUnsafe {
fn is_unsafe(&self) -> bool;
}
pub trait NoReturn {
#[must_use]
fn simplify(self) -> Self;
}
pub trait IsPrimary {
fn is_primary(&self) -> bool;
fn into_primary(self) -> RPrimaryExpr;
}