use crate::types::{
ExpandedBuiltIn, HeapPos, MelExpr, UnrolledExpr, UnrolledStatement, Value, VarId,
};
use std::collections::HashMap;
pub struct MemoryMap {
memory_store: HashMap<VarId, HeapPos>,
}
impl MemoryMap {
pub fn new() -> Self {
let mut hm = HashMap::new();
for i in 0..crate::parser::NUM_RESERVED {
hm.insert(i as i32, i as u16);
}
MemoryMap { memory_store: hm }
}
fn binop<F>(&mut self, e1: UnrolledExpr, e2: UnrolledExpr, op: F) -> ExpandedBuiltIn<MelExpr>
where
F: Fn(MelExpr, MelExpr) -> ExpandedBuiltIn<MelExpr>,
{
let mel_e1 = self.unrolled_to_mel(e1);
let mel_e2 = self.unrolled_to_mel(e2);
op(mel_e1, mel_e2)
}
pub fn stmnt_to_mel_expr(&mut self, stmnt: UnrolledStatement) -> MelExpr {
match stmnt {
UnrolledStatement::Set(var_id, body) => {
let mel_body = self.unrolled_to_mel(*body);
let loc = self
.memory_store
.get(&var_id)
.expect("Failed to access variable id, there's a bug somewhere.");
MelExpr::Seq(vec![
mel_body,
MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Store(*loc))),
])
}
UnrolledStatement::Loop(n, stmnt) => {
MelExpr::Loop(n, Box::new(self.stmnt_to_mel_expr(*stmnt)))
}
UnrolledStatement::If(pred, on_true, on_false) => {
let mel_true = self.stmnt_to_mel_expr(*on_true);
let mel_false = self.stmnt_to_mel_expr(*on_false);
MelExpr::Seq(vec![
self.unrolled_to_mel(*pred),
MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Bez(
(count_insts(&mel_true) + 1) as u16,
))),
mel_true,
MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Jmp(
count_insts(&mel_false) as u16
))),
mel_false,
])
}
UnrolledStatement::SetLet(binds, stmnts) => {
let mut mel_binds = vec![];
binds.into_iter().for_each(|(var_id, expr)| {
if self.memory_store.contains_key(&var_id) {
panic!("Variable id in let binding should not already be defined, this is a bug.")
}
let loc = var_id as HeapPos;
self.memory_store.insert(var_id, loc);
let mel_expr = self.unrolled_to_mel(expr);
mel_binds.push(mel_expr);
mel_binds.push( MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Store(loc))) );
});
let mel_stmnts = stmnts.into_iter().map(|stm| self.stmnt_to_mel_expr(stm));
mel_binds.extend(mel_stmnts);
MelExpr::Seq(mel_binds)
}
UnrolledStatement::Noop => MelExpr::Noop,
}
}
pub fn unrolled_to_mel(&mut self, expr: UnrolledExpr) -> MelExpr {
match expr.clone() {
UnrolledExpr::Value(v) => match v {
Value::Int(n) => MelExpr::Value(Value::Int(n)),
Value::Bytes(b) => MelExpr::Value(Value::Bytes(b)),
},
UnrolledExpr::Var(ref v) => {
let loc = self
.memory_store
.get(v)
.expect("Expected to find a mapping for variable.");
MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Load(*loc)))
}
UnrolledExpr::BuiltIn(b) => {
let mel_b = match *b {
ExpandedBuiltIn::Vempty => ExpandedBuiltIn::<MelExpr>::Vempty,
ExpandedBuiltIn::Bempty => ExpandedBuiltIn::<MelExpr>::Bempty,
ExpandedBuiltIn::Bez(n) => ExpandedBuiltIn::<MelExpr>::Bez(n),
ExpandedBuiltIn::Bnz(n) => ExpandedBuiltIn::<MelExpr>::Bnz(n),
ExpandedBuiltIn::Jmp(n) => ExpandedBuiltIn::<MelExpr>::Jmp(n),
ExpandedBuiltIn::Load(p) => ExpandedBuiltIn::<MelExpr>::Load(p),
ExpandedBuiltIn::Store(p) => ExpandedBuiltIn::<MelExpr>::Store(p),
ExpandedBuiltIn::Print(e) => {
ExpandedBuiltIn::<MelExpr>::Print(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::Not(e) => {
ExpandedBuiltIn::<MelExpr>::Not(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::Vlen(e) => {
ExpandedBuiltIn::<MelExpr>::Vlen(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::Blen(e) => {
ExpandedBuiltIn::<MelExpr>::Blen(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::BtoI(e) => {
ExpandedBuiltIn::<MelExpr>::BtoI(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::ItoB(e) => {
ExpandedBuiltIn::<MelExpr>::ItoB(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::TypeQ(e) => {
ExpandedBuiltIn::<MelExpr>::TypeQ(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::Dup(e) => {
ExpandedBuiltIn::<MelExpr>::Dup(self.unrolled_to_mel(e))
}
ExpandedBuiltIn::Add(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Add)
}
ExpandedBuiltIn::Sub(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Sub)
}
ExpandedBuiltIn::Mul(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Mul)
}
ExpandedBuiltIn::Exp(e1, e2, k) => ExpandedBuiltIn::<MelExpr>::Exp(
self.unrolled_to_mel(e1),
self.unrolled_to_mel(e2),
k,
),
ExpandedBuiltIn::Div(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Div)
}
ExpandedBuiltIn::Rem(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Rem)
}
ExpandedBuiltIn::Eql(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Eql)
}
ExpandedBuiltIn::Lt(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Lt)
}
ExpandedBuiltIn::Gt(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Gt)
}
ExpandedBuiltIn::And(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::And)
}
ExpandedBuiltIn::Or(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Or)
}
ExpandedBuiltIn::Xor(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Xor)
}
ExpandedBuiltIn::Shl(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Shl)
}
ExpandedBuiltIn::Shr(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Shr)
}
ExpandedBuiltIn::Vref(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Vref)
}
ExpandedBuiltIn::Vpush(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Vpush)
}
ExpandedBuiltIn::Vcons(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Vcons)
}
ExpandedBuiltIn::Vappend(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Vappend)
}
ExpandedBuiltIn::Vslice(e1, e2, e3) => ExpandedBuiltIn::<MelExpr>::Vslice(
self.unrolled_to_mel(e1),
self.unrolled_to_mel(e2),
self.unrolled_to_mel(e3),
),
ExpandedBuiltIn::Vset(e1, e2, e3) => ExpandedBuiltIn::<MelExpr>::Vset(
self.unrolled_to_mel(e1),
self.unrolled_to_mel(e2),
self.unrolled_to_mel(e3),
),
ExpandedBuiltIn::Bref(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Bref)
}
ExpandedBuiltIn::Bpush(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Bpush)
}
ExpandedBuiltIn::Bcons(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Bcons)
}
ExpandedBuiltIn::Bappend(e1, e2) => {
self.binop(e1, e2, ExpandedBuiltIn::<MelExpr>::Bappend)
}
ExpandedBuiltIn::Bslice(e1, e2, e3) => ExpandedBuiltIn::<MelExpr>::Bslice(
self.unrolled_to_mel(e1),
self.unrolled_to_mel(e2),
self.unrolled_to_mel(e3),
),
ExpandedBuiltIn::Bset(e1, e2, e3) => ExpandedBuiltIn::<MelExpr>::Bset(
self.unrolled_to_mel(e1),
self.unrolled_to_mel(e2),
self.unrolled_to_mel(e3),
),
};
MelExpr::BuiltIn(Box::new(mel_b))
}
UnrolledExpr::If(pred, on_true, on_false) => {
let mel_true = self.unrolled_to_mel(*on_true);
let mel_false = self.unrolled_to_mel(*on_false);
MelExpr::Seq(vec![
self.unrolled_to_mel(*pred),
MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Bez(
(count_insts(&mel_true) + 1) as u16,
))),
mel_true,
MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Jmp(
count_insts(&mel_false) as u16
))),
mel_false,
])
}
UnrolledExpr::Let(binds, stmnts, expr) => {
let mut mel_binds = vec![];
binds.into_iter().for_each(|(var_id, expr)| {
if self.memory_store.contains_key(&var_id) {
panic!("Variable id in let binding should not already be defined, this is a bug.")
}
let loc = var_id as HeapPos;
self.memory_store.insert(var_id, loc);
let mel_expr = self.unrolled_to_mel(expr);
mel_binds.push(mel_expr);
mel_binds.push( MelExpr::BuiltIn(Box::new(ExpandedBuiltIn::Store(loc))) );
});
let mel_stmnts = stmnts.into_iter().map(|stm| self.stmnt_to_mel_expr(stm));
mel_binds.extend(mel_stmnts);
let mel_expr = self.unrolled_to_mel(*expr);
mel_binds.push(mel_expr);
MelExpr::Seq(mel_binds)
}
UnrolledExpr::Hash(n, expr) => MelExpr::Hash(n, Box::new(self.unrolled_to_mel(*expr))),
UnrolledExpr::Sigeok(n, e1, e2, e3) => MelExpr::Sigeok(
n,
Box::new(self.unrolled_to_mel(*e1)),
Box::new(self.unrolled_to_mel(*e2)),
Box::new(self.unrolled_to_mel(*e3)),
),
}
}
}
pub fn count_insts(e: &MelExpr) -> u16 {
match e {
MelExpr::Noop => 1,
MelExpr::Seq(v) => v.iter().map(count_insts).reduce(|a, b| a + b).unwrap_or(0),
MelExpr::Loop(_, e) => 1 + count_insts(e),
MelExpr::Hash(_, e) => 1 + count_insts(e),
MelExpr::Sigeok(_, e1, e2, e3) => 1 + count_insts(e1) + count_insts(e2) + count_insts(e3),
MelExpr::Value(val) => match val {
Value::Int(_) => 1,
Value::Bytes(_) => 1,
},
MelExpr::BuiltIn(b) => match &**b {
ExpandedBuiltIn::Add(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Sub(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Mul(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Exp(e1, e2, _) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Div(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Rem(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Eql(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Lt(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Gt(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::And(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Or(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Xor(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Shl(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Shr(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Print(e) => 1 + count_insts(&e),
ExpandedBuiltIn::Not(e) => 1 + count_insts(&e),
ExpandedBuiltIn::BtoI(e) => 1 + count_insts(&e),
ExpandedBuiltIn::ItoB(e) => 1 + count_insts(&e),
ExpandedBuiltIn::TypeQ(e) => 1 + count_insts(&e),
ExpandedBuiltIn::Dup(e) => 1 + count_insts(&e),
ExpandedBuiltIn::Vempty => 1,
ExpandedBuiltIn::Bempty => 1,
ExpandedBuiltIn::Vref(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Vappend(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Vlen(e) => 1 + count_insts(&e),
ExpandedBuiltIn::Vpush(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Vcons(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Vslice(e1, e2, e3) => {
1 + count_insts(&e1) + count_insts(&e2) + count_insts(&e3)
}
ExpandedBuiltIn::Vset(e1, e2, e3) => {
1 + count_insts(&e1) + count_insts(&e2) + count_insts(&e3)
}
ExpandedBuiltIn::Bref(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Bappend(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Blen(e) => 1 + count_insts(&e),
ExpandedBuiltIn::Bpush(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Bcons(e1, e2) => 1 + count_insts(&e1) + count_insts(&e2),
ExpandedBuiltIn::Bslice(e1, e2, e3) => {
1 + count_insts(&e1) + count_insts(&e2) + count_insts(&e3)
}
ExpandedBuiltIn::Bset(e1, e2, e3) => {
1 + count_insts(&e1) + count_insts(&e2) + count_insts(&e3)
}
ExpandedBuiltIn::Jmp(_) => 1,
ExpandedBuiltIn::Bez(_) => 1,
ExpandedBuiltIn::Bnz(_) => 1,
ExpandedBuiltIn::Store(_) => 1,
ExpandedBuiltIn::Load(_) => 1,
},
}
}