add return and const instructions.

This commit is contained in:
publicmatt 2024-05-02 11:30:50 -07:00
commit 5cee345e8b
7 changed files with 158 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

7
Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "mox"
version = "0.1.0"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "mox"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

44
src/debug.rs Normal file
View File

@ -0,0 +1,44 @@
use mox::value::Value;
use mox::{Chunk, ConversionError, OptCode};
pub fn disassemble_chunk(chunk: &Chunk, name: &str) {
// println!("{:?}", chunk);
println!("== {} ==", name);
let mut offset = 0;
while offset < chunk.code.len() {
offset = disassemble_instruction(&chunk, offset);
}
}
fn disassemble_instruction(chunk: &Chunk, offset: usize) -> usize {
print!("{:04} ", offset);
let instruction: Result<OptCode, ConversionError> = chunk.code[offset].try_into();
match instruction {
Ok(code) => match code {
OptCode::OpConstant => {
return constant_instruction("OpConstant", chunk, offset);
}
OptCode::OpReturn => {
return simple_instruction("OpReturn", offset);
}
},
Err(e) => {
println!("Unknown optcode {:?}", e);
return offset + 1;
}
}
}
fn simple_instruction(name: &str, offset: usize) -> usize {
println!("{}", name);
return offset + 1;
}
fn constant_instruction(name: &str, chunk: &Chunk, offset: usize) -> usize {
let constant: u8 = chunk.code[offset + 1];
print!("{:<16} {:>4} ", name, constant);
print_value(chunk.constants[constant as usize]);
println!();
return offset + 2;
}
fn print_value(value: Value) {
print!("{:}", value);
}

82
src/lib.rs Normal file
View File

@ -0,0 +1,82 @@
pub mod value;
use value::Value;
#[derive(Debug, PartialEq, Eq)]
pub enum OptCode {
OpReturn,
OpConstant,
}
#[derive(Debug)]
pub struct Chunk {
pub code: Vec<u8>,
pub constants: Vec<Value>,
}
impl From<OptCode> for u8 {
fn from(code: OptCode) -> Self {
match code {
OptCode::OpReturn => 0,
OptCode::OpConstant => 1,
}
}
}
#[derive(Debug)]
pub struct ConversionError;
impl TryFrom<u8> for OptCode {
type Error = ConversionError;
fn try_from(code: u8) -> Result<Self, Self::Error> {
match code {
0 => Ok(OptCode::OpReturn),
1 => Ok(OptCode::OpConstant),
_ => Err(ConversionError),
}
}
}
impl Chunk {
pub fn new() -> Self {
Self {
code: vec![],
constants: vec![],
}
}
pub fn write(&mut self, byte: u8) {
self.code.push(byte);
}
pub fn write_value(&mut self, add: Value) -> u8 {
self.constants.push(add);
return (self.constants.len() - 1).try_into().unwrap();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u8_to_optcode() {
let pred: OptCode = 0.try_into().unwrap();
assert_eq!(pred, OptCode::OpReturn);
let pred: OptCode = 1.try_into().unwrap();
assert_eq!(pred, OptCode::OpConstant);
}
#[test]
fn basic_write() {
let mut chunk = Chunk::new();
let constant_idx: u8 = chunk.write_value(1.2);
assert_eq!(constant_idx, 0);
chunk.write(OptCode::OpConstant.into());
chunk.write(constant_idx);
let pred: OptCode = chunk.code[0].try_into().unwrap();
assert_eq!(pred, OptCode::OpConstant);
}
#[test]
fn try_into_constant() {
let mut chunk = Chunk::new();
let constant_idx: u8 = chunk.write_value(1.2);
chunk.write(OptCode::OpConstant.into());
chunk.write(constant_idx);
}
}

15
src/main.rs Normal file
View File

@ -0,0 +1,15 @@
use mox::Chunk;
use mox::OptCode;
mod debug;
use debug::disassemble_chunk;
fn main() {
let mut chunk = Chunk::new();
let constant_idx: u8 = chunk.write_value(1.2);
chunk.write(OptCode::OpConstant.into());
chunk.write(constant_idx);
chunk.write(OptCode::OpReturn.into());
disassemble_chunk(&chunk, "test chunk");
}

1
src/value.rs Normal file
View File

@ -0,0 +1 @@
pub type Value = f64;