#![forbid(unused_must_use)]
#![warn(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
mod expressions;
mod functions;
mod guards;
pub mod interface;
mod memory;
mod statements;
mod types;
use std::{
collections::{HashMap, HashSet},
path::PathBuf,
};
use clap::ValueEnum;
use interface::{InterfaceConfig, PartialEvaluationError};
use memory::Memory;
use rtlola_streamir::{
formatter::{
files::{ConstructStore, ConstructWriteError, FilesFormatter},
StreamIrFormatter,
},
ir::{
memory::{Parameter, StreamMemory},
Accesses, OutputReference, StreamIr, StreamReference, Type,
},
};
use thiserror::Error;
#[derive(Debug)]
pub struct SolidityFormatter {
config: InterfaceConfig,
contract_name: String,
streams_with_iteration: HashSet<OutputReference>,
trigger_action: TriggerAction,
trigger_function_mode: TriggerFunctionMode,
sr2name: HashMap<StreamReference, String>,
sr2memory: HashMap<StreamReference, StreamMemory>,
sr2ty: HashMap<StreamReference, Type>,
file: PathBuf,
construct_store: ConstructStore<Self>,
overwrite: bool,
accesses: HashMap<StreamReference, Accesses>,
triggers: HashMap<OutputReference, usize>,
outputs_verdict: Vec<StreamReference>,
}
#[derive(ValueEnum, Debug, Clone, Copy, Eq, PartialEq)]
pub enum TriggerAction {
Revert,
EmitSingle,
EmitMultiple,
}
#[derive(ValueEnum, Debug, Clone, Copy, Eq, PartialEq)]
pub enum TriggerFunctionMode {
Single,
Multiple,
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
#[allow(missing_docs)]
pub enum RequirementKey {
SolidityHeader,
TupleDefinition(Vec<Type>),
Memory(StreamReference),
SpawnFunction(StreamReference),
CloseFunction(StreamReference),
EvalFunction(StreamReference, usize),
ShiftFunction(StreamReference),
#[allow(dead_code)]
SyncFunction(StreamReference),
GetFunction(StreamReference),
TriggerEvent(usize),
TriggerFunction(usize),
UnpartialCycle,
VerdictEvent,
Cycle(String),
CloseContract,
}
impl SolidityFormatter {
#[allow(clippy::too_many_arguments)]
pub fn new(
streamir: &StreamIr,
config: InterfaceConfig,
contract_name: String,
trigger_action: TriggerAction,
trigger_function_mode: TriggerFunctionMode,
file: PathBuf,
overwrite: bool,
outputs_verdict: Vec<StreamReference>,
) -> Self {
let streams_with_iteration = streamir
.outputs()
.filter(|sr| streamir.stmt.contains_interate(*sr))
.collect();
let (sr2name, sr2ty) = streamir
.sr2memory
.iter()
.map(|(sr, m)| ((*sr, m.name.clone()), (*sr, m.ty.clone())))
.collect();
let sr2memory = streamir
.sr2memory
.iter()
.map(|(sr, m)| (*sr, m.buffer.clone()))
.collect();
let triggers = streamir.triggers.clone();
let construct_store = ConstructStore::default();
Self {
config,
contract_name,
streams_with_iteration,
trigger_action,
trigger_function_mode,
sr2name,
sr2memory,
sr2ty,
file,
construct_store,
overwrite,
accesses: streamir.accesses.clone(),
triggers,
outputs_verdict,
}
}
fn name(&self, sr: StreamReference) -> &str {
&self.sr2name[&sr]
}
fn stream_memory(&self, sr: StreamReference) -> &StreamMemory {
&self.sr2memory[&sr]
}
fn stream_parameter(&self, sr: StreamReference) -> Option<&[Parameter]> {
self.stream_memory(sr).parameters()
}
fn stream_type(&self, sr: StreamReference) -> &Type {
&self.sr2ty[&sr]
}
fn file(&self) -> &PathBuf {
&self.file
}
}
#[derive(Error, Debug)]
pub enum SolidityFormatterError {
#[error("Error writing output contract: {0}")]
ConstructWrite(#[from] ConstructWriteError),
#[error("Error partially evaluating StreamIR: {0}")]
PartialEvaluation(#[from] PartialEvaluationError),
}
impl StreamIrFormatter for SolidityFormatter {
type Return = Result<(), SolidityFormatterError>;
fn id(&self) -> String {
"solidity-formatter".into()
}
fn format(self, ir: StreamIr) -> Self::Return {
self.add_requirement_string(
self.file(),
RequirementKey::SolidityHeader,
format!(
"pragma solidity ^0.8.24;\ncontract {} {{",
self.contract_name
),
);
self.add_requirement_string(self.file(), RequirementKey::CloseContract, "}".into());
for stream in ir.streams() {
self.add_requirement(Memory(stream));
}
self.format_cycle_functions(&self.config, ir)?;
self.generate_files()?;
Ok(())
}
}