mod opcode;
pub use opcode::*;
mod operand;
pub use operand::*;
mod operation;
pub use operation::*;
mod bytes;
mod parse;
use crate::{Registers, Stack};
use console::{
network::{
prelude::{
alt,
bail,
ensure,
error,
fmt,
map,
tag,
Debug,
Display,
Error,
Formatter,
FromBytes,
FromStr,
IoResult,
Parser,
ParserResult,
Read,
Result,
Sanitizer,
ToBytes,
Write,
},
Network,
},
program::{Register, RegisterType},
};
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Instruction<N: Network> {
Abs(Abs<N>),
AbsWrapped(AbsWrapped<N>),
Add(Add<N>),
AddWrapped(AddWrapped<N>),
And(And<N>),
AssertEq(AssertEq<N>),
AssertNeq(AssertNeq<N>),
Call(Call<N>),
Cast(Cast<N>),
CommitBHP256(CommitBHP256<N>),
CommitBHP512(CommitBHP512<N>),
CommitBHP768(CommitBHP768<N>),
CommitBHP1024(CommitBHP1024<N>),
CommitPED64(CommitPED64<N>),
CommitPED128(CommitPED128<N>),
Div(Div<N>),
DivWrapped(DivWrapped<N>),
Double(Double<N>),
GreaterThan(GreaterThan<N>),
GreaterThanOrEqual(GreaterThanOrEqual<N>),
HashBHP256(HashBHP256<N>),
HashBHP512(HashBHP512<N>),
HashBHP768(HashBHP768<N>),
HashBHP1024(HashBHP1024<N>),
HashPED64(HashPED64<N>),
HashPED128(HashPED128<N>),
HashPSD2(HashPSD2<N>),
HashPSD4(HashPSD4<N>),
HashPSD8(HashPSD8<N>),
Inv(Inv<N>),
IsEq(IsEq<N>),
IsNeq(IsNeq<N>),
LessThan(LessThan<N>),
LessThanOrEqual(LessThanOrEqual<N>),
Modulo(Modulo<N>),
Mul(Mul<N>),
MulWrapped(MulWrapped<N>),
Nand(Nand<N>),
Neg(Neg<N>),
Nor(Nor<N>),
Not(Not<N>),
Or(Or<N>),
Pow(Pow<N>),
PowWrapped(PowWrapped<N>),
Rem(Rem<N>),
RemWrapped(RemWrapped<N>),
Shl(Shl<N>),
ShlWrapped(ShlWrapped<N>),
Shr(Shr<N>),
ShrWrapped(ShrWrapped<N>),
Square(Square<N>),
SquareRoot(SquareRoot<N>),
Sub(Sub<N>),
SubWrapped(SubWrapped<N>),
Ternary(Ternary<N>),
Xor(Xor<N>),
}
#[macro_export]
macro_rules! instruction {
($object:expr, |$input:ident| $operation:block) => {{ $crate::instruction!(instruction, $object, |$input| $operation) }};
($object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!(instruction, $object, |$input| { $operation }) }};
($macro_:ident, $object:expr, |$input:ident| $operation:block) => {
$macro_!{$object, |$input| $operation, {
Abs,
AbsWrapped,
Add,
AddWrapped,
And,
AssertEq,
AssertNeq,
Call,
Cast,
CommitBHP256,
CommitBHP512,
CommitBHP768,
CommitBHP1024,
CommitPED64,
CommitPED128,
Div,
DivWrapped,
Double,
GreaterThan,
GreaterThanOrEqual,
HashBHP256,
HashBHP512,
HashBHP768,
HashBHP1024,
HashPED64,
HashPED128,
HashPSD2,
HashPSD4,
HashPSD8,
Inv,
IsEq,
IsNeq,
LessThan,
LessThanOrEqual,
Modulo,
Mul,
MulWrapped,
Nand,
Neg,
Nor,
Not,
Or,
Pow,
PowWrapped,
Rem,
RemWrapped,
Shl,
ShlWrapped,
Shr,
ShrWrapped,
Square,
SquareRoot,
Sub,
SubWrapped,
Ternary,
Xor,
}}
};
($macro_:ident, $object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!($macro_, $object, |$input| { $operation }) }};
($macro_:ident!($object:expr, $input:ident)) => {{ $crate::instruction!($macro_, $object, |$input| {}) }};
($object:expr, |InstructionMember| $operation:block, { $( $variant:ident, )+ }) => {{
match $object {
$( Self::$variant(..) => {{
type InstructionMember<N> = $variant<N>;
$operation
}} ),+
}
}};
($object:expr, |InstructionMember| $operation:expr, { $( $variant:ident, )+ }) => {{
$crate::instruction!($object, |InstructionMember| { $operation }, { $( $variant, )+ })
}};
($object:expr, |$instruction:ident| $operation:block, { $( $variant:ident, )+ }) => {{
match $object { $( Self::$variant($instruction) => { $operation } ),+ }
}};
($object:expr, |$instruction:ident| $operation:expr, { $( $variant:ident, )+ }) => {{
$crate::instruction!($object, |$instruction| { $operation }, { $( $variant, )+ })
}};
}
macro_rules! derive_from_operation {
($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => {
$(impl<N: Network> From<$variant<N>> for Instruction<N> {
#[inline]
fn from(operation: $variant<N>) -> Self {
Self::$variant(operation)
}
})+
}
}
instruction!(derive_from_operation, Instruction, |None| {});
macro_rules! opcodes {
($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => { [$( $variant::<N>::opcode() ),+] }
}
impl<N: Network> Instruction<N> {
pub const OPCODES: &'static [Opcode] = &instruction!(opcodes, Instruction, |None| {});
#[inline]
pub const fn opcode(&self) -> Opcode {
instruction!(self, |InstructionMember| InstructionMember::<N>::opcode())
}
#[inline]
pub fn operands(&self) -> &[Operand<N>] {
instruction!(self, |instruction| instruction.operands())
}
#[inline]
pub fn destinations(&self) -> Vec<Register<N>> {
instruction!(self, |instruction| instruction.destinations())
}
#[inline]
pub fn evaluate<A: circuit::Aleo<Network = N>>(
&self,
stack: &Stack<N>,
registers: &mut Registers<N, A>,
) -> Result<()> {
instruction!(self, |instruction| instruction.evaluate::<A>(stack, registers))
}
#[inline]
pub fn execute<A: circuit::Aleo<Network = N>>(
&self,
stack: &Stack<N>,
registers: &mut Registers<N, A>,
) -> Result<()> {
instruction!(self, |instruction| instruction.execute::<A>(stack, registers))
}
#[inline]
pub fn output_types(&self, stack: &Stack<N>, input_types: &[RegisterType<N>]) -> Result<Vec<RegisterType<N>>> {
instruction!(self, |instruction| instruction.output_types(stack, input_types))
}
}
impl<N: Network> Debug for Instruction<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl<N: Network> Display for Instruction<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
instruction!(self, |instruction| write!(f, "{};", instruction))
}
}
#[cfg(test)]
mod tests {
use super::*;
use console::network::Testnet3;
type CurrentNetwork = Testnet3;
#[test]
fn test_opcodes() {
assert_eq!(
56,
Instruction::<CurrentNetwork>::OPCODES.len(),
"Update me if the number of instructions changes."
);
}
}