use bincode::{Decode, Encode};
use crate::{calx::Calx, syntax::CalxSyntax};
#[derive(Debug, Clone, PartialEq, PartialOrd, Decode, Encode)]
pub enum CalxInstr {
LocalSet(usize),
LocalTee(usize),
LocalGet(usize),
LocalNew,
GlobalSet(usize),
GlobalGet(usize),
GlobalNew,
Const(Calx),
Dup,
Drop,
IntAdd,
IntMul,
IntDiv,
IntRem,
IntNeg,
IntShr,
IntShl,
IntEq,
IntNe,
IntLt,
IntLe,
IntGt,
IntGe,
Add,
Mul,
Div,
Neg,
NewList,
ListGet,
ListSet,
NewLink,
And,
Or,
Not,
Jmp(usize),
JmpOffset(i32),
JmpIf(usize),
JmpOffsetIf(i32),
Echo,
Call(String),
ReturnCall(String),
CallImport(String),
Unreachable,
Nop,
Quit(usize),
Return,
Assert(String),
Inspect,
}
impl TryFrom<&CalxSyntax> for CalxInstr {
type Error = String;
fn try_from(syntax: &CalxSyntax) -> Result<Self, Self::Error> {
match syntax {
CalxSyntax::LocalSet(a) => Ok(Self::LocalSet(a.to_owned())),
CalxSyntax::LocalTee(a) => Ok(Self::LocalTee(a.to_owned())),
CalxSyntax::LocalGet(a) => Ok(Self::LocalGet(a.to_owned())),
CalxSyntax::LocalNew => Ok(Self::LocalNew),
CalxSyntax::GlobalSet(a) => Ok(Self::GlobalSet(a.to_owned())),
CalxSyntax::GlobalGet(a) => Ok(Self::GlobalGet(a.to_owned())),
CalxSyntax::GlobalNew => Ok(Self::GlobalNew),
CalxSyntax::Const(a) => Ok(Self::Const(a.to_owned())),
CalxSyntax::Dup => Ok(Self::Dup),
CalxSyntax::Drop => Ok(Self::Drop),
CalxSyntax::IntAdd => Ok(Self::IntAdd),
CalxSyntax::IntMul => Ok(Self::IntMul),
CalxSyntax::IntDiv => Ok(Self::IntDiv),
CalxSyntax::IntRem => Ok(Self::IntRem),
CalxSyntax::IntNeg => Ok(Self::IntNeg),
CalxSyntax::IntShr => Ok(Self::IntShr),
CalxSyntax::IntShl => Ok(Self::IntShl),
CalxSyntax::IntEq => Ok(Self::IntEq),
CalxSyntax::IntNe => Ok(Self::IntNe),
CalxSyntax::IntLt => Ok(Self::IntLt),
CalxSyntax::IntLe => Ok(Self::IntLe),
CalxSyntax::IntGt => Ok(Self::IntGt),
CalxSyntax::IntGe => Ok(Self::IntGe),
CalxSyntax::Add => Ok(Self::Add),
CalxSyntax::Mul => Ok(Self::Mul),
CalxSyntax::Div => Ok(Self::Div),
CalxSyntax::Neg => Ok(Self::Neg),
CalxSyntax::NewList => Ok(Self::NewList),
CalxSyntax::ListGet => Ok(Self::ListGet),
CalxSyntax::ListSet => Ok(Self::ListSet),
CalxSyntax::NewLink => Ok(Self::NewLink),
CalxSyntax::And => Ok(Self::And),
CalxSyntax::Or => Ok(Self::Or),
CalxSyntax::Not => Ok(Self::Not),
CalxSyntax::Br(_) => Err("Br should be handled manually".to_string()),
CalxSyntax::BrIf(_) => Err("BrIf should be handled manually".to_owned()),
CalxSyntax::Block { .. } => Err("Block should be handled manually".to_string()),
CalxSyntax::BlockEnd(a) => Err(format!("BlockEnd should be handled manually: {}", a)),
CalxSyntax::Echo => Ok(Self::Echo),
CalxSyntax::Call(a) => Ok(Self::Call(a.to_owned())),
CalxSyntax::ReturnCall(a) => Ok(Self::ReturnCall(a.to_owned())),
CalxSyntax::CallImport(a) => Ok(Self::CallImport(a.to_owned())),
CalxSyntax::Unreachable => Ok(Self::Unreachable),
CalxSyntax::Nop => Ok(Self::Nop),
CalxSyntax::Quit(a) => Ok(Self::Quit(a.to_owned())),
CalxSyntax::Return => Ok(Self::Return),
CalxSyntax::Assert(a) => Ok(Self::Assert(a.to_owned())),
CalxSyntax::Inspect => Ok(Self::Inspect),
CalxSyntax::If { .. } => Err("If should be handled manually".to_string()),
CalxSyntax::ThenEnd => Err("ThenEnd should be handled manually".to_string()),
CalxSyntax::ElseEnd => Err("ElseEnd should be handled manually".to_string()),
CalxSyntax::Do(_) => Err("do should be handled manually".to_string()),
}
}
}
impl CalxInstr {
pub fn stack_arity(&self) -> (usize, usize) {
match self {
CalxInstr::LocalSet(_) => (1, 0),
CalxInstr::LocalTee(_) => (1, 1), CalxInstr::LocalGet(_) => (0, 1),
CalxInstr::LocalNew => (0, 0),
CalxInstr::GlobalSet(_) => (1, 0),
CalxInstr::GlobalGet(_) => (0, 1),
CalxInstr::GlobalNew => (0, 0),
CalxInstr::Const(_) => (0, 1),
CalxInstr::Dup => (1, 2),
CalxInstr::Drop => (1, 0),
CalxInstr::IntAdd => (2, 1),
CalxInstr::IntMul => (2, 1),
CalxInstr::IntDiv => (2, 1),
CalxInstr::IntRem => (2, 1),
CalxInstr::IntNeg => (1, 1),
CalxInstr::IntShr => (2, 1),
CalxInstr::IntShl => (2, 1),
CalxInstr::IntEq => (2, 1),
CalxInstr::IntNe => (2, 1),
CalxInstr::IntLt => (2, 1),
CalxInstr::IntLe => (2, 1),
CalxInstr::IntGt => (2, 1),
CalxInstr::IntGe => (2, 1),
CalxInstr::Add => (2, 1),
CalxInstr::Mul => (2, 1),
CalxInstr::Div => (2, 1),
CalxInstr::Neg => (1, 1),
CalxInstr::NewList => (0, 1),
CalxInstr::ListGet => (2, 1),
CalxInstr::ListSet => (3, 0),
CalxInstr::NewLink => (0, 1),
CalxInstr::And => (2, 1),
CalxInstr::Or => (2, 1),
CalxInstr::Not => (1, 1),
CalxInstr::Jmp(_) => (0, 0),
CalxInstr::JmpOffset(_) => (0, 0),
CalxInstr::JmpIf(_) => (1, 0),
CalxInstr::JmpOffsetIf(_) => (1, 0),
CalxInstr::Echo => (1, 0),
CalxInstr::Call(_) => (0, 0), CalxInstr::ReturnCall(_) => (0, 0), CalxInstr::CallImport(_) => (0, 0), CalxInstr::Unreachable => (0, 0), CalxInstr::Nop => (0, 0),
CalxInstr::Quit(_) => (0, 0),
CalxInstr::Return => (1, 0), CalxInstr::Assert(_) => (1, 0),
CalxInstr::Inspect => (0, 0),
}
}
}
pub const CALX_INSTR_EDITION: &str = "0.2";