use ethnum::U256;
pub struct PushI;
pub struct PushB;
pub type HeapPos = u16;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ExpandedBuiltIn<E> {
Print(E),
Add(E, E),
Sub(E, E),
Mul(E, E),
Exp(E, E, u8),
Div(E, E),
Rem(E, E),
Not(E),
Or(E, E),
And(E, E),
Xor(E, E),
Eql(E, E),
Lt(E, E),
Gt(E, E),
Shl(E, E),
Shr(E, E),
Vempty,
Vlen(E),
Vref(E, E),
Vpush(E, E),
Vcons(E, E),
Vappend(E, E),
Vslice(E, E, E),
Vset(E, E, E),
Bempty,
Blen(E),
Bref(E, E),
Bpush(E, E),
Bcons(E, E),
Bappend(E, E),
Bslice(E, E, E),
Bset(E, E, E),
Bez(u16),
Bnz(u16),
Jmp(u16),
ItoB(E),
BtoI(E),
TypeQ(E),
Dup(E),
Load(HeapPos),
Store(HeapPos),
}
impl<E> ExpandedBuiltIn<E> {
pub fn arguments(&self) -> Vec<&E> {
let mut toret = Vec::with_capacity(3);
match self {
ExpandedBuiltIn::Add(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Sub(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Mul(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Exp(x, y, _) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Div(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Rem(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Print(x) => toret.push(x),
ExpandedBuiltIn::Not(x) => toret.push(x),
ExpandedBuiltIn::Or(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::And(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Xor(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Eql(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Lt(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Gt(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Shl(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Shr(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Vlen(x) => toret.push(x),
ExpandedBuiltIn::Vref(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Vpush(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Vcons(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Vappend(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Vslice(x, y, z) => toret.extend_from_slice(&[x, y, z]),
ExpandedBuiltIn::Vset(x, y, z) => toret.extend_from_slice(&[x, y, z]),
ExpandedBuiltIn::Blen(x) => toret.push(x),
ExpandedBuiltIn::Bref(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Bpush(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Bcons(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Bappend(x, y) => toret.extend_from_slice(&[x, y]),
ExpandedBuiltIn::Bslice(x, y, z) => toret.extend_from_slice(&[x, y, z]),
ExpandedBuiltIn::Bset(x, y, z) => toret.extend_from_slice(&[x, y, z]),
ExpandedBuiltIn::ItoB(x) => toret.push(x),
ExpandedBuiltIn::BtoI(x) => toret.push(x),
ExpandedBuiltIn::TypeQ(x) => toret.push(x),
ExpandedBuiltIn::Dup(x) => toret.push(x),
_ => {}
};
toret
}
pub fn structural_map(self, mut f: impl FnMut(E) -> E) -> Self {
match self {
ExpandedBuiltIn::Add(x, y) => ExpandedBuiltIn::Add(f(x), f(y)),
ExpandedBuiltIn::Sub(x, y) => ExpandedBuiltIn::Sub(f(x), f(y)),
ExpandedBuiltIn::Mul(x, y) => ExpandedBuiltIn::Mul(f(x), f(y)),
ExpandedBuiltIn::Exp(x, y, k) => ExpandedBuiltIn::Exp(f(x), f(y), k),
ExpandedBuiltIn::Div(x, y) => ExpandedBuiltIn::Div(f(x), f(y)),
ExpandedBuiltIn::Rem(x, y) => ExpandedBuiltIn::Rem(f(x), f(y)),
ExpandedBuiltIn::Print(x) => ExpandedBuiltIn::Print(f(x)),
ExpandedBuiltIn::Not(x) => ExpandedBuiltIn::Not(f(x)),
ExpandedBuiltIn::Or(x, y) => ExpandedBuiltIn::Or(f(x), f(y)),
ExpandedBuiltIn::And(x, y) => ExpandedBuiltIn::And(f(x), f(y)),
ExpandedBuiltIn::Xor(x, y) => ExpandedBuiltIn::Xor(f(x), f(y)),
ExpandedBuiltIn::Eql(x, y) => ExpandedBuiltIn::Eql(f(x), f(y)),
ExpandedBuiltIn::Lt(x, y) => ExpandedBuiltIn::Lt(f(x), f(y)),
ExpandedBuiltIn::Gt(x, y) => ExpandedBuiltIn::Gt(f(x), f(y)),
ExpandedBuiltIn::Shl(x, y) => ExpandedBuiltIn::Shl(f(x), f(y)),
ExpandedBuiltIn::Shr(x, y) => ExpandedBuiltIn::Shr(f(x), f(y)),
ExpandedBuiltIn::Vlen(x) => ExpandedBuiltIn::Vlen(f(x)),
ExpandedBuiltIn::Vref(x, y) => ExpandedBuiltIn::Vref(f(x), f(y)),
ExpandedBuiltIn::Vpush(x, y) => ExpandedBuiltIn::Vpush(f(x), f(y)),
ExpandedBuiltIn::Vcons(x, y) => ExpandedBuiltIn::Vcons(f(x), f(y)),
ExpandedBuiltIn::Vappend(x, y) => ExpandedBuiltIn::Vappend(f(x), f(y)),
ExpandedBuiltIn::Vslice(x, y, z) => ExpandedBuiltIn::Vslice(f(x), f(y), f(z)),
ExpandedBuiltIn::Vset(x, y, z) => ExpandedBuiltIn::Vset(f(x), f(y), f(z)),
ExpandedBuiltIn::Blen(x) => ExpandedBuiltIn::Blen(f(x)),
ExpandedBuiltIn::Bref(x, y) => ExpandedBuiltIn::Bref(f(x), f(y)),
ExpandedBuiltIn::Bpush(x, y) => ExpandedBuiltIn::Bpush(f(x), f(y)),
ExpandedBuiltIn::Bcons(x, y) => ExpandedBuiltIn::Bcons(f(x), f(y)),
ExpandedBuiltIn::Bappend(x, y) => ExpandedBuiltIn::Bappend(f(x), f(y)),
ExpandedBuiltIn::Bslice(x, y, z) => ExpandedBuiltIn::Bslice(f(x), f(y), f(z)),
ExpandedBuiltIn::Bset(x, y, z) => ExpandedBuiltIn::Bset(f(x), f(y), f(z)),
ExpandedBuiltIn::ItoB(x) => ExpandedBuiltIn::ItoB(f(x)),
ExpandedBuiltIn::BtoI(x) => ExpandedBuiltIn::BtoI(f(x)),
ExpandedBuiltIn::TypeQ(x) => ExpandedBuiltIn::TypeQ(f(x)),
ExpandedBuiltIn::Dup(x) => ExpandedBuiltIn::TypeQ(f(x)),
other => other,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum BuiltIn {
Print(Expr),
Add(Expr, Expr),
Sub(Expr, Expr),
Mul(Expr, Expr),
Div(Expr, Expr),
Rem(Expr, Expr),
Exp(Expr, Expr, u8),
And(Expr, Expr),
Or(Expr, Expr),
Xor(Expr, Expr),
Not(Expr),
Eql(Expr, Expr),
Lt(Expr, Expr),
Gt(Expr, Expr),
Shl(Expr, Expr),
Shr(Expr, Expr),
Vpush(Expr, Expr),
Vcons(Expr, Expr),
Vempty,
Vref(Expr, Expr),
Vlen(Expr),
Vappend(Expr, Expr),
Vslice(Expr, Expr, Expr),
Vset(Expr, Expr, Expr),
Bempty,
Blen(Expr),
Bref(Expr, Expr),
Bpush(Expr, Expr),
Bcons(Expr, Expr),
Bappend(Expr, Expr),
Bslice(Expr, Expr, Expr),
Bset(Expr, Expr, Expr),
ItoB(Expr),
BtoI(Expr),
TypeQ(Expr),
Dup(Expr),
Fail,
}
pub type Symbol = String;
pub type Symb = str;
pub type VarId = i32;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Value {
Int(U256),
Bytes(Vec<u8>),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Reserved {
SpenderTx = 0,
SpenderTxHash = 1,
ParentTxHash = 2,
ParentIndex = 3,
SelfHash = 4,
ParentValue = 5,
ParentDenom = 6,
ParentData = 7,
ParentHeight = 8,
SpenderIndex = 9,
LastHeader = 10,
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Statement {
SetLet(Vec<(Symbol, Expr)>, Vec<Statement>),
Loop(u16, Box<Statement>),
If(Box<Expr>, Box<Statement>, Box<Statement>),
Set(Symbol, Box<Expr>),
Noop,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum UnrolledStatement {
SetLet(Vec<(VarId, UnrolledExpr)>, Vec<UnrolledStatement>),
Loop(u16, Box<UnrolledStatement>),
If(
Box<UnrolledExpr>,
Box<UnrolledStatement>,
Box<UnrolledStatement>,
),
Set(VarId, Box<UnrolledExpr>),
Noop,
}
impl UnrolledStatement {
pub fn structural_map(
self,
stmt_map: &mut impl FnMut(Self) -> Self,
expr_map: &mut impl FnMut(UnrolledExpr) -> UnrolledExpr,
) -> Self {
let new_self = match self {
UnrolledStatement::SetLet(binds, stmt) => {
let binds = binds
.into_iter()
.map(|(i, j)| (i, j.structural_map(expr_map, stmt_map)))
.collect();
let stmt = stmt
.into_iter()
.map(|s| s.structural_map(stmt_map, expr_map))
.collect();
UnrolledStatement::SetLet(binds, stmt)
}
UnrolledStatement::Loop(n, body) => {
let body = Box::new(body.structural_map(stmt_map, expr_map));
UnrolledStatement::Loop(n, body)
}
UnrolledStatement::If(x, y, z) => {
let x = Box::new(x.structural_map(expr_map, stmt_map));
let y = Box::new(y.structural_map(stmt_map, expr_map));
let z = Box::new(z.structural_map(stmt_map, expr_map));
UnrolledStatement::If(x, y, z)
}
UnrolledStatement::Set(i, expr) => {
let expr = Box::new(expr.structural_map(expr_map, stmt_map));
UnrolledStatement::Set(i, expr)
}
UnrolledStatement::Noop => UnrolledStatement::Noop,
};
stmt_map(new_self)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MelExpr {
Value(Value),
BuiltIn(Box<ExpandedBuiltIn<MelExpr>>),
Seq(Vec<MelExpr>),
Loop(u16, Box<MelExpr>),
Hash(u16, Box<MelExpr>),
Sigeok(u16, Box<MelExpr>, Box<MelExpr>, Box<MelExpr>),
Noop,
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Expr {
Value(Value),
Vector(Vec<Expr>),
BuiltIn(Box<BuiltIn>),
App(Symbol, Vec<Expr>),
Var(Symbol),
Reserved(Reserved),
Let(Vec<(Symbol, Expr)>, Vec<Statement>, Box<Expr>),
If(Box<Expr>, Box<Expr>, Box<Expr>),
Hash(u16, Box<Expr>),
Sigeok(u16, Box<Expr>, Box<Expr>, Box<Expr>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnrolledExpr {
Value(Value),
BuiltIn(Box<ExpandedBuiltIn<UnrolledExpr>>),
Var(VarId),
Let(
Vec<(VarId, UnrolledExpr)>,
Vec<UnrolledStatement>,
Box<UnrolledExpr>,
),
If(Box<UnrolledExpr>, Box<UnrolledExpr>, Box<UnrolledExpr>),
Hash(u16, Box<UnrolledExpr>),
Sigeok(u16, Box<UnrolledExpr>, Box<UnrolledExpr>, Box<UnrolledExpr>),
}
impl UnrolledExpr {
pub fn structural_map(
self,
expr_map: &mut impl FnMut(Self) -> Self,
stmt_map: &mut impl FnMut(UnrolledStatement) -> UnrolledStatement,
) -> Self {
let new_self = match self {
UnrolledExpr::BuiltIn(builtin) => UnrolledExpr::BuiltIn(Box::new(
builtin.structural_map(|f| f.structural_map(expr_map, stmt_map)),
)),
UnrolledExpr::Let(x, y, z) => {
let x: Vec<(i32, UnrolledExpr)> = x
.into_iter()
.map(|(i, j)| (i, j.structural_map(expr_map, stmt_map)))
.collect();
let y: Vec<UnrolledStatement> = y
.into_iter()
.map(|i| i.structural_map(stmt_map, expr_map))
.collect();
let z = z.structural_map(expr_map, stmt_map);
UnrolledExpr::Let(x, y, Box::new(z))
}
UnrolledExpr::If(x, y, z) => UnrolledExpr::If(
Box::new(x.structural_map(expr_map, stmt_map)),
Box::new(y.structural_map(expr_map, stmt_map)),
Box::new(z.structural_map(expr_map, stmt_map)),
),
UnrolledExpr::Hash(x, y) => {
UnrolledExpr::Hash(x, Box::new(y.structural_map(expr_map, stmt_map)))
}
UnrolledExpr::Sigeok(n, x, y, z) => UnrolledExpr::Sigeok(
n,
Box::new(x.structural_map(expr_map, stmt_map)),
Box::new(y.structural_map(expr_map, stmt_map)),
Box::new(z.structural_map(expr_map, stmt_map)),
),
other => other,
};
expr_map(new_self)
}
}