diff options
| author | Cody <cody@codyq.dev> | 2023-04-12 07:39:50 -0500 |
|---|---|---|
| committer | Cody <cody@codyq.dev> | 2023-04-12 07:39:50 -0500 |
| commit | be4294a5c60d24643ba712db4b6b4c9b2586179c (patch) | |
| tree | 22b702d7ba8a466fcc934d6abee4b4d19253736d /crates/sloth_bytecode | |
| parent | ee079d193b6644e65543c3fa02dbfcf7b4f2f9c6 (diff) | |
| download | sloth-be4294a5c60d24643ba712db4b6b4c9b2586179c.tar.gz | |
END THIS PAIN AND SUFFERING
Diffstat (limited to 'crates/sloth_bytecode')
| -rw-r--r-- | crates/sloth_bytecode/Cargo.toml | 2 | ||||
| -rw-r--r-- | crates/sloth_bytecode/macros/Cargo.toml | 15 | ||||
| -rw-r--r-- | crates/sloth_bytecode/macros/src/lib.rs | 164 | ||||
| -rw-r--r-- | crates/sloth_bytecode/src/lib.rs | 89 |
4 files changed, 44 insertions, 226 deletions
diff --git a/crates/sloth_bytecode/Cargo.toml b/crates/sloth_bytecode/Cargo.toml index 76448ee..0de211f 100644 --- a/crates/sloth_bytecode/Cargo.toml +++ b/crates/sloth_bytecode/Cargo.toml @@ -6,6 +6,4 @@ version.workspace = true edition.workspace = true [dependencies] -sloth_bytecode_macros = { path = "./macros" } - byteorder = "1.4.3" diff --git a/crates/sloth_bytecode/macros/Cargo.toml b/crates/sloth_bytecode/macros/Cargo.toml deleted file mode 100644 index 649d88a..0000000 --- a/crates/sloth_bytecode/macros/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "sloth_bytecode_macros" - -license.workspace = true -version.workspace = true -edition.workspace = true - -[dependencies] -proc-macro2 = "1.0.54" -quote = "1.0.26" -syn = "2.0.12" - -[lib] -proc-macro = true - diff --git a/crates/sloth_bytecode/macros/src/lib.rs b/crates/sloth_bytecode/macros/src/lib.rs deleted file mode 100644 index 1690c17..0000000 --- a/crates/sloth_bytecode/macros/src/lib.rs +++ /dev/null @@ -1,164 +0,0 @@ -use proc_macro2::{Ident, TokenStream}; -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, - args: Punctuated<Ident, Token![,]>, - description: LitStr, -} - -impl Parse for DslInstructionInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let args_content; - Ok(Self { - opcode: input.parse()?, - name: input.parse()?, - args: { - bracketed!(args_content in input); - args_content.parse_terminated(Ident::parse, Token![,])? - }, - description: input.parse()?, - }) - } -} - -struct DslInstructionsInput { - name: Ident, - instructions: Punctuated<DslInstructionInput, Token![,]>, -} - -impl Parse for DslInstructionsInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - Ok(Self { - name: input.parse()?, - instructions: { - input.parse::<Token![;]>()?; - input.parse_terminated(DslInstructionInput::parse, Token![,])? - }, - }) - } -} - -fn into_enum_field(instruction: &DslInstructionInput) -> TokenStream { - let DslInstructionInput { - opcode, - name, - args, - description, - } = instruction; - - let args = args.iter(); - - if args.len() > 0 { - quote! { - #[doc = #description] - #name ( #( #args ),* ) = #opcode - } - } else { - quote! { - #[doc = #description] - #name = #opcode - } - } -} - -fn into_bytecode_parser(instruction: &DslInstructionInput) -> TokenStream { - let DslInstructionInput { - opcode, - name, - args, - description: _, - } = instruction; - - if args.is_empty() { - return quote! { - #opcode => Self :: #name - }; - } - - 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) * 8; - chunks.push(quote! { - ((chunk[*offset + #byte] as #arg) << #shift_amount) - }); - } - - arg_params.push(quote! { - let value = #( #chunks )+* ; - *offset += #bytes ; - value - }); - } - - quote! { - #opcode => { - Self :: #name ( - #( { #arg_params } ),* - ) - } - } -} - -#[proc_macro] -pub fn instructions(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as DslInstructionsInput); - - // Getting values to construct the enum - let enum_name = input.name; - let enum_fields = input - .instructions - .iter() - .map(into_enum_field) - .collect::<Vec<_>>(); - - // Getting the values to parse bytecode - let bytecode_parsers = input - .instructions - .iter() - .map(into_bytecode_parser) - .collect::<Vec<_>>(); - - // Building out the expanded code - quote! { - #[repr(u8)] - #[derive(Clone, Debug, Eq, PartialEq)] - pub enum #enum_name { - #( #enum_fields ),* - } - - impl #enum_name { - pub fn disassemble(chunk: &[u8], offset: &mut usize) -> #enum_name { - let opcode = chunk[*offset]; - *offset += 1; - - let instruction = match opcode { - #( #bytecode_parsers , )* - _ => panic!("Unknown bytecode encountered"), - }; - - instruction - } - } - } - .into() -} diff --git a/crates/sloth_bytecode/src/lib.rs b/crates/sloth_bytecode/src/lib.rs index bf20068..df91c41 100644 --- a/crates/sloth_bytecode/src/lib.rs +++ b/crates/sloth_bytecode/src/lib.rs @@ -7,65 +7,64 @@ unused_lifetimes )] -use sloth_bytecode_macros::instructions; - pub enum Error { UnknownOpcode(u8), InvalidArguments, Eof, } -instructions! { - Instruction; - - 0x00 Constant [u32] "Push a constant value onto the stack", - 0x01 Load [u32] "Load a value from a variable", - 0x02 Push [u32] "Push a value to a variable", +macro_rules! opcodes { + ( $( $code:literal $name:ident $docs:literal ),* ) => { + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum Opcode { + $( + #[doc = $docs] + $name = $code + ),* + } - 0x10 Dup [] "Duplicate a value on the stack", - 0x11 Del [] "Delete a value from the stack", + impl Opcode { + pub fn into_u8(self) -> u8 { + self as u8 + } - 0x20 Add [] "Add the last 2 values on the stack", - 0x21 Sub [] "Subtract the last 2 values on the stack", - 0x22 Mul [] "Multiply the last 2 values on the stack", - 0x23 Div [] "Divide the last 2 values on the stack", - 0x24 Mod [] "Modulo the last 2 values on the stack", + pub fn from_u8(value: u8) -> Opcode { + match value { + $( $code => Self:: $name , )* + _ => panic!("Invalid opcode"), + } + } + } + }; +} - 0x30 Eq [] "Check if the last 2 values on the stack are equal", - 0x31 Ne [] "Check if the last 2 values on the stack are not equal", +opcodes! { + 0x00 Constant "Push a constant value onto the stack", + 0x01 Load "Load a value from a variable", + 0x02 Push "Push a value to a variable", - 0x40 Jmp [u32] "Jump to a specific point in the program", - 0x41 JmpIf [u32] "Jump to a specific point in the program if true is on the stack", + 0x10 Dup "Duplicate a value on the stack", + 0x11 Del "Delete a value from the stack", - 0xE0 Hlt [] "Halt the program", - 0xE1 Exit [] "Exit the program", + 0x20 Add "Add the last 2 values on the stack", + 0x21 Sub "Subtract the last 2 values on the stack", + 0x22 Mul "Multiply the last 2 values on the stack", + 0x23 Div "Divide the last 2 values on the stack", + 0x24 Mod "Modulo the last 2 values on the stack", - 0xF0 VMReturn [] "[DEBUG] Pop value from stack and return it from the program", -} + 0x30 Eq "Check if the last 2 values on the stack are equal", + 0x31 Ne "Check if the last 2 values on the stack are not equal", -#[cfg(test)] -mod tests { - use crate::Instruction; + 0x40 Jmp "Jump to a specific point in the program", + 0x41 JmpIf "Jump to a specific point in the program if true is on the stack", - #[test] - #[rustfmt::skip] - fn decompile_basic_instructions() { - let code = [ - // Load constant 0 - 0x00, 0, 0, 0, 0, - // Pop, Del, Add, Sub, Mul, Div, Mod - 0x10, 0x11, 0x20, 0x21, 0x22, 0x23, 0x24, - ]; + 0x50 Call "Call function on stack", + 0x51 Return "Return from function on stack", - let mut offset = 0; + 0xE0 Hlt "Halt the program", + 0xE1 Exit "Exit the program", - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Constant(0)); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Dup); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Del); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Add); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Sub); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Mul); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Div); - assert_eq!(Instruction::disassemble(&code, &mut offset), Instruction::Mod); - } + 0xF0 VMReturn "[DEBUG] Pop value from stack and return it fromthe program", + 0xF1 VMPrint "[DEBUG] Print value to console" } |
