aboutsummaryrefslogtreecommitdiffstats
path: root/bytecode/src/encoding.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bytecode/src/encoding.rs')
-rw-r--r--bytecode/src/encoding.rs279
1 files changed, 112 insertions, 167 deletions
diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs
index deacae5..8f49ab6 100644
--- a/bytecode/src/encoding.rs
+++ b/bytecode/src/encoding.rs
@@ -1,225 +1,170 @@
-use crate::bytecode::Op;
+// This file must stay in sync with encoding.csc.
+use crate::bytecode::{Arg, Local, Op};
+use crate::data::Value;
+use std::io;
use std::io::Read;
-fn read_tag<T: Read>(prog: &mut T) -> Result<u64, String> {
+fn read_const<T: Read>(prog: &mut T) -> Result<Value, String> {
let mut buf = [0; 8];
match prog.read_exact(&mut buf) {
Ok(()) => (),
- Err(_) => {
- return Err(String::from("error reading input"));
+ Err(e) => {
+ return Err(format!("error reading input: {}", e));
}
};
- Ok(u64::from_le_bytes(buf))
+ Ok(Value(u64::from_le_bytes(buf)))
}
-fn read_i64<T: Read>(prog: &mut T) -> Result<i64, String> {
- let mut buf = [0; 8];
+fn read_local<T: Read>(prog: &mut T) -> Result<Local, String> {
+ let mut buf = [0; 1];
match prog.read_exact(&mut buf) {
Ok(()) => (),
- Err(_) => {
- return Err(String::from("error reading input"));
+ Err(e) => {
+ return Err(format!("error reading input: {}", e));
}
};
- Ok(i64::from_le_bytes(buf))
+ Ok(Local(buf[0]))
}
-fn read_u8<T: Read>(prog: &mut T) -> Result<u8, String> {
- let mut buf = vec![0];
+fn read_arg<T: Read>(prog: &mut T, is_const: bool) -> Result<Arg, String> {
+ if is_const {
+ let c = read_const(prog)?;
+ return Ok(Arg::Const(c));
+ }
+ let l = read_local(prog)?;
+ Ok(Arg::L(l))
+}
+
+fn op_decoding<T: Read>(prog: &mut T) -> Result<Option<Op>, String> {
+ let mut buf = [0; 1];
match prog.read_exact(&mut buf) {
Ok(()) => (),
- Err(_) => {
- return Err(String::from("error reading input"));
+ Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
+ return Ok(None);
+ }
+ Err(e) => {
+ return Err(format!("error reading input: {}", e));
}
};
- Ok(buf[0])
-}
-
-fn op_decoding<T: Read>(prog: &mut T) -> Result<Op, String> {
- let op = match read_tag(prog)? {
- 1010 => Op::Const(read_i64(prog)?),
- 1020 => Op::Add,
- 1030 => Op::Sub,
- 1040 => Op::Mul,
- 1050 => Op::Div,
- 1060 => Op::Mod,
- 2010 => Op::Alloc,
- 2020 => Op::Peek,
- 2030 => Op::Poke,
- 2040 => Op::PeekByte,
- 2050 => Op::PokeByte,
- 3010 => Op::Pop,
- 3020 => Op::Local(read_u8(prog)?),
- 4010 => Op::If(read_i64(prog)?),
- 4020 => Op::Call(read_u8(prog)?),
- 4030 => Op::Ret,
- 4040 => Op::Exit,
- 5010 => Op::PutC,
- 5020 => Op::GetC,
+ let tag = buf[0] >> 2;
+ let arg1_const = buf[0] & 2 != 0;
+ let arg2_const = buf[0] & 1 != 0;
+ let op = match tag {
+ // Note: arguments are evaluated left to right.
+ 0 => Op::Mov(read_local(prog)?, read_arg(prog, arg1_const)?),
+ 1 => Op::JmpIf(read_arg(prog, arg1_const)?, read_arg(prog, arg2_const)?),
+ 2 => Op::Jmp(read_arg(prog, arg1_const)?),
+ 3 => Op::Alloc(read_local(prog)?, read_arg(prog, arg1_const)?),
+ 4 => Op::Peek(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 5 => Op::Poke(
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, false)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 6 => Op::Add(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 7 => Op::Sub(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 8 => Op::Mul(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 9 => Op::Div(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 10 => Op::Mod(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 11 => Op::PeekByte(
+ read_local(prog)?,
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 12 => Op::PokeByte(
+ read_arg(prog, arg1_const)?,
+ read_arg(prog, false)?,
+ read_arg(prog, arg2_const)?,
+ ),
+ 13 => Op::Exit(read_arg(prog, arg1_const)?),
+ 14 => Op::AllocBytevector(read_local(prog)?, read_arg(prog, arg1_const)?),
_ => {
return Err(String::from("invalid opcode"));
}
};
- Ok(op)
+ Ok(Some(op))
}
-pub fn decode(prog: &[u8]) -> Result<Vec<Op>, String> {
- let mut reader = prog;
+pub fn decode<T: Read>(prog: &mut T) -> Result<Vec<Op>, String> {
let mut out = Vec::new();
- while reader.len() > 0 {
- out.push(op_decoding(&mut reader)?);
+ loop {
+ match op_decoding(prog)? {
+ Some(op) => {
+ out.push(op);
+ }
+ None => {
+ return Ok(out);
+ }
+ }
}
- Ok(out)
}
mod tests {
use super::*;
+ use Arg::*;
+ use Op::*;
#[test]
- fn decode_const() {
+ fn decode_mov_const() {
assert_eq!(
- Ok(vec![Op::Const(10)]),
- decode(&vec![0xf2, 0x3, 0, 0, 0, 0, 0, 0, 0xa, 0, 0, 0, 0, 0, 0, 0])
+ Ok(vec![Mov(Local(0), Const(Value::from_int(10)))]),
+ decode(&mut vec![0x2, 0, 0x15, 0, 0, 0, 0, 0, 0, 0].as_slice())
);
}
#[test]
- fn decode_add() {
+ fn decode_mov_local() {
assert_eq!(
- Ok(vec![Op::Add]),
- decode(&vec![0xfc, 0x3, 0, 0, 0, 0, 0, 0])
+ Ok(vec![Mov(Local(0), L(Local(1)))]),
+ decode(&mut vec![0, 0, 1].as_slice()),
);
}
#[test]
- fn decode_sub() {
- assert_eq!(Ok(vec![Op::Sub]), decode(&vec![0x6, 0x4, 0, 0, 0, 0, 0, 0]));
- }
-
- #[test]
- fn decode_mul() {
+ fn decode_jmpif() {
assert_eq!(
- Ok(vec![Op::Mul]),
- decode(&vec![0x10, 0x4, 0, 0, 0, 0, 0, 0])
+ Ok(vec![JmpIf(L(Local(0)), L(Local(1)))]),
+ decode(&mut vec![4, 0, 1].as_slice())
);
}
#[test]
- fn decode_div() {
+ fn decode_jmp() {
assert_eq!(
- Ok(vec![Op::Div]),
- decode(&vec![0x1a, 0x4, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_mod() {
- assert_eq!(
- Ok(vec![Op::Mod]),
- decode(&vec![0x24, 0x4, 0, 0, 0, 0, 0, 0])
+ Ok(vec![Jmp(L(Local(0)))]),
+ decode(&mut vec![8, 0].as_slice())
);
}
#[test]
fn decode_alloc() {
assert_eq!(
- Ok(vec![Op::Alloc]),
- decode(&vec![0xda, 0x7, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_peek() {
- assert_eq!(
- Ok(vec![Op::Peek]),
- decode(&vec![0xe4, 0x7, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_poke() {
- assert_eq!(
- Ok(vec![Op::Poke]),
- decode(&vec![0xee, 0x7, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_peek_byte() {
- assert_eq!(
- Ok(vec![Op::PeekByte]),
- decode(&vec![0xf8, 0x7, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_poke_byte() {
- assert_eq!(
- Ok(vec![Op::PokeByte]),
- decode(&vec![0x2, 0x8, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_pop() {
- assert_eq!(
- Ok(vec![Op::Pop]),
- decode(&vec![0xc2, 0xb, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_local() {
- assert_eq!(
- Ok(vec![Op::Local(10)]),
- decode(&vec![0xcc, 0xb, 0, 0, 0, 0, 0, 0, 0xa])
- );
- }
-
- #[test]
- fn decode_if() {
- assert_eq!(
- Ok(vec![Op::If(10)]),
- decode(&vec![0xaa, 0xf, 0, 0, 0, 0, 0, 0, 0xa, 0, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_call() {
- assert_eq!(
- Ok(vec![Op::Call(10)]),
- decode(&vec![0xb4, 0xf, 0, 0, 0, 0, 0, 0, 0xa])
- );
- }
-
- #[test]
- fn decode_ret() {
- assert_eq!(
- Ok(vec![Op::Ret]),
- decode(&vec![0xbe, 0xf, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_exit() {
- assert_eq!(
- Ok(vec![Op::Exit]),
- decode(&vec![0xc8, 0xf, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_putc() {
- assert_eq!(
- Ok(vec![Op::PutC]),
- decode(&vec![0x92, 0x13, 0, 0, 0, 0, 0, 0])
- );
- }
-
- #[test]
- fn decode_getc() {
- assert_eq!(
- Ok(vec![Op::GetC]),
- decode(&vec![0x9c, 0x13, 0, 0, 0, 0, 0, 0])
+ Ok(vec![Alloc(Local(0), L(Local(1)))]),
+ decode(&mut vec![12, 0, 1].as_slice())
);
}
}