use serde::{Deserialize, Serialize};
use crate::{bytecode::*, bytes_util::*, error::CodegenError, evm::Opcode};
use std::path::PathBuf;
pub type Literal = [u8; 32];
pub type FilePath = PathBuf;
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Contract {
pub macros: Vec<MacroDefinition>,
pub invocations: Vec<MacroInvocation>,
pub imports: Vec<FilePath>,
pub constants: Vec<ConstantDefinition>,
pub functions: Vec<Function>,
pub events: Vec<Event>,
pub tables: Vec<Table>,
}
impl Contract {
pub fn find_macro_by_name(&self, name: &str) -> Option<MacroDefinition> {
if let Some(m) = self
.macros
.iter()
.filter(|m| m.name == name)
.cloned()
.collect::<Vec<MacroDefinition>>()
.get(0)
{
Some(m.clone())
} else {
tracing::warn!("Failed to find macro \"{}\" in contract", name);
None
}
}
pub fn derive_storage_pointers(&mut self) {
let mut storage_pointers: Vec<[u8; 32]> = Vec::new();
let mut last_assigned_free_pointer = 0;
for constant in &self.constants {
if let ConstVal::Literal(literal) = &constant.value {
storage_pointers.push(*literal);
}
}
for constant in self.constants.iter_mut() {
if let ConstVal::FreeStoragePointer(_) = &constant.value {
let mut fsp_bytes = str_to_bytes32(&format!("{}", last_assigned_free_pointer));
while storage_pointers.contains(&fsp_bytes) {
last_assigned_free_pointer += 1;
fsp_bytes = str_to_bytes32(&format!("{}", last_assigned_free_pointer));
}
storage_pointers.push(fsp_bytes);
last_assigned_free_pointer += 1;
constant.value = ConstVal::Literal(fsp_bytes);
}
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Argument {
pub arg_type: Option<String>,
pub name: Option<String>,
pub indexed: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Function {
pub name: String,
pub signature: [u8; 4],
pub inputs: Vec<Argument>,
pub fn_type: FunctionType,
pub outputs: Vec<Argument>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum FunctionType {
View,
Payable,
NonPayable,
Pure,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Event {
pub name: String,
pub parameters: Vec<Argument>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Table {
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct MacroDefinition {
pub name: String,
pub parameters: Vec<Argument>,
pub statements: Vec<Statement>,
pub takes: usize,
pub returns: usize,
}
impl ToIRBytecode<CodegenError> for MacroDefinition {
fn to_irbytecode(&self) -> Result<IRBytecode, CodegenError> {
let mut inner_irbytes: Vec<IRByte> = vec![];
self.statements.iter().for_each(|statement| {
match statement {
Statement::Literal(l) => {
let combined = l
.iter()
.map(|b| IRByte::Byte(Byte(format!("{:04x}", b))))
.collect::<Vec<IRByte>>();
println!("Combined IRBytes: {:?}", combined);
combined.iter().for_each(|irb| inner_irbytes.push(irb.clone()));
}
Statement::Opcode(o) => {
let opcode_str = o.string();
tracing::info!("Got opcode hex string: {}", opcode_str);
inner_irbytes.push(IRByte::Byte(Byte(opcode_str)))
}
Statement::MacroInvocation(mi) => {
inner_irbytes.push(IRByte::Statement(Statement::MacroInvocation(mi.clone())));
}
Statement::Constant(name) => {
inner_irbytes.push(IRByte::Constant(name.to_string()));
}
Statement::ArgCall(arg_name) => {
inner_irbytes.push(IRByte::ArgCall(arg_name.to_string()));
}
}
});
Ok(IRBytecode(inner_irbytes))
}
}
impl MacroDefinition {
pub fn new(
name: String,
parameters: Vec<Argument>,
statements: Vec<Statement>,
takes: usize,
returns: usize,
) -> Self {
MacroDefinition { name, parameters, statements, takes, returns }
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct MacroInvocation {
pub macro_name: String,
pub args: Vec<MacroArg>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum MacroArg {
Literal(Literal),
Ident(String),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FreeStoragePointer;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ConstVal {
Literal(Literal),
FreeStoragePointer(FreeStoragePointer),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ConstantDefinition {
pub name: String,
pub value: ConstVal,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Statement {
Literal(Literal),
Opcode(Opcode),
MacroInvocation(MacroInvocation),
Constant(String),
ArgCall(String),
}