use std::fmt;
#[allow(unused_imports)]
use super::entities::{Type, Value};
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum IRNode {
Export(Vec<Export>),
ConstInt(i64),
ConstFloat(f64),
Variable(String),
IAdd {
left: Box<IRNode>,
right: Box<IRNode>
},
ISub {
left: Box<IRNode>,
right: Box<IRNode>
},
IMul {
left: Box<IRNode>,
right: Box<IRNode>
},
IDiv {
left: Box<IRNode>,
right: Box<IRNode>
},
INeg {
operand: Box<IRNode>
},
Label(String),
Assign {
name: String,
value: Box<IRNode>,
var_type: Type
},
Function {
return_type: Type,
name: String,
body: Vec<IRNode>
},
Ret(Box<IRNode>),
End
}
#[derive(Debug, Clone)]
pub enum Export {
Function(FunctionExport)
}
impl fmt::Display for Export {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Function(func) => write!(
f, "[function({}/{})]",
func.name,
func.arg_number
)
}
}
}
#[derive(Debug, Clone)]
pub struct FunctionExport {
pub name: String,
pub arg_number: u64
}
impl IRNode {
pub fn into_string(&self) -> String {
match self {
Self::Export(exports) => {
let mut output: String = String::from("@export(");
for (index, export) in exports.iter().enumerate() {
output.push_str(&export.to_string());
if index < exports.len() - 1 {
output.push_str(", ")
}
}
output.push_str(")");
output
},
Self::ConstInt(number) => format!("int.{}", number),
Self::ConstFloat(number) => format!("float.{}", number),
Self::Variable(var) => format!("${}", var),
Self::IAdd {
left
,right
} => format!("iadd {} {}", (*left).into_string(), (*right).into_string()),
Self::ISub {
left
,right
} => format!("isub {} {}", (*left).into_string(), (*right).into_string()),
Self::IMul {
left
,right
} => format!("imul {} {}", (*left).into_string(), (*right).into_string()),
Self::IDiv {
left
,right
} => format!("idiv {} {}", (*left).into_string(), (*right).into_string()),
Self::INeg {
operand
} => format!("ineg {}", (*operand).into_string()),
Self::Label(label) => format!("{}:", label),
Self::Assign {
name,
value,
var_type
} => format!("assign {} {} = {}", var_type, name, (*value).into_string()),
Self::Function {
return_type,
name,
body
} => format!("function {} > {}:\n{}",
name,
return_type.to_string(),
&serialize(body)
),
Self::Ret(return_value) => format!("ret {}", (*return_value).into_string()),
Self::End => "end".to_string()
}
}
}
pub fn serialize(program: &Vec<IRNode>) -> String {
let mut output = String::new();
for (index, instruction) in program.iter().enumerate() {
output.push_str(&instruction.into_string());
if index < program.len() - 1 {
output.push_str("\n")
}
}
output
}