use anyhow::{anyhow, Result};
use std::collections::HashMap;
use std::io::{Read, Write};
use crate::config::Config;
use crate::mir::{ArithOp, BinOp, FusedOp, Instruction, Mir, UniOp};
use crate::symbol::Loc;
use crate::utils::*;
const REG_GENERAL: u8 = 0x40;
const REG_STATIC: u8 = 0x80;
const REG_SPECIAL: u8 = 0xc0;
const REG_RET: u8 = REG_SPECIAL;
const REG_TEMP: u8 = REG_SPECIAL | 0x01;
const REG_LEFT: u8 = REG_SPECIAL | 0x02;
const REG_RIGHT: u8 = REG_SPECIAL | 0x03;
const LOC_MEM: u8 = 0x40;
const LOC_PARAM: u8 = 0x80;
const LOC_STACK: u8 = 0xc0;
const UNI_OP: u8 = 0x40;
const BIN_OP: u8 = 0x80;
const NOP: u8 = 0;
const END: u8 = 1;
const MOV: u8 = 2;
const LOAD: u8 = 3;
const SAVE: u8 = 4;
const LOAD_CONST: u8 = 5;
const LOAD_COMPLEX: u8 = 6;
const SAVE_COMPLEX: u8 = 7;
const BRANCH: u8 = 8;
const BRANCH_IF: u8 = 9;
const BRANCH_ELSE: u8 = 10;
const CALL: u8 = 11;
const LABEL: u8 = 12;
const IFELSE: u8 = 13;
const FUSED_MUL_ADD: u8 = 32;
const FUSED_MUL_SUB: u8 = 33;
const FUSED_NEG_MUL_ADD: u8 = 34;
const FUSED_NEG_MUL_SUB: u8 = 35;
const LOAD_MATH_PLUS: u8 = 36;
const LOAD_MATH_MINUS: u8 = 37;
const LOAD_MATH_TIMES: u8 = 38;
const LOAD_MATH_DIVIDE: u8 = 39;
const LOAD_CONST_MATH_PLUS: u8 = 40;
const LOAD_CONST_MATH_MINUS: u8 = 41;
const LOAD_CONST_MATH_TIMES: u8 = 42;
const LOAD_CONST_MATH_DIVIDE: u8 = 43;
const COMPLEX_BI_PLUS: u8 = 44;
const COMPLEX_BI_MINUS: u8 = 45;
const COMPLEX_BI_TIMES: u8 = 46;
const COMPLEX_BI_DIVIDE: u8 = 47;
const UNIOP_NEG: u8 = UniOp::Neg as u8;
const UNIOP_NOT: u8 = UniOp::Not as u8;
const UNIOP_ABS: u8 = UniOp::Abs as u8;
const UNIOP_ROOT: u8 = UniOp::Root as u8;
const UNIOP_REALROOT: u8 = UniOp::RealRoot as u8;
const UNIOP_RECIP: u8 = UniOp::Recip as u8;
const UNIOP_ROUND: u8 = UniOp::Round as u8;
const UNIOP_FLOOR: u8 = UniOp::Floor as u8;
const UNIOP_CEILING: u8 = UniOp::Ceiling as u8;
const UNIOP_TRUNC: u8 = UniOp::Trunc as u8;
const UNIOP_REAL: u8 = UniOp::Real as u8;
const UNIOP_IMAGINARY: u8 = UniOp::Imaginary as u8;
const UNIOP_CONJUGATE: u8 = UniOp::Conjugate as u8;
const UNIOP_HALF: u8 = UniOp::Half as u8;
const UNIOP_ISZERO: u8 = UniOp::IsZero as u8;
const UNIOP_ISNOTZERO: u8 = UniOp::IsNotZero as u8;
const BINOP_PLUS: u8 = BinOp::Plus as u8;
const BINOP_MINUS: u8 = BinOp::Minus as u8;
const BINOP_TIMES: u8 = BinOp::Times as u8;
const BINOP_DIVIDE: u8 = BinOp::Divide as u8;
const BINOP_GREATER_THAN: u8 = BinOp::GreaterThan as u8;
const BINOP_GREATER_THAN_EQUAL: u8 = BinOp::GreaterThanEqual as u8;
const BINOP_LITTLE_THAN: u8 = BinOp::LittleThan as u8;
const BINOP_LITTLE_THAN_EQUAL: u8 = BinOp::LittleThanEqual as u8;
const BINOP_EQUAL: u8 = BinOp::Equal as u8;
const BINOP_NOT_EQUAL: u8 = BinOp::NotEqual as u8;
const BINOP_AND: u8 = BinOp::And as u8;
const BINOP_AND_NOT: u8 = BinOp::AndNot as u8;
const BINOP_OR: u8 = BinOp::Or as u8;
const BINOP_XOR: u8 = BinOp::Xor as u8;
const BINOP_COMPLEX: u8 = BinOp::Complex as u8;
#[derive(Clone)]
pub struct MirWriter {
buf: Vec<u8>,
pub ip: usize,
}
impl Default for MirWriter {
fn default() -> Self {
Self::new()
}
}
impl MirWriter {
pub fn new() -> MirWriter {
MirWriter {
buf: Vec::new(),
ip: 0,
}
}
pub fn push(&mut self, ins: &Instruction) {
self.ip += 1;
match ins {
Instruction::Nop => self.append_byte(NOP),
Instruction::End => self.append_byte(END),
Instruction::Uni { op, dst, s1 } => {
let op = *op as u8;
assert!(op < 64);
self.append_byte(UNI_OP | op);
self.reg(*dst);
self.reg(*s1);
}
Instruction::Bi { op, dst, s1, s2 } => {
let op = *op as u8;
assert!(op < 64);
self.append_byte(BIN_OP | op);
self.reg(*dst);
self.reg(*s1);
self.reg(*s2);
}
Instruction::Mov { dst, s1 } => {
self.append_byte(MOV);
self.reg(*dst);
self.reg(*s1);
}
Instruction::Load { dst, loc } => {
self.append_byte(LOAD);
self.reg(*dst);
self.loc(*loc);
}
Instruction::LoadMath { op, dst, s1, loc } => {
let op = *op as u8;
assert!(op < 4);
self.append_byte(LOAD_MATH_PLUS + op);
self.reg(*dst);
self.reg(*s1);
self.loc(*loc);
}
Instruction::Save { src, loc } => {
self.append_byte(SAVE);
self.reg(*src);
self.loc(*loc);
}
Instruction::LoadConst { dst, idx } => {
self.append_byte(LOAD_CONST);
self.reg(*dst);
self.num(0, *idx);
}
Instruction::LoadComplex { xd, yd, loc } => {
self.append_byte(LOAD_COMPLEX);
self.reg(*xd);
self.reg(*yd);
self.loc(*loc);
}
Instruction::SaveComplex { xs, ys, loc } => {
self.append_byte(SAVE_COMPLEX);
self.reg(*xs);
self.reg(*ys);
self.loc(*loc);
}
Instruction::LoadConstMath { op, dst, s1, idx } => {
let op = *op as u8;
assert!(op < 4);
self.append_byte(LOAD_CONST_MATH_PLUS + op);
self.reg(*dst);
self.reg(*s1);
self.num(0, *idx);
}
Instruction::Branch { label } => {
self.append_byte(BRANCH);
self.string(label);
}
Instruction::BranchIf {
cond,
label,
is_else,
} => {
if *is_else {
self.append_byte(BRANCH_ELSE);
} else {
self.append_byte(BRANCH_IF);
}
self.reg(*cond);
self.string(label);
}
Instruction::IfElse {
dst,
true_val,
false_val,
cond,
} => {
self.append_byte(IFELSE);
self.reg(*dst);
self.reg(*true_val);
self.reg(*false_val);
self.loc(*cond);
}
Instruction::Call {
label, num_args, ..
} => {
self.append_byte(CALL);
assert!(*num_args < 256);
self.append_byte(*num_args as u8);
self.string(label);
}
Instruction::Label { label } => {
self.append_byte(LABEL);
self.string(label);
}
Instruction::Fused { op, dst, a, b, c } => {
let op = *op as u8;
assert!(op < 4);
self.append_byte(FUSED_MUL_ADD + op);
self.reg(*dst);
self.reg(*a);
self.reg(*b);
self.reg(*c);
}
Instruction::ComplexBi {
op,
xd,
yd,
x1,
y1,
x2,
y2,
} => {
let op = *op as u8;
assert!(op < 8);
self.append_byte(COMPLEX_BI_PLUS + op);
self.reg(*xd);
self.reg(*yd);
self.reg(*x1);
self.reg(*y1);
self.reg(*x2);
self.reg(*y2);
}
}
}
pub fn iter_mut(&mut self) -> MirIterator {
let buf = std::mem::take(&mut self.buf);
MirIterator { buf, pos: 0 }
}
pub fn iter(&self) -> MirIterator {
let buf = self.buf.clone();
MirIterator { buf, pos: 0 }
}
fn append_byte(&mut self, b: u8) {
self.buf.push(b);
}
pub fn serialize(&mut self, mir: &Mir) {
for ins in mir.code.iter() {
self.push(&ins);
}
}
fn num(&mut self, prefix: u8, mut n: u32) {
let num_bytes: u8 = 1 + ((32 - n.leading_zeros()) >> 3) as u8;
self.append_byte(prefix | num_bytes);
for _ in 0..num_bytes {
self.append_byte((n & 0xff) as u8);
n >>= 8;
}
}
fn reg(&mut self, r: Reg) {
match r {
Reg::Ret => self.append_byte(REG_RET),
Reg::Temp => self.append_byte(REG_TEMP),
Reg::Left => self.append_byte(REG_LEFT),
Reg::Right => self.append_byte(REG_RIGHT),
Reg::Gen(r) => self.append_byte(REG_GENERAL | r),
Reg::Static(s) => self.num(REG_STATIC, s),
}
}
fn loc(&mut self, loc: Loc) {
match loc {
Loc::Mem(idx) => self.num(LOC_MEM, idx),
Loc::Param(idx) => self.num(LOC_PARAM, idx),
Loc::Stack(idx) => self.num(LOC_STACK, idx),
};
}
fn string(&mut self, s: &str) {
let bytes = s.as_bytes();
let len = bytes.len();
assert!(len < 256);
self.append_byte(len as u8);
for b in bytes {
self.append_byte(*b);
}
}
}
impl Storage for Mir {
fn save(&self, stream: &mut impl Write) -> Result<()> {
stream.write_all(&Self::MAGIC.to_le_bytes())?;
stream.write_all(&self.code.buf.len().to_le_bytes())?;
stream.write_all(&self.code.buf)?;
stream.write_all(&self.consts.len().to_le_bytes())?;
for x in self.consts.iter() {
stream.write_all(&x.to_le_bytes())?;
}
Ok(())
}
fn load(stream: &mut impl Read, config: &Config) -> Result<Self> {
let mut bytes: [u8; 8] = [0; 8];
stream.read_exact(&mut bytes)?;
if usize::from_le_bytes(bytes) != Self::MAGIC {
return Err(anyhow!("invalid magic number (Mir)"));
}
stream.read_exact(&mut bytes)?;
let num_bytes = usize::from_le_bytes(bytes);
let mut buf: Vec<u8> = vec![0; num_bytes];
stream.read_exact(&mut buf)?;
stream.read_exact(&mut bytes)?;
let num_consts = usize::from_le_bytes(bytes);
let mut consts: Vec<f64> = Vec::new();
for _ in 0..num_consts {
stream.read_exact(&mut bytes)?;
consts.push(f64::from_le_bytes(bytes));
}
let mut iter = MirIterator::from_buf(&buf);
let mut ip = 0;
while iter.next().is_some() {
ip += 1;
}
let mut mir = Mir {
code: MirWriter { buf, ip },
consts,
labels: HashMap::new(),
config: config.clone(),
};
mir.populate_labels();
Ok(mir)
}
}
pub struct MirIterator {
buf: Vec<u8>,
pos: usize,
}
impl Iterator for MirIterator {
type Item = Instruction;
fn next(&mut self) -> Option<Self::Item> {
if !self.eof() {
let header = self.pop().unwrap();
match header & 0xc0 {
UNI_OP => self.uniop(header).ok(),
BIN_OP => self.binop(header).ok(),
_ => self.other(header).ok(),
}
} else {
None
}
}
}
impl MirIterator {
pub fn new(writer: &mut MirWriter) -> MirIterator {
let buf = std::mem::take(&mut writer.buf);
MirIterator { buf, pos: 0 }
}
pub fn from_buf(buf: &[u8]) -> MirIterator {
MirIterator {
buf: buf.to_vec(),
pos: 0,
}
}
fn pop(&mut self) -> Result<u8> {
if self.pos < self.buf.len() {
let c = self.buf[self.pos];
self.pos += 1;
Ok(c)
} else {
Err(anyhow!("unexpected EOF"))
}
}
fn eof(&self) -> bool {
self.pos >= self.buf.len()
}
fn uniop(&mut self, header: u8) -> Result<Instruction> {
let dst = self.reg()?;
let s1 = self.reg()?;
match header & 0x3f {
UNIOP_NEG => Ok(Instruction::Uni {
op: UniOp::Neg,
dst,
s1,
}),
UNIOP_NOT => Ok(Instruction::Uni {
op: UniOp::Not,
dst,
s1,
}),
UNIOP_ABS => Ok(Instruction::Uni {
op: UniOp::Abs,
dst,
s1,
}),
UNIOP_ROOT => Ok(Instruction::Uni {
op: UniOp::Root,
dst,
s1,
}),
UNIOP_REALROOT => Ok(Instruction::Uni {
op: UniOp::RealRoot,
dst,
s1,
}),
UNIOP_RECIP => Ok(Instruction::Uni {
op: UniOp::Recip,
dst,
s1,
}),
UNIOP_ROUND => Ok(Instruction::Uni {
op: UniOp::Round,
dst,
s1,
}),
UNIOP_FLOOR => Ok(Instruction::Uni {
op: UniOp::Floor,
dst,
s1,
}),
UNIOP_CEILING => Ok(Instruction::Uni {
op: UniOp::Ceiling,
dst,
s1,
}),
UNIOP_TRUNC => Ok(Instruction::Uni {
op: UniOp::Trunc,
dst,
s1,
}),
UNIOP_REAL => Ok(Instruction::Uni {
op: UniOp::Real,
dst,
s1,
}),
UNIOP_IMAGINARY => Ok(Instruction::Uni {
op: UniOp::Imaginary,
dst,
s1,
}),
UNIOP_CONJUGATE => Ok(Instruction::Uni {
op: UniOp::Conjugate,
dst,
s1,
}),
UNIOP_HALF => Ok(Instruction::Uni {
op: UniOp::Half,
dst,
s1,
}),
UNIOP_ISZERO => Ok(Instruction::Uni {
op: UniOp::IsZero,
dst,
s1,
}),
UNIOP_ISNOTZERO => Ok(Instruction::Uni {
op: UniOp::IsNotZero,
dst,
s1,
}),
_ => Err(anyhow!("undefined UnaryOp")),
}
}
fn binop(&mut self, header: u8) -> Result<Instruction> {
let dst = self.reg()?;
let s1 = self.reg()?;
let s2 = self.reg()?;
match header & 0x3f {
BINOP_PLUS => Ok(Instruction::Bi {
op: BinOp::Plus,
dst,
s1,
s2,
}),
BINOP_MINUS => Ok(Instruction::Bi {
op: BinOp::Minus,
dst,
s1,
s2,
}),
BINOP_TIMES => Ok(Instruction::Bi {
op: BinOp::Times,
dst,
s1,
s2,
}),
BINOP_DIVIDE => Ok(Instruction::Bi {
op: BinOp::Divide,
dst,
s1,
s2,
}),
BINOP_GREATER_THAN => Ok(Instruction::Bi {
op: BinOp::GreaterThan,
dst,
s1,
s2,
}),
BINOP_GREATER_THAN_EQUAL => Ok(Instruction::Bi {
op: BinOp::GreaterThanEqual,
dst,
s1,
s2,
}),
BINOP_LITTLE_THAN => Ok(Instruction::Bi {
op: BinOp::LittleThan,
dst,
s1,
s2,
}),
BINOP_LITTLE_THAN_EQUAL => Ok(Instruction::Bi {
op: BinOp::LittleThanEqual,
dst,
s1,
s2,
}),
BINOP_EQUAL => Ok(Instruction::Bi {
op: BinOp::Equal,
dst,
s1,
s2,
}),
BINOP_NOT_EQUAL => Ok(Instruction::Bi {
op: BinOp::NotEqual,
dst,
s1,
s2,
}),
BINOP_AND => Ok(Instruction::Bi {
op: BinOp::And,
dst,
s1,
s2,
}),
BINOP_AND_NOT => Ok(Instruction::Bi {
op: BinOp::AndNot,
dst,
s1,
s2,
}),
BINOP_OR => Ok(Instruction::Bi {
op: BinOp::Or,
dst,
s1,
s2,
}),
BINOP_XOR => Ok(Instruction::Bi {
op: BinOp::Xor,
dst,
s1,
s2,
}),
BINOP_COMPLEX => Ok(Instruction::Bi {
op: BinOp::Complex,
dst,
s1,
s2,
}),
_ => Err(anyhow!("undefined BinaryOp")),
}
}
pub fn other(&mut self, header: u8) -> Result<Instruction> {
match header & 0x3f {
NOP => Ok(Instruction::Nop),
END => Ok(Instruction::End),
MOV => {
let dst = self.reg()?;
let s1 = self.reg()?;
Ok(Instruction::Mov { dst, s1 })
}
LOAD => {
let dst = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::Load { dst, loc })
}
SAVE => {
let src = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::Save { src, loc })
}
LOAD_CONST => {
let dst = self.reg()?;
let num_bytes = self.pop()?;
let idx = self.num(num_bytes)?;
Ok(Instruction::LoadConst { dst, idx })
}
LOAD_COMPLEX => {
let xd = self.reg()?;
let yd = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::LoadComplex { xd, yd, loc })
}
SAVE_COMPLEX => {
let xs = self.reg()?;
let ys = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::SaveComplex { xs, ys, loc })
}
BRANCH => {
let label = self.string()?;
Ok(Instruction::Branch { label })
}
BRANCH_IF => {
let cond = self.reg()?;
let label = self.string()?;
Ok(Instruction::BranchIf {
cond,
label,
is_else: false,
})
}
BRANCH_ELSE => {
let cond = self.reg()?;
let label = self.string()?;
Ok(Instruction::BranchIf {
cond,
label,
is_else: true,
})
}
CALL => {
let num_args = self.pop()? as usize;
let op = self.string()?;
Ok(Instruction::Call {
label: op.to_string(),
num_args,
})
}
LABEL => {
let label = self.string()?;
Ok(Instruction::Label { label })
}
IFELSE => {
let dst = self.reg()?;
let true_val = self.reg()?;
let false_val = self.reg()?;
let cond = self.loc()?;
Ok(Instruction::IfElse {
dst,
true_val,
false_val,
cond,
})
}
FUSED_MUL_ADD => {
let dst = self.reg()?;
let a = self.reg()?;
let b = self.reg()?;
let c = self.reg()?;
Ok(Instruction::Fused {
op: FusedOp::MulAdd,
dst,
a,
b,
c,
})
}
FUSED_MUL_SUB => {
let dst = self.reg()?;
let a = self.reg()?;
let b = self.reg()?;
let c = self.reg()?;
Ok(Instruction::Fused {
op: FusedOp::MulSub,
dst,
a,
b,
c,
})
}
FUSED_NEG_MUL_ADD => {
let dst = self.reg()?;
let a = self.reg()?;
let b = self.reg()?;
let c = self.reg()?;
Ok(Instruction::Fused {
op: FusedOp::NegMulAdd,
dst,
a,
b,
c,
})
}
FUSED_NEG_MUL_SUB => {
let dst = self.reg()?;
let a = self.reg()?;
let b = self.reg()?;
let c = self.reg()?;
Ok(Instruction::Fused {
op: FusedOp::NegMulSub,
dst,
a,
b,
c,
})
}
LOAD_MATH_PLUS => {
let dst = self.reg()?;
let s1 = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::LoadMath {
op: ArithOp::Plus,
dst,
s1,
loc,
})
}
LOAD_MATH_MINUS => {
let dst = self.reg()?;
let s1 = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::LoadMath {
op: ArithOp::Minus,
dst,
s1,
loc,
})
}
LOAD_MATH_TIMES => {
let dst = self.reg()?;
let s1 = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::LoadMath {
op: ArithOp::Times,
dst,
s1,
loc,
})
}
LOAD_MATH_DIVIDE => {
let dst = self.reg()?;
let s1 = self.reg()?;
let loc = self.loc()?;
Ok(Instruction::LoadMath {
op: ArithOp::Divide,
dst,
s1,
loc,
})
}
LOAD_CONST_MATH_PLUS => {
let dst = self.reg()?;
let s1 = self.reg()?;
let num_bytes = self.pop()?;
let idx = self.num(num_bytes)?;
Ok(Instruction::LoadConstMath {
op: ArithOp::Plus,
dst,
s1,
idx,
})
}
LOAD_CONST_MATH_MINUS => {
let dst = self.reg()?;
let s1 = self.reg()?;
let num_bytes = self.pop()?;
let idx = self.num(num_bytes)?;
Ok(Instruction::LoadConstMath {
op: ArithOp::Minus,
dst,
s1,
idx,
})
}
LOAD_CONST_MATH_TIMES => {
let dst = self.reg()?;
let s1 = self.reg()?;
let num_bytes = self.pop()?;
let idx = self.num(num_bytes)?;
Ok(Instruction::LoadConstMath {
op: ArithOp::Times,
dst,
s1,
idx,
})
}
LOAD_CONST_MATH_DIVIDE => {
let dst = self.reg()?;
let s1 = self.reg()?;
let num_bytes = self.pop()?;
let idx = self.num(num_bytes)?;
Ok(Instruction::LoadConstMath {
op: ArithOp::Divide,
dst,
s1,
idx,
})
}
COMPLEX_BI_PLUS => {
let xd = self.reg()?;
let yd = self.reg()?;
let x1 = self.reg()?;
let y1 = self.reg()?;
let x2 = self.reg()?;
let y2 = self.reg()?;
Ok(Instruction::ComplexBi {
op: ArithOp::Plus,
xd,
yd,
x1,
y1,
x2,
y2,
})
}
COMPLEX_BI_MINUS => {
let xd = self.reg()?;
let yd = self.reg()?;
let x1 = self.reg()?;
let y1 = self.reg()?;
let x2 = self.reg()?;
let y2 = self.reg()?;
Ok(Instruction::ComplexBi {
op: ArithOp::Minus,
xd,
yd,
x1,
y1,
x2,
y2,
})
}
COMPLEX_BI_TIMES => {
let xd = self.reg()?;
let yd = self.reg()?;
let x1 = self.reg()?;
let y1 = self.reg()?;
let x2 = self.reg()?;
let y2 = self.reg()?;
Ok(Instruction::ComplexBi {
op: ArithOp::Times,
xd,
yd,
x1,
y1,
x2,
y2,
})
}
COMPLEX_BI_DIVIDE => {
let xd = self.reg()?;
let yd = self.reg()?;
let x1 = self.reg()?;
let y1 = self.reg()?;
let x2 = self.reg()?;
let y2 = self.reg()?;
Ok(Instruction::ComplexBi {
op: ArithOp::Divide,
xd,
yd,
x1,
y1,
x2,
y2,
})
}
_ => Err(anyhow!("undefined op code")),
}
}
fn num(&mut self, b: u8) -> Result<u32> {
let num_bytes: u8 = b & 15;
let mut val: u32 = 0;
for i in 0..num_bytes {
val += (self.pop()? as u32) << (8 * i);
}
Ok(val)
}
fn reg(&mut self) -> Result<Reg> {
let b = self.pop()?;
let r = match b & 0xc0 {
REG_GENERAL => Reg::Gen(b & 0x3f),
REG_STATIC => Reg::Static(self.num(b)?),
REG_SPECIAL => match b {
REG_RET => Reg::Ret,
REG_TEMP => Reg::Temp,
REG_LEFT => Reg::Left,
REG_RIGHT => Reg::Right,
_ => return Err(anyhow!("undefined Reg type")),
},
_ => return Err(anyhow!("undefined Reg type")),
};
Ok(r)
}
fn loc(&mut self) -> Result<Loc> {
let b = self.pop()?;
let loc = match b & 0xc0 {
LOC_MEM => Loc::Mem(self.num(b)?),
LOC_PARAM => Loc::Param(self.num(b)?),
LOC_STACK => Loc::Stack(self.num(b)?),
_ => return Err(anyhow!("undefined Loc type")),
};
Ok(loc)
}
fn string(&mut self) -> Result<String> {
let len = self.pop()? as usize;
let mut b: Vec<u8> = Vec::with_capacity(len);
for _ in 0..len {
b.push(self.pop()?)
}
Ok(String::from_utf8(b)?)
}
}