aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody <cody@codyq.dev>2023-04-08 20:36:04 -0500
committerCody <cody@codyq.dev>2023-04-08 20:36:04 -0500
commit637dcc8c495c272a66788a650c09d20178d57f55 (patch)
treec7b163ed55f73ec41bdba841ac73cd4788effed2
parenta990b1f869385a2cf9da38176b709261bd2b30cf (diff)
downloadsloth-637dcc8c495c272a66788a650c09d20178d57f55.tar.gz
Finnish 🇫🇮 the disassemble portion of macro
-rw-r--r--crates/sloth_bytecode/macros/src/lib.rs87
-rw-r--r--crates/sloth_bytecode/src/lib.rs186
2 files changed, 93 insertions, 180 deletions
diff --git a/crates/sloth_bytecode/macros/src/lib.rs b/crates/sloth_bytecode/macros/src/lib.rs
index e07a027..41035b9 100644
--- a/crates/sloth_bytecode/macros/src/lib.rs
+++ b/crates/sloth_bytecode/macros/src/lib.rs
@@ -1,9 +1,11 @@
use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote};
+use quote::quote;
use syn::parse::Parse;
use syn::punctuated::Punctuated;
use syn::{bracketed, parse_macro_input, LitInt, LitStr, Token};
+// TODO: Rename args to operands?
+
struct DslInstructionInput {
opcode: LitInt,
name: Ident,
@@ -53,9 +55,16 @@ fn into_enum_field(instruction: &DslInstructionInput) -> TokenStream {
let args = args.iter();
- quote! {
- #[doc = #description]
- #name ( #( #args ),* ) = #opcode
+ if args.len() > 0 {
+ quote! {
+ #[doc = #description]
+ #name ( #( #args ),* ) = #opcode
+ }
+ } else {
+ quote! {
+ #[doc = #description]
+ #name = #opcode
+ }
}
}
@@ -67,23 +76,44 @@ fn into_bytecode_parser(instruction: &DslInstructionInput) -> TokenStream {
description: _,
} = instruction;
- let args = args.iter().map(|arg| {
- let read_ident = format_ident!("read_{}", arg);
-
- let _chunk_codes = arg;
+ if args.is_empty() {
+ return quote! {
+ #opcode => Self :: #name
+ };
+ }
- quote! {
- {
- let a: #arg = (chunk.code[*offset] << 56) + (chunk)
- cursor . #read_ident ::<byteorder::LittleEndian>().unwrap()
- }
+ let mut arg_params = Vec::new();
+ for arg in args {
+ let size = match arg.to_string().as_str() {
+ "u128" => 128,
+ "u64" => 64,
+ "u32" => 32,
+ "u16" => 16,
+ "u8" => 8,
+ typ => panic!("Unsupported instruction arg type '{typ}'"),
+ } as usize;
+
+ let bytes = size / 8;
+
+ let mut chunks = Vec::new();
+ for byte in 0..bytes {
+ let shift_amount = size - (byte + 1) * bytes;
+ chunks.push(quote! {
+ ((chunk.code[*offset + #byte] as #arg) << #shift_amount)
+ });
}
- });
+
+ arg_params.push(quote! {
+ let value = #( #chunks )+* ;
+ *offset += #bytes ;
+ value
+ });
+ }
quote! {
#opcode => {
- Self:: #name (
- #( #args ),*
+ Self :: #name (
+ #( { #arg_params } ),*
)
}
}
@@ -109,9 +139,9 @@ pub fn instructions(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
.collect::<Vec<_>>();
// Building out the expanded code
- let expanded = quote! {
+ quote! {
#[repr(u8)]
- #[derive(Clone, Debug)]
+ #[derive(Clone, Debug, Eq, PartialEq)]
enum #enum_name {
#( #enum_fields ),*
}
@@ -122,7 +152,7 @@ pub fn instructions(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
*offset += 1;
let instruction = match opcode {
- #( #bytecode_parsers ),*
+ #( #bytecode_parsers , )*
_ => panic!("Unknown bytecode encountered"),
};
@@ -133,21 +163,6 @@ pub fn instructions(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
//
}
}
-
- // impl #enum_name {
- // fn from_bytecode(cursor: &mut Cursor<Vec<u8>>) -> Self {
- // let bytecode = cursor.read_u8().unwrap();
- //
- // let instruction = match bytecode {
- // #( #bytecode_parsers ),*
- // _ => panic!("Unknown bytecode encountered"),
- // };
- //
- // instruction
- // }
- // }
- };
-
- // Returning the proc_macro version of TokenStream
- expanded.into()
+ }
+ .into()
}
diff --git a/crates/sloth_bytecode/src/lib.rs b/crates/sloth_bytecode/src/lib.rs
index dbf53ae..f0262f6 100644
--- a/crates/sloth_bytecode/src/lib.rs
+++ b/crates/sloth_bytecode/src/lib.rs
@@ -7,164 +7,62 @@
unused_lifetimes
)]
-use std::io::Cursor;
-
-use byteorder::ReadBytesExt;
-// use sloth_bytecode_macros::instructions;
+use sloth_bytecode_macros::instructions;
pub struct Chunk {
pub code: Vec<u8>,
pub constants: Vec<u64>,
}
-// instructions! {
-// Instructions;
-//
-// 0x00 Constant [u64] "Push a constant value onto the stack",
-//
-// 0x01 Pop [] "Pop a value from the stack",
-// 0x02 Dup [] "Duplicate a value on the stack",
-//
-// 0x10 Add [] "Add the last 2 values on the stack",
-// 0x11 Sub [] "Subtract the last 2 values on the stack",
-// 0x12 Mul [] "Multiply the last 2 values on the stack",
-// 0x13 Div [] "Divide the last 2 values on the stack",
-// 0x14 Mod [] "Modulo the last 2 values on the stack"
-// }
-
-// impl Instructions {
-// fn disassemble(chunk: &Chunk, offset: &mut usize) {
-// //
-// }
-//
-// fn assemble(chunk: &mut Chunk) {
-// //
-// }
-// }
-
-// #[test]
-// fn test() {
-// let mut cursor = Cursor::new(vec![0, 1, 0, 0, 1, 0, 0, 0, 0]);
-// let instruction = Instructions::from_bytecode(&mut cursor);
-// println!("{instruction:?}");
-// assert!(1 == 0);
-// }
-
-// macro_rules! instructions {
-// ( $( $opcode:literal $name:ident [ $( $v_type:ident ),* ] $doc:literal
-// ),* ) => { #[repr(u8)]
-// enum Instruction {
-// $(
-// #[doc = $doc]
-// $name ( $( $v_type ),* ) = $opcode
-// ),*
-// }
-//
-// impl Instruction {
-// fn opcode(&self) -> u8 {
-// match self {
-// $(
-// Self::$name ( $( _ ${ignore(v_type)} ),* ) => $opcode
-// ),*
-// }
-// }
-//
-// fn from_bytecode(bytecode: &[u8]) -> Option<Self> {
-// if bstecode.is_empty() {
-// return None;
-// }
-//
-// let opcode = bytecode[0];
-// let instruction = match opcode {
-// $(
-// $opcode => {
-// // TODO: Get the actual values
-// Some(Self::$name ( $( 0 ${ignore(v_type)} ),* ))
-// }
-// ),*,
-// _ => None,
-// };
-//
-// instruction
-// }
-// }
-// }
-// }
-
-// instructions! {
-// Instructions;
-//
-// 0x00 Constant [u64] "Push a constant value onto the stack",
-//
-// 0x01 Pop [] "Pop a value from the stack",
-// 0x02 Dup [] "Duplicate a value on the stack",
-//
-// 0x10 Add [] "Add the last 2 values on the stack",
-// 0x11 Sub [] "Subtract the last 2 values on the stack",
-// 0x12 Mul [] "Multiply the last 2 values on the stack",
-// 0x13 Div [] "Divide the last 2 values on the stack",
-// 0x14 Mod [] "Modulo the last 2 values on the stack"
-// }
-
pub enum Error {
UnknownOpcode(u8),
InvalidArguments,
Eof,
}
-pub enum Instruction {
- Constant(u64),
+instructions! {
+ Instructions;
- Pop(),
- Dup(),
+ 0x00 Constant [u64] "Push a constant value onto the stack",
- Add(),
- Sub(),
- Mul(),
- Div(),
- Mod(),
-}
-
-// fn parse_bytecode(pos: usize, bc: &[u8]) -> Result<Bytecode, BytecodeError> {
-// let Some(opcode) = bc.get(pos) else {
-// return Err(BytecodeError::Eof);
-// };
-//
-// let instruction = match opcode {
-// 0x00 => {
-// // let arg0: [u8; 8] = bc.get(1..1+size_of::<u64>()).unwrap();
-// let arg0 = u64::from_ne_bytes(arg0);
-// }
-// _ => return Err(BytecodeError::UnknownOpcode(opcode)),
-// }
-//
-// todo!()
-// }
-
-fn parse_bytecode(cursor: &mut Cursor<&[u8]>) -> Result<Instruction, Error> {
- let Ok(opcode) = cursor.read_u8() else {
- return Err(Error::Eof);
- };
+ 0x01 Pop [] "Pop a value from the stack",
+ 0x02 Dup [] "Duplicate a value on the stack",
- let instruction = match opcode {
- 0x00 => {
- let arg0 = cursor
- .read_u64::<byteorder::LittleEndian>()
- .map_err(|_| Error::InvalidArguments)?;
-
- Instruction::Constant(arg0)
- }
- _ => return Err(Error::UnknownOpcode(opcode)),
- };
-
- Ok(instruction)
+ 0x10 Add [] "Add the last 2 values on the stack",
+ 0x11 Sub [] "Subtract the last 2 values on the stack",
+ 0x12 Mul [] "Multiply the last 2 values on the stack",
+ 0x13 Div [] "Divide the last 2 values on the stack",
+ 0x14 Mod [] "Modulo the last 2 values on the stack"
}
-// impl<T: Iterator<Item = u8>> TryFrom<T> for Bytecode {
-// type Error = BytecodeError;
-//
-// fn try_from(value: T) -> Result<Self, Self::Error> {
-// todo!()
-// //
-// }
-// }
+#[cfg(test)]
+mod tests {
+ use crate::{Chunk, Instructions};
+
+ #[test]
+ #[rustfmt::skip]
+ fn decompile_basic_instructions() {
+ let code = vec![
+ // Load constant 0
+ 0x00, 0, 0, 0, 0, 0, 0, 0, 0,
+ // Pop, Dup, Add, Sub, Mul, Div, Mod
+ 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14,
+ ];
+
+ let chunk = Chunk {
+ code,
+ constants: Vec::new(),
+ };
+
+ let mut offset = 0;
+
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Constant(0));
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Pop);
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Dup);
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Add);
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Sub);
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Mul);
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Div);
+ assert_eq!(Instructions::disassemble(&chunk, &mut offset), Instructions::Mod);
+ }
+}