aboutsummaryrefslogtreecommitdiff
path: root/crates/sloth_bytecode
diff options
context:
space:
mode:
Diffstat (limited to 'crates/sloth_bytecode')
-rw-r--r--crates/sloth_bytecode/Cargo.toml5
-rw-r--r--crates/sloth_bytecode/macros/Cargo.toml13
-rw-r--r--crates/sloth_bytecode/macros/src/lib.rs153
-rw-r--r--crates/sloth_bytecode/src/lib.rs203
4 files changed, 326 insertions, 48 deletions
diff --git a/crates/sloth_bytecode/Cargo.toml b/crates/sloth_bytecode/Cargo.toml
index a302c81..981b6ee 100644
--- a/crates/sloth_bytecode/Cargo.toml
+++ b/crates/sloth_bytecode/Cargo.toml
@@ -2,3 +2,8 @@
name = "sloth_bytecode"
version = "0.1.0"
edition = "2021"
+
+[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
new file mode 100644
index 0000000..c75bc58
--- /dev/null
+++ b/crates/sloth_bytecode/macros/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "sloth_bytecode_macros"
+version = "0.1.0"
+edition = "2021"
+
+[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
new file mode 100644
index 0000000..e07a027
--- /dev/null
+++ b/crates/sloth_bytecode/macros/src/lib.rs
@@ -0,0 +1,153 @@
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
+use syn::parse::Parse;
+use syn::punctuated::Punctuated;
+use syn::{bracketed, parse_macro_input, LitInt, LitStr, Token};
+
+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();
+
+ quote! {
+ #[doc = #description]
+ #name ( #( #args ),* ) = #opcode
+ }
+}
+
+fn into_bytecode_parser(instruction: &DslInstructionInput) -> TokenStream {
+ let DslInstructionInput {
+ opcode,
+ name,
+ args,
+ description: _,
+ } = instruction;
+
+ let args = args.iter().map(|arg| {
+ let read_ident = format_ident!("read_{}", arg);
+
+ let _chunk_codes = arg;
+
+ quote! {
+ {
+ let a: #arg = (chunk.code[*offset] << 56) + (chunk)
+ cursor . #read_ident ::<byteorder::LittleEndian>().unwrap()
+ }
+ }
+ });
+
+ quote! {
+ #opcode => {
+ Self:: #name (
+ #( #args ),*
+ )
+ }
+ }
+}
+
+#[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
+ let expanded = quote! {
+ #[repr(u8)]
+ #[derive(Clone, Debug)]
+ enum #enum_name {
+ #( #enum_fields ),*
+ }
+
+ impl #enum_name {
+ fn disassemble(chunk: &Chunk, offset: &mut usize) -> #enum_name {
+ let opcode = chunk.code[*offset];
+ *offset += 1;
+
+ let instruction = match opcode {
+ #( #bytecode_parsers ),*
+ _ => panic!("Unknown bytecode encountered"),
+ };
+
+ instruction
+ }
+
+ fn assemble(chunk: &mut Chunk) {
+ //
+ }
+ }
+
+ // 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()
+}
diff --git a/crates/sloth_bytecode/src/lib.rs b/crates/sloth_bytecode/src/lib.rs
index f814f86..dbf53ae 100644
--- a/crates/sloth_bytecode/src/lib.rs
+++ b/crates/sloth_bytecode/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(macro_metavar_expr)]
#![allow(dead_code)]
#![warn(
clippy::wildcard_imports,
@@ -8,56 +7,164 @@
unused_lifetimes
)]
-macro_rules! instructions {
- ( $( $opcode:literal $name:ident [ $( $v_type:ident ),* ] $doc:literal ),* ) => {
- #[repr(u8)]
- enum Instruction {
- $(
- #[doc = $doc]
- $name ( $( $v_type ),* ) = $opcode
- ),*
- }
+use std::io::Cursor;
- impl Instruction {
- fn opcode(&self) -> u8 {
- match self {
- $(
- Self::$name ( $( _ ${ignore(v_type)} ),* ) => $opcode
- ),*
- }
- }
-
- fn from_bytecode(bytecode: &[u8]) -> Option<Self> {
- if bytecode.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
- }
- }
- }
+use byteorder::ReadBytesExt;
+// 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,
}
-instructions! {
- 0x00 Constant [u64] "Push a constant value onto the stack",
+pub enum Instruction {
+ Constant(u64),
- 0x01 Pop [] "Pop a value from the stack",
- 0x02 Dup [] "Duplicate a value on the stack",
+ Pop(),
+ Dup(),
- 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"
+ 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);
+ };
+
+ 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)
+}
+
+// impl<T: Iterator<Item = u8>> TryFrom<T> for Bytecode {
+// type Error = BytecodeError;
+//
+// fn try_from(value: T) -> Result<Self, Self::Error> {
+// todo!()
+// //
+// }
+// }