use crate::op::*;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Program {
pub constants: Vec<Const>,
pub functions: Vec<Function>,
pub function_names: IndexMap<String, u32>,
pub module_aliases: IndexMap<String, String>,
pub entry: Option<u32>,
}
impl Program {
pub fn lookup(&self, name: &str) -> Option<u32> {
self.function_names.get(name).copied()
}
pub fn declared_effects(&self) -> Vec<DeclaredEffect> {
let mut out: Vec<DeclaredEffect> = Vec::new();
for f in &self.functions {
for e in &f.effects {
if !out.iter().any(|x| x == e) {
out.push(e.clone());
}
}
}
out
}
}
pub type BodyHash = [u8; 16];
pub const ZERO_BODY_HASH: BodyHash = [0u8; 16];
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Function {
pub name: String,
pub arity: u16,
pub locals_count: u16,
pub code: Vec<Op>,
#[serde(default)]
pub effects: Vec<DeclaredEffect>,
#[serde(default = "zero_body_hash")]
pub body_hash: BodyHash,
#[serde(default)]
pub refinements: Vec<Option<Refinement>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Refinement {
pub binding: String,
pub predicate: lex_ast::CExpr,
}
fn zero_body_hash() -> BodyHash { ZERO_BODY_HASH }
pub fn compute_body_hash(arity: u16, locals_count: u16, code: &[Op]) -> BodyHash {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(arity.to_le_bytes());
hasher.update(locals_count.to_le_bytes());
hasher.update((code.len() as u64).to_le_bytes());
for op in code {
let bytes = serde_json::to_vec(op)
.expect("Op serialization must succeed");
hasher.update((bytes.len() as u64).to_le_bytes());
hasher.update(&bytes);
}
let full = hasher.finalize();
let mut out = [0u8; 16];
out.copy_from_slice(&full[..16]);
out
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DeclaredEffect {
pub kind: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub arg: Option<EffectArg>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum EffectArg {
Str(String),
Int(i64),
Ident(String),
}