aboutsummaryrefslogtreecommitdiff
path: root/crates/sloth_bytecode
diff options
context:
space:
mode:
authorCody <cody@codyq.dev>2023-04-12 07:39:50 -0500
committerCody <cody@codyq.dev>2023-04-12 07:39:50 -0500
commitbe4294a5c60d24643ba712db4b6b4c9b2586179c (patch)
tree22b702d7ba8a466fcc934d6abee4b4d19253736d /crates/sloth_bytecode
parentee079d193b6644e65543c3fa02dbfcf7b4f2f9c6 (diff)
downloadsloth-be4294a5c60d24643ba712db4b6b4c9b2586179c.tar.gz
END THIS PAIN AND SUFFERING
Diffstat (limited to 'crates/sloth_bytecode')
-rw-r--r--crates/sloth_bytecode/Cargo.toml2
-rw-r--r--crates/sloth_bytecode/macros/Cargo.toml15
-rw-r--r--crates/sloth_bytecode/macros/src/lib.rs164
-rw-r--r--crates/sloth_bytecode/src/lib.rs89
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"
}