aboutsummaryrefslogtreecommitdiffstats
path: root/bytecode/src/encoding.rs
diff options
context:
space:
mode:
authorRose Hogenson <rhogenson@posteo.net>2022-01-09 08:40:09 -0800
committerRose Hogenson <rhogenson@posteo.net>2022-01-09 08:40:09 -0800
commit3ff7aac2d2eb2cbf2f854793fc0d7bc6f1f7d927 (patch)
treecef8ca0e77c40a70daaca40af25572437d563105 /bytecode/src/encoding.rs
downloadchromatopelma-3ff7aac2d2eb2cbf2f854793fc0d7bc6f1f7d927.tar.zst
Initial commit.
Not sure if everything here will be needed eventually, but we have a working bytecode interpreter. Next I will write the linker, then the core compiler, and finish with the macro expander.
Diffstat (limited to 'bytecode/src/encoding.rs')
-rw-r--r--bytecode/src/encoding.rs225
1 files changed, 225 insertions, 0 deletions
diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs
new file mode 100644
index 0000000..b3a7983
--- /dev/null
+++ b/bytecode/src/encoding.rs
@@ -0,0 +1,225 @@
+use crate::bytecode::Op;
+use std::io::Read;
+
+fn read_tag<T: Read>(prog: &mut T) -> Result<u64, String> {
+ let mut buf = [0; 8];
+ match prog.read_exact(&mut buf) {
+ Ok(()) => (),
+ Err(_) => {
+ return Err(String::from("error reading input"));
+ }
+ };
+ Ok(u64::from_le_bytes(buf))
+}
+
+fn read_i64<T: Read>(prog: &mut T) -> Result<i64, String> {
+ let mut buf = [0; 8];
+ match prog.read_exact(&mut buf) {
+ Ok(()) => (),
+ Err(_) => {
+ return Err(String::from("error reading input"));
+ }
+ };
+ Ok(i64::from_le_bytes(buf))
+}
+
+fn read_u8<T: Read>(prog: &mut T) -> Result<u8, String> {
+ let mut buf = vec![0];
+ match prog.read_exact(&mut buf) {
+ Ok(()) => (),
+ Err(_) => {
+ return Err(String::from("error reading input"));
+ }
+ };
+ 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(read_u8(prog)?),
+ 2030 => Op::Poke(read_u8(prog)?),
+ 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,
+ _ => {
+ return Err(String::from("invalid opcode"));
+ }
+ };
+ Ok(op)
+}
+
+pub fn decode(prog: &[u8]) -> Result<Vec<Op>, String> {
+ let mut reader = prog;
+ let mut out = Vec::new();
+ while reader.len() > 0 {
+ out.push(op_decoding(&mut reader)?);
+ }
+ Ok(out)
+}
+
+mod tests {
+ use super::*;
+
+ #[test]
+ fn decode_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])
+ );
+ }
+
+ #[test]
+ fn decode_add() {
+ assert_eq!(
+ Ok(vec![Op::Add]),
+ decode(&vec![0xfc, 0x3, 0, 0, 0, 0, 0, 0])
+ );
+ }
+
+ #[test]
+ fn decode_sub() {
+ assert_eq!(Ok(vec![Op::Sub]), decode(&vec![0x6, 0x4, 0, 0, 0, 0, 0, 0]));
+ }
+
+ #[test]
+ fn decode_mul() {
+ assert_eq!(
+ Ok(vec![Op::Mul]),
+ decode(&vec![0x10, 0x4, 0, 0, 0, 0, 0, 0])
+ );
+ }
+
+ #[test]
+ fn decode_div() {
+ 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])
+ );
+ }
+
+ #[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(10)]),
+ decode(&vec![0xe4, 0x7, 0, 0, 0, 0, 0, 0, 0xa])
+ );
+ }
+
+ #[test]
+ fn decode_poke() {
+ assert_eq!(
+ Ok(vec![Op::Poke(10)]),
+ decode(&vec![0xee, 0x7, 0, 0, 0, 0, 0, 0, 0xa])
+ );
+ }
+
+ #[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])
+ );
+ }
+}