parent
71f19068a7
commit
56c2885565
@ -0,0 +1 @@
|
||||
target
|
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "lox"
|
||||
version = "0.1.0"
|
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "lox"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@ -0,0 +1,2 @@
|
||||
test-watch:
|
||||
while true; do fd .*.rs | entr -d cargo test; done
|
@ -0,0 +1,112 @@
|
||||
use std::alloc::{self, Layout};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
pub enum OpCode {
|
||||
Return,
|
||||
}
|
||||
|
||||
pub struct Chunk {
|
||||
count: usize,
|
||||
capacity: usize,
|
||||
code: NonNull<u8>,
|
||||
_marker: PhantomData<u8>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Chunk {}
|
||||
unsafe impl Sync for Chunk {}
|
||||
|
||||
impl Chunk {
|
||||
pub fn new() -> Self {
|
||||
Chunk {
|
||||
count: 0,
|
||||
capacity: 0,
|
||||
code: NonNull::dangling(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// https://doc.rust-lang.org/nomicon/vec/vec-push-pop.html
|
||||
pub fn write(&mut self, byte: u8) {
|
||||
if self.count == self.capacity {
|
||||
self.grow();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ptr::write(self.code.as_ptr().add(self.count), byte);
|
||||
}
|
||||
|
||||
// Can't fail, we'll OOM first.
|
||||
self.count += 1;
|
||||
}
|
||||
|
||||
// https://doc.rust-lang.org/nomicon/vec/vec-alloc.html
|
||||
fn grow(&mut self) {
|
||||
// Crafting Interpreters: GROW_CAPACITY
|
||||
let new_cap = if self.capacity < 8 {
|
||||
8
|
||||
} else {
|
||||
// This can't overflow since self.capacity <= isize::MAX.
|
||||
self.capacity * 2
|
||||
};
|
||||
|
||||
// `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::<u8>(new_cap).unwrap();
|
||||
|
||||
// Ensure that the new allocation doesn't exceed `isize::MAX` bytes.
|
||||
assert!(
|
||||
new_layout.size() <= isize::MAX as usize,
|
||||
"Allocation too large"
|
||||
);
|
||||
|
||||
// Crafting Interpreters: GROW_ARRAY / reallocate
|
||||
// TODO: Handle shrinking maybe? We may need to
|
||||
// extract these out if it's used elsewhere
|
||||
// in the book
|
||||
let new_ptr = if self.capacity == 0 {
|
||||
unsafe { alloc::alloc(new_layout) }
|
||||
} else {
|
||||
let old_layout = Layout::array::<u8>(self.capacity).unwrap();
|
||||
let old_ptr = self.code.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.code = match NonNull::new(new_ptr as *mut u8) {
|
||||
Some(p) => p,
|
||||
None => alloc::handle_alloc_error(new_layout),
|
||||
};
|
||||
self.capacity = new_cap;
|
||||
}
|
||||
|
||||
// https://doc.rust-lang.org/nomicon/vec/vec-push-pop.html
|
||||
pub fn pop(&mut self) -> Option<u8> {
|
||||
if self.count == 0 {
|
||||
None
|
||||
} else {
|
||||
self.count -= 1;
|
||||
unsafe { Some(ptr::read(self.code.as_ptr().add(self.count))) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://doc.rust-lang.org/nomicon/vec/vec-dealloc.html
|
||||
impl Drop for Chunk {
|
||||
fn drop(&mut self) {
|
||||
if self.capacity != 0 {
|
||||
while self.pop().is_some() {}
|
||||
let layout = Layout::array::<u8>(self.capacity).unwrap();
|
||||
unsafe {
|
||||
alloc::dealloc(self.code.as_ptr() as *mut u8, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Chunk {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
pub mod chunk;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
Loading…
Reference in new issue