use std::fmt::Debug;
use crate::Error;
#[derive(Copy, Clone, Debug)]
pub enum Fetched {
Z,
B(u8),
BB(u8, u8),
BBB(u8, u8, u8),
BS(u8, u16),
BSS(u8, u16, u16),
S(u16),
W(u32), }
type FetchResult<Res> = Result<Res, Error>;
impl Fetched {
pub fn as_z(self) -> FetchResult<()> {
match self {
Fetched::Z => Ok(()),
_ => Err(Error::internal("invaid operand")),
}
}
pub fn as_b(self) -> FetchResult<u8> {
match self {
Fetched::B(a) => Ok(a),
_ => Err(Error::internal("invaid operand")),
}
}
pub fn as_bb(self) -> FetchResult<(u8, u8)> {
match self {
Fetched::BB(a, b) => Ok((a, b)),
_ => Err(Error::internal("invaid operand")),
}
}
pub fn as_bbb(self) -> FetchResult<(u8, u8, u8)> {
match self {
Fetched::BBB(a, b, c) => Ok((a, b, c)),
_ => Err(Error::internal("invalid operand")),
}
}
pub fn as_bs(self) -> FetchResult<(u8, u16)> {
match self {
Fetched::BS(a, b) => Ok((a, b)),
_ => Err(Error::internal("invalid operand")),
}
}
pub fn as_bss(self) -> FetchResult<(u8, u16, u16)> {
match self {
Fetched::BSS(a, b, c) => Ok((a, b, c)),
_ => Err(Error::internal("invalid operand")),
}
}
pub fn as_s(self) -> FetchResult<u16> {
match self {
Fetched::S(s) => Ok(s),
_ => Err(Error::internal("invalid operand")),
}
}
pub fn as_w(self) -> FetchResult<u32> {
match self {
Fetched::W(w) => Ok(w),
_ => Err(Error::internal("invalid operand")),
}
}
pub fn len(&self) -> usize {
match self {
Fetched::Z => 0,
Fetched::B(_) => 1,
Fetched::BB(_, _) => 2,
Fetched::BBB(_, _, _) => 3,
Fetched::BS(_, _) => 3,
Fetched::BSS(_, _, _) => 5,
Fetched::S(_) => 2,
Fetched::W(_) => 3,
}
}
pub fn is_empty(&self) -> bool {
matches!(self, Fetched::Z)
}
}
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum OpCode {
NOP,
MOVE,
LOADL,
LOADI,
LOADINEG,
LOADI__1,
LOADI_0,
LOADI_1,
LOADI_2,
LOADI_3,
LOADI_4,
LOADI_5,
LOADI_6,
LOADI_7,
LOADI16,
LOADI32,
LOADSYM,
LOADNIL,
LOADSELF,
LOADT,
LOADF,
GETGV,
SETGV,
GETSV,
SETSV,
GETIV,
SETIV,
GETCV,
SETCV,
GETCONST,
SETCONST,
GETMCNST,
SETMCNST,
GETUPVAR,
SETUPVAR,
GETIDX,
SETIDX,
JMP,
JMPIF,
JMPNOT,
JMPNIL,
JMPUW,
EXCEPT,
RESCUE,
RAISEIF,
SSEND,
SSENDB,
SEND,
SENDB,
CALL,
SUPER,
ARGARY,
ENTER,
KEY_P,
KEYEND,
KARG,
RETURN,
RETURN_BLK,
BREAK,
BLKPUSH,
ADD,
ADDI,
SUB,
SUBI,
MUL,
DIV,
EQ,
LT,
LE,
GT,
GE,
ARRAY,
ARRAY2,
ARYCAT,
ARYPUSH,
ARYSPLAT,
AREF,
ASET,
APOST,
INTERN,
SYMBOL,
STRING,
STRCAT,
HASH,
HASHADD,
HASHCAT,
LAMBDA,
BLOCK,
METHOD,
RANGE_INC,
RANGE_EXC,
OCLASS,
CLASS,
MODULE,
EXEC,
DEF,
ALIAS,
UNDEF,
SCLASS,
TCLASS,
DEBUG,
ERR,
EXT1,
EXT2,
EXT3,
STOP,
NumberOfOpcode, }
use self::OpCode::*;
const ENUM_TABLE: [OpCode; OpCode::NumberOfOpcode as usize] = [
NOP, MOVE, LOADL, LOADI, LOADINEG, LOADI__1, LOADI_0, LOADI_1, LOADI_2, LOADI_3, LOADI_4,
LOADI_5, LOADI_6, LOADI_7, LOADI16, LOADI32, LOADSYM, LOADNIL, LOADSELF, LOADT, LOADF, GETGV,
SETGV, GETSV, SETSV, GETIV, SETIV, GETCV, SETCV, GETCONST, SETCONST, GETMCNST, SETMCNST,
GETUPVAR, SETUPVAR, GETIDX, SETIDX, JMP, JMPIF, JMPNOT, JMPNIL, JMPUW, EXCEPT, RESCUE, RAISEIF,
SSEND, SSENDB, SEND, SENDB, CALL, SUPER, ARGARY, ENTER, KEY_P, KEYEND, KARG, RETURN,
RETURN_BLK, BREAK, BLKPUSH, ADD, ADDI, SUB, SUBI, MUL, DIV, EQ, LT, LE, GT, GE, ARRAY, ARRAY2,
ARYCAT, ARYPUSH, ARYSPLAT, AREF, ASET, APOST, INTERN, SYMBOL, STRING, STRCAT, HASH, HASHADD,
HASHCAT, LAMBDA, BLOCK, METHOD, RANGE_INC, RANGE_EXC, OCLASS, CLASS, MODULE, EXEC, DEF, ALIAS,
UNDEF, SCLASS, TCLASS, DEBUG, ERR, EXT1, EXT2, EXT3, STOP,
];
impl TryFrom<u8> for OpCode {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0..=105 => Ok(ENUM_TABLE[value as usize]),
_ => Err(Error::InvalidOpCode),
}
}
}
impl Debug for OpCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NOP => write!(f, "NOP"),
Self::MOVE => write!(f, "MOVE"),
Self::LOADL => write!(f, "LOADL"),
Self::LOADI => write!(f, "LOADI"),
Self::LOADINEG => write!(f, "LOADINEG"),
Self::LOADI__1 => write!(f, "LOADI__1"),
Self::LOADI_0 => write!(f, "LOADI_0"),
Self::LOADI_1 => write!(f, "LOADI_1"),
Self::LOADI_2 => write!(f, "LOADI_2"),
Self::LOADI_3 => write!(f, "LOADI_3"),
Self::LOADI_4 => write!(f, "LOADI_4"),
Self::LOADI_5 => write!(f, "LOADI_5"),
Self::LOADI_6 => write!(f, "LOADI_6"),
Self::LOADI_7 => write!(f, "LOADI_7"),
Self::LOADI16 => write!(f, "LOADI16"),
Self::LOADI32 => write!(f, "LOADI32"),
Self::LOADSYM => write!(f, "LOADSYM"),
Self::LOADNIL => write!(f, "LOADNIL"),
Self::LOADSELF => write!(f, "LOADSELF"),
Self::LOADT => write!(f, "LOADT"),
Self::LOADF => write!(f, "LOADF"),
Self::GETGV => write!(f, "GETGV"),
Self::SETGV => write!(f, "SETGV"),
Self::GETSV => write!(f, "GETSV"),
Self::SETSV => write!(f, "SETSV"),
Self::GETIV => write!(f, "GETIV"),
Self::SETIV => write!(f, "SETIV"),
Self::GETCV => write!(f, "GETCV"),
Self::SETCV => write!(f, "SETCV"),
Self::GETCONST => write!(f, "GETCONST"),
Self::SETCONST => write!(f, "SETCONST"),
Self::GETMCNST => write!(f, "GETMCNST"),
Self::SETMCNST => write!(f, "SETMCNST"),
Self::GETUPVAR => write!(f, "GETUPVAR"),
Self::SETUPVAR => write!(f, "SETUPVAR"),
Self::GETIDX => write!(f, "GETIDX"),
Self::SETIDX => write!(f, "SETIDX"),
Self::JMP => write!(f, "JMP"),
Self::JMPIF => write!(f, "JMPIF"),
Self::JMPNOT => write!(f, "JMPNOT"),
Self::JMPNIL => write!(f, "JMPNIL"),
Self::JMPUW => write!(f, "JMPUW"),
Self::EXCEPT => write!(f, "EXCEPT"),
Self::RESCUE => write!(f, "RESCUE"),
Self::RAISEIF => write!(f, "RAISEIF"),
Self::SSEND => write!(f, "SSEND"),
Self::SSENDB => write!(f, "SSENDB"),
Self::SEND => write!(f, "SEND"),
Self::SENDB => write!(f, "SENDB"),
Self::CALL => write!(f, "CALL"),
Self::SUPER => write!(f, "SUPER"),
Self::ARGARY => write!(f, "ARGARY"),
Self::ENTER => write!(f, "ENTER"),
Self::KEY_P => write!(f, "KEY_P"),
Self::KEYEND => write!(f, "KEYEND"),
Self::KARG => write!(f, "KARG"),
Self::RETURN => write!(f, "RETURN"),
Self::RETURN_BLK => write!(f, "RETURN_BLK"),
Self::BREAK => write!(f, "BREAK"),
Self::BLKPUSH => write!(f, "BLKPUSH"),
Self::ADD => write!(f, "ADD"),
Self::ADDI => write!(f, "ADDI"),
Self::SUB => write!(f, "SUB"),
Self::SUBI => write!(f, "SUBI"),
Self::MUL => write!(f, "MUL"),
Self::DIV => write!(f, "DIV"),
Self::EQ => write!(f, "EQ"),
Self::LT => write!(f, "LT"),
Self::LE => write!(f, "LE"),
Self::GT => write!(f, "GT"),
Self::GE => write!(f, "GE"),
Self::ARRAY => write!(f, "ARRAY"),
Self::ARRAY2 => write!(f, "ARRAY2"),
Self::ARYCAT => write!(f, "ARYCAT"),
Self::ARYPUSH => write!(f, "ARYPUSH"),
Self::ARYSPLAT => write!(f, "ARYSPLAT"),
Self::AREF => write!(f, "AREF"),
Self::ASET => write!(f, "ASET"),
Self::APOST => write!(f, "APOST"),
Self::INTERN => write!(f, "INTERN"),
Self::SYMBOL => write!(f, "SYMBOL"),
Self::STRING => write!(f, "STRING"),
Self::STRCAT => write!(f, "STRCAT"),
Self::HASH => write!(f, "HASH"),
Self::HASHADD => write!(f, "HASHADD"),
Self::HASHCAT => write!(f, "HASHCAT"),
Self::LAMBDA => write!(f, "LAMBDA"),
Self::BLOCK => write!(f, "BLOCK"),
Self::METHOD => write!(f, "METHOD"),
Self::RANGE_INC => write!(f, "RANGE_INC"),
Self::RANGE_EXC => write!(f, "RANGE_EXC"),
Self::OCLASS => write!(f, "OCLASS"),
Self::CLASS => write!(f, "CLASS"),
Self::MODULE => write!(f, "MODULE"),
Self::EXEC => write!(f, "EXEC"),
Self::DEF => write!(f, "DEF"),
Self::ALIAS => write!(f, "ALIAS"),
Self::UNDEF => write!(f, "UNDEF"),
Self::SCLASS => write!(f, "SCLASS"),
Self::TCLASS => write!(f, "TCLASS"),
Self::DEBUG => write!(f, "DEBUG"),
Self::ERR => write!(f, "ERR"),
Self::EXT1 => write!(f, "EXT1"),
Self::EXT2 => write!(f, "EXT2"),
Self::EXT3 => write!(f, "EXT3"),
Self::STOP => write!(f, "STOP"),
Self::NumberOfOpcode => write!(f, "[BUG] overflow opcode"),
}
}
}
fn fetch_z(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.is_empty() {
return Err(Error::internal("byte code too short"));
}
*bin = &bin[1..];
Ok(Fetched::Z)
}
fn fetch_b(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 2 {
return Err(Error::internal("byte code too short"));
}
let a = bin[1];
let operand = Fetched::B(a);
*bin = &bin[2..];
Ok(operand)
}
fn fetch_bb(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 3 {
return Err(Error::internal("byte code too short"));
}
let a = bin[1];
let b = bin[2];
let operand = Fetched::BB(a, b);
*bin = &bin[3..];
Ok(operand)
}
fn fetch_bbb(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 4 {
return Err(Error::internal("byte code too short"));
}
let a = bin[1];
let b = bin[2];
let c = bin[3];
let operand = Fetched::BBB(a, b, c);
*bin = &bin[4..];
Ok(operand)
}
fn fetch_bs(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 4 {
return Err(Error::internal("byte code too short"));
}
let a = bin[1];
let s = ((bin[2] as u16) << 8) | bin[3] as u16;
let operand = Fetched::BS(a, s);
*bin = &bin[4..];
Ok(operand)
}
fn fetch_bss(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 6 {
return Err(Error::internal("byte code too short"));
}
let a = bin[1];
let s1 = ((bin[2] as u16) << 8) | bin[3] as u16;
let s2 = ((bin[4] as u16) << 8) | bin[5] as u16;
let operand = Fetched::BSS(a, s1, s2);
*bin = &bin[6..];
Ok(operand)
}
fn fetch_s(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 3 {
return Err(Error::internal("byte code too short"));
}
let s = ((bin[1] as u16) << 8) | bin[2] as u16;
let operand = Fetched::S(s);
*bin = &bin[3..];
Ok(operand)
}
fn fetch_w(bin: &mut &[u8]) -> Result<Fetched, Error> {
if bin.len() < 4 {
return Err(Error::internal("byte code too short"));
}
let w = ((bin[1] as u32) << 16) | ((bin[2] as u32) << 8) | bin[3] as u32;
let operand = Fetched::W(w);
*bin = &bin[4..];
Ok(operand)
}
const Z: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_z;
const B: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_b;
const BB: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_bb;
const BBB: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_bbb;
const BS: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_bs;
const BSS: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_bss;
const S: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_s;
const W: fn(&mut &[u8]) -> Result<Fetched, Error> = fetch_w;
type FetchFn = fn(&mut &[u8]) -> Result<Fetched, Error>;
pub const FETCH_TABLE: [FetchFn; OpCode::NumberOfOpcode as usize] = [
Z, BB, BB, BB, BB, B, B, B, B, B, B, B, B, B, BS, BSS, BB, B, B, B, B, BB, BB, BB, BB, BB, BB,
BB, BB, BB, BB, BB, BB, BBB, BBB, B, B, S, BS, BS, BS, S, B, BB, B, BBB, BBB, BBB, BBB, Z, BB,
BS, W, BB, Z, BB, B, B, B, BS, B, BB, B, BB, B, B, B, B, B, B, B, BB, BBB, B, BB, B, BBB, BBB,
BBB, B, BB, BB, B, BB, BB, B, BB, BB, BB, B, B, B, BB, BB, BB, BB, BB, B, B, B, BBB, B, Z, Z,
Z, Z,
];