14
change rlpspzsyywoxyprtlwruonvrszzwwoyq
commit f9ebdc40c793a5271496c72df18f54422f1e5047
author Alpha Chen <alpha@kejadlen.dev>
date
parent oxmqrwvu
diff --git a/rust/.rustfmt.toml b/rust/.rustfmt.toml
new file mode 100644
index 0000000..c2c8317
--- /dev/null
+++ b/rust/.rustfmt.toml
@@ -0,0 +1,6 @@
+condense_wildcard_suffixes = true
+format_strings = true
+reorder_impl_items = true
+group_imports = "StdExternalCrate"
+use_field_init_shorthand = true
+wrap_comments = true
diff --git a/rust/src/chunk.rs b/rust/src/chunk.rs
index 688764f..c57fa76 100644
--- a/rust/src/chunk.rs
+++ b/rust/src/chunk.rs
@@ -1,148 +1,62 @@
-use std::mem;
+use std::fmt;
 
-use vec::Vec;
+use crate::value::Value;
 
-use crate::vec;
-
-#[repr(u8)]
+#[derive(Debug)]
 pub enum OpCode {
-    Constant,
-    LongConstant,
+    Constant(usize),
     Return,
 }
 
-type Value = f32;
+#[derive(Debug)]
+pub struct Instruction {
+    op_code: OpCode,
+    line: usize,
+}
 
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct Chunk {
-    pub code: Vec<u8>,
-    constants: Vec<Value>,
-    lines: Lines,
+    pub code: Vec<Instruction>,
+    pub constants: Vec<Value>,
 }
 
 impl Chunk {
-    pub fn write(&mut self, byte: u8, line: usize) {
-        self.code.push(byte);
-        self.lines.add(line);
+    pub fn push(&mut self, op_code: OpCode, line: usize) {
+        self.code.push(Instruction { op_code, line });
     }
 
-    pub fn write_constant(&mut self, value: Value, line: usize) {
+    pub fn push_constant(&mut self, value: Value, line: usize) {
         self.constants.push(value);
-        let index = self.constants.len() - 1;
-
-        if let Ok(index) = index.try_into() {
-            self.write(OpCode::Constant as u8, line);
-            self.write(index, line);
-        } else {
-            self.write(OpCode::LongConstant as u8, line);
-            for byte in index.to_ne_bytes() {
-                self.write(byte, line);
-            }
-        }
+        self.push(OpCode::Constant(self.constants.len() - 1), line)
     }
 
     pub fn disassemble(&self, name: &str) {
-        println!("== {} ==", name);
-
-        let mut offset = 0;
-        while offset < self.code.len() {
-            offset = self.disassemble_instruction(offset);
-        }
-    }
-
-    fn disassemble_instruction(&self, offset: usize) -> usize {
-        print!("{:04} ", offset);
-
-        let (line, is_first) = self.lines.get(offset);
-        if is_first {
-            print!("{:>4} ", line);
-        } else {
-            print!("   | ");
-        }
-
-        match self.code[offset] {
-            0 => self.constant_instruction("OP_CONSTANT", offset),
-            1 => self.constant_long_instruction("OP_CONSTANT_LONG", offset),
-            2 => self.simple_instruction("OP_RETURN", offset),
-            _ => unreachable!(),
-        }
-    }
-
-    fn simple_instruction(&self, name: &str, offset: usize) -> usize {
-        println!("{}", name);
-        offset + 1
-    }
-
-    fn constant_instruction(&self, name: &str, offset: usize) -> usize {
-        let constant_index = self.code[offset + 1];
-        let value = self.constants[constant_index as usize];
-        println!("{:<16} {:>4} '{}'", name, constant_index, value);
-        offset + 2
+        println!("== {} ==\n{}", name, self);
     }
-
-    fn constant_long_instruction(&self, name: &str, offset: usize) -> usize {
-        let index_len = mem::size_of::<usize>();
-        let index_bytes = &self.code[offset + 1..offset + 1 + index_len];
-
-        let (int_bytes, _) = index_bytes.split_at(std::mem::size_of::<usize>());
-        let constant_index = usize::from_ne_bytes(int_bytes.try_into().unwrap());
-
-        let value = self.constants[constant_index as usize];
-        println!("{:<16} {:>4} '{}'", name, constant_index, value);
-        offset + 1 + index_len
-    }
-}
-
-#[test]
-fn test_constant_long() {
-    let mut chunk = Chunk::default();
-
-    for i in 0..=u8::MAX {
-        chunk.write_constant(i.into(), 123);
-    }
-
-    chunk.write_constant(0.0, 123);
-
-    // TODO Make the disassembler testable
 }
 
-// Lines are stored using run-length encoding, where the first element is the line and the second
-// element the number of instructions that are associated with that line
-#[derive(Debug, Default)]
-struct Lines(std::vec::Vec<(usize, usize)>);
-
-impl Lines {
-    fn add(&mut self, line: usize) {
-        if let Some(last) = self.0.last_mut() {
-            last.1 += 1;
-        } else {
-            self.0.push((line, 1));
-        }
-    }
+impl fmt::Display for Chunk {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut last_line: Option<usize> = None;
 
-    fn get(&self, offset: usize) -> (usize, bool) {
-        let mut offset = offset;
-        for (line, run) in self.0.iter() {
-            if offset == 0 {
-                return (*line, true);
+        for (i, instruction) in self.code.iter().enumerate() {
+            write!(f, "{:04} ", i)?;
+            if last_line == Some(instruction.line) {
+                write!(f, "   | ")?;
+            } else {
+                write!(f, "{:>4} ", instruction.line)?;
             }
-
-            if offset < *run {
-                return (*line, false);
+            last_line = Some(instruction.line);
+
+            match instruction.op_code {
+                OpCode::Constant(constant) => {
+                    let value = self.constants[constant];
+                    writeln!(f, "{:<16} {:4} '{}'", "OP_CONSTANT", constant, value)?;
+                }
+                OpCode::Return => writeln!(f, "OP_RETURN")?,
             }
-
-            offset -= run;
         }
 
-        unreachable!()
+        Ok(())
     }
 }
-
-#[test]
-fn test_get_line() {
-    let lines = Lines(vec![(1_usize, 2_usize), (2_usize, 2_usize)]);
-    assert_eq!(lines.get(0), (1, true));
-    assert_eq!(lines.get(1), (1, false));
-    assert_eq!(lines.get(2), (2, true));
-    assert_eq!(lines.get(3), (2, false));
-}
diff --git a/rust/src/main.rs b/rust/src/main.rs
index 2ec0252..71cc773 100644
--- a/rust/src/main.rs
+++ b/rust/src/main.rs
@@ -1,25 +1,13 @@
 use chunk::{Chunk, OpCode};
-use vm::VM;
 
-pub mod chunk;
-pub mod vec;
-pub mod vm;
+mod chunk;
+mod value;
 
 fn main() {
     let mut chunk = Chunk::default();
 
-    chunk.write_constant(1.2, 123);
+    chunk.push_constant(1.2, 123);
+    chunk.push(OpCode::Return, 123);
 
-    chunk.write(OpCode::Return as u8, 123);
-
-    // for i in 0..=u8::MAX {
-    //     chunk.write_constant(i.into(), 123);
-    // }
-
-    // chunk.write_constant(0.0, 123);
-
-    // chunk.disassemble("test chunk");
-
-    let vm = VM::new(chunk);
-    vm.interpret();
+    chunk.disassemble("test chunk");
 }
diff --git a/rust/src/value.rs b/rust/src/value.rs
new file mode 100644
index 0000000..343d142
--- /dev/null
+++ b/rust/src/value.rs
@@ -0,0 +1 @@
+pub type Value = f64;
diff --git a/rust/src/vec.rs b/rust/src/vec.rs
deleted file mode 100644
index 195e207..0000000
--- a/rust/src/vec.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-// https://doc.rust-lang.org/nomicon/vec/vec.html
-
-use std::alloc::{self, Layout};
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::{Deref, DerefMut};
-use std::ptr::{self, NonNull};
-
-pub struct Vec<T> {
-    ptr: NonNull<T>,
-    cap: usize,
-    len: usize,
-    _marker: PhantomData<T>,
-}
-
-unsafe impl<T: Send> Send for Vec<T> {}
-unsafe impl<T: Sync> Sync for Vec<T> {}
-
-impl<T> Vec<T> {
-    pub fn new() -> Self {
-        assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
-        Vec {
-            ptr: NonNull::dangling(),
-            len: 0,
-            cap: 0,
-            _marker: PhantomData,
-        }
-    }
-
-    pub fn push(&mut self, elem: T) {
-        if self.len == self.cap {
-            self.grow();
-        }
-
-        unsafe {
-            ptr::write(self.ptr.as_ptr().add(self.len), elem);
-        }
-
-        // Can't fail, we'll OOM first.
-        self.len += 1;
-    }
-
-    pub fn pop(&mut self) -> Option<T> {
-        if self.len == 0 {
-            None
-        } else {
-            self.len -= 1;
-            unsafe { Some(ptr::read(self.ptr.as_ptr().add(self.len))) }
-        }
-    }
-
-    fn grow(&mut self) {
-        let (new_cap, new_layout) = if self.cap == 0 {
-            (1, Layout::array::<T>(1).unwrap())
-        } else {
-            // This can't overflow since self.cap <= isize::MAX.
-            let new_cap = 2 * self.cap;
-
-            // `Layout::array` checks that the number of bytes is <= usize::MAX,
-            // but this is redundant since old_layout.size() <= isize::MAX,
-            // so the `unwrap` should never fail.
-            let new_layout = Layout::array::<T>(new_cap).unwrap();
-            (new_cap, new_layout)
-        };
-
-        // Ensure that the new allocation doesn't exceed `isize::MAX` bytes.
-        assert!(
-            new_layout.size() <= isize::MAX as usize,
-            "Allocation too large"
-        );
-
-        let new_ptr = if self.cap == 0 {
-            unsafe { alloc::alloc(new_layout) }
-        } else {
-            let old_layout = Layout::array::<T>(self.cap).unwrap();
-            let old_ptr = self.ptr.as_ptr() as *mut u8;
-            unsafe { alloc::realloc(old_ptr, old_layout, new_layout.size()) }
-        };
-
-        // If allocation fails, `new_ptr` will be null, in which case we abort.
-        self.ptr = match NonNull::new(new_ptr as *mut T) {
-            Some(p) => p,
-            None => alloc::handle_alloc_error(new_layout),
-        };
-        self.cap = new_cap;
-    }
-}
-
-impl<T> Drop for Vec<T> {
-    fn drop(&mut self) {
-        if self.cap != 0 {
-            while self.pop().is_some() {}
-            let layout = Layout::array::<T>(self.cap).unwrap();
-            unsafe {
-                alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
-            }
-        }
-    }
-}
-
-impl<T> Deref for Vec<T> {
-    type Target = [T];
-    fn deref(&self) -> &[T] {
-        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
-    }
-}
-
-impl<T> DerefMut for Vec<T> {
-    fn deref_mut(&mut self) -> &mut [T] {
-        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
-    }
-}
-
-impl<T> Default for Vec<T> {
-    fn default() -> Self {
-        Self::new()
-    }
-}
diff --git a/rust/src/vm.rs b/rust/src/vm.rs
deleted file mode 100644
index 8b61340..0000000
--- a/rust/src/vm.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use std::ptr;
-
-use anyhow::Result;
-use thiserror::Error;
-
-use crate::chunk::Chunk;
-
-pub struct VM {
-    chunk: Chunk,
-    ip: *const u8,
-}
-
-#[derive(Error, Debug)]
-pub enum DataStoreError {
-    #[error("")]
-    CompileError,
-    #[error("")]
-    RuntimeError,
-}
-
-impl VM {
-    pub fn new(chunk: Chunk) -> Self {
-        VM { chunk, ip: &chunk.code.ptr }
-    }
-
-    pub fn interpret(&self) -> Result<()> {
-        self.run()
-    }
-
-    fn run(&self) -> Result<()> {
-        todo!()
-    }
-}