use std::fmt::Display;
use crate::{ccarp::error::{c2rust_err, CCErr, Result}, ccarp_c::tt::{Identifier, Literal}};
use super::{defs::{Context, RFrom}, rustdecl::RType};
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct RIdent(pub String);
impl From<Identifier> for RIdent {
fn from(value: Identifier) -> Self {
Self(rustify_ident(&value.0))
}
}
impl Display for RIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",self.0)
}
}
pub type IsGlobal=bool;
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct TypedIdent(pub RIdent, pub Box<RType>, pub IsGlobal);
impl RFrom<RIdent> for TypedIdent {
fn rfrom(value: RIdent, context: &mut Context) -> Result<Self> {
let ty=context.get_variable_ty(&value.0).ok_or_else(|| c2rust_err!("Could not find type of variable '{}' inside context!",value.0))?;
let is_global=context.is_variable_mutable_global(&value.0);
Ok(Self(value, Box::new(ty), is_global))
}
}
impl Display for TypedIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",self.0)
}
}
fn rustify_ident(ident: &str) -> String {
let ident=ident.trim();
if ident=="_" { "_0".to_string() }
else { ident.to_string() }
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RLit {
Int(String,RType),
Float(String,RType),
String(String,RType)
}
impl From<Literal> for RLit {
fn from(value: Literal) -> Self {
match value {
Literal::Int(int) => { let (lit,ty)=rustify_int(&int); Self::Int(lit,ty) },
Literal::Float(float) => { let (lit,ty)=rustify_float(&float); Self::Float(lit,ty) },
Literal::Char(chr) => { let (lit,ty)=rustify_char(&chr); Self::String(lit,ty) },
Literal::String(string) => { let (lit,ty)=rustify_string(&string); Self::String(lit,ty) },
}
}
}
impl Display for RLit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Int(int,_) => write!(f,"{int}"),
Self::Float(float,_) => write!(f,"{float}"),
Self::String(string,_) => write!(f,"{string}"),
}
}
}
fn rustify_int(int: &str) -> (String,RType) {
let int=int.trim();
let mut out=int.replace('U', "u").replace('L', "l"); if out.starts_with("0x") || int.starts_with("0X") { out=out.replacen("0X", "0x", 1); } else if out.starts_with('0') && !["0","0u","0l","0ll","0ul","0lu","0ull","0llu"].contains(&out.as_str()) { out=out.replacen('0', "0o", 1); } let ty=
if out.contains('l') {
out=out.replace('l', "");
if out.contains('u') {
out=out.replace('u', "");
out+="u64";
RType::U64 }
else {
out+="i64";
RType::I64 }
}
else if out.contains('u') {
out=out.replace('u', "");
out+="u32";
RType::U32 }
else { RType::I32 }; (out,ty)
}
#[allow(clippy::cast_precision_loss)]
fn rustify_float(float: &str) -> (String,RType) {
fn hex_to_int(h: char) -> isize {
isize::from_str_radix(h.to_string().as_str(), 16).unwrap_or_default()
}
let mut out=float.trim().replace('F', "f").replace('L', "l"); let ty=
if out.starts_with("0x") || out.starts_with("0X") { out=out[2..].replace('P', "p"); let suffix={
if out.contains('f') { out=out.replace('f', ""); "f32"} else if out.contains('l') { out=out.replace('l', ""); "f64"} else { "" } };
let mut res=0.0;
let mut sp=out.split('p');
let num=sp.next().unwrap_or_default();
let mut sp2=num.split('.');
let whole=sp2.next().unwrap_or_default().replace("0x",""); if !whole.is_empty() { res=isize::from_str_radix(whole.as_str(), 16).unwrap_or_default() as f64; }
let frac=sp2.next(); if let Some(frac)=frac {
let mut div=1.0;
for h in frac.chars() {
div*=16.0;
res+=hex_to_int(h) as f64/div;
}
}
let exp=sp.next(); if let Some(exp)=exp {
let exp=str::parse::<isize>(exp).unwrap_or_default();
res*=f64::powf(2.0, exp as f64);
}
out=format!("{res}{suffix}");
if suffix.contains("f32") { RType::F32 } else { RType::F64 } }
else {
if out.starts_with('.') { out.insert(0, '0'); }
if !out.contains('.') { out.push('.'); }
out=out.replace('f', "f32").replace('l', "f64"); if out.contains("f32") { RType::F32 } else { RType::F64 } };
(out,ty)
}
fn rustify_char(ch: &str) -> (String,RType) {
fn chr_to_hex(ch: char) -> String {
format!("{:x}", ch as u8)
}
let ch=ch[1..ch.len()-1].replace("\\v", "\\x0b").replace("\\?", "?").replace("\\a", "\\x07").replace("\\b", "\\x08").replace("\\f", "\\x0c");
if ch.len()==1 || ch.starts_with('\\') && ch.len()==2 || ch.starts_with("\\x") && ch.len()==4 { (format!("b'{ch}'"),RType::U8) }
else {
let mut out="0x".to_string();
for c in ch.chars() {
out+=chr_to_hex(c).as_str();
}
(out,RType::I32)
}
}
fn rustify_string(s: &str) -> (String,RType) {
let out=s.replace("\\v", "\\x0b").replace("\\?", "?").replace("\\a", "\\x07").replace("\\b", "\\x08").replace("\\f", "\\x0c");
(format!("&mut b{out}.to_vec()[..]"),RType::RefMut(vec![],Box::new(RType::U8)))
}