diff --git a/rust/src/error.rs b/rust/src/error.rs new file mode 100644 index 0000000..4cf7d4c --- /dev/null +++ b/rust/src/error.rs @@ -0,0 +1,34 @@ +use std::io; +use std::process::{ExitCode, Termination}; + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("compile error")] + Compile, + #[error("runtime error")] + Runtime, + #[error("could not open file {path}")] + ReadFile { + path: String, + #[source] + source: io::Error, + }, + #[error("Usage: clox [path]")] + Usage, +} + +// Doesn't actually work with eyre... yet? But I'm +// willing to give up "nice" exit status codes for +// eyre's error handling. +impl Termination for Error { + fn report(self) -> ExitCode { + ExitCode::from(match self { + Error::Compile => 65, + Error::Runtime => 70, + Error::ReadFile { path, source } => 74, + Error::Usage => 64, + }) + } +} diff --git a/rust/src/main.rs b/rust/src/main.rs index a34ba0f..dd2616b 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,13 +1,17 @@ -use std::env; +use std::io::{self, Write}; -use chunk::{Chunk, OpCode}; -use vm::VM; +use std::{env, fs}; + +// use chunk::{Chunk, OpCode}; +// use vm::VM; use color_eyre::eyre::{Result, WrapErr}; +use error::Error; use tracing::Level; use tracing_subscriber::FmtSubscriber; mod chunk; +mod error; mod value; mod vm; @@ -16,29 +20,45 @@ fn main() -> Result<()> { Ok(_) => Level::DEBUG, Err(_) => Level::ERROR, }; - let subscriber = FmtSubscriber::builder() - .with_max_level(level) - .finish(); + let subscriber = FmtSubscriber::builder().with_max_level(level).finish(); tracing::subscriber::set_global_default(subscriber) .wrap_err("setting default subscriber failed")?; - let mut chunk = Chunk::default(); + match &env::args().skip(1).collect::>()[..] { + [] => repl()?, + [file] => run(file)?, + _ => return Err(Error::Usage.into()), + } - chunk.push_constant(1.2, 123); - chunk.push_constant(3.4, 123); - chunk.push(OpCode::Add, 123); + Ok(()) +} - chunk.push_constant(5.6, 123); - chunk.push(OpCode::Divide, 123); +fn repl() -> Result<()> { + let stdin = io::stdin(); // We get `Stdin` here. + let mut buffer = String::new(); - chunk.push(OpCode::Negate, 123); + loop { + print!("> "); + io::stdout().flush()?; - chunk.push(OpCode::Return, 123); + stdin.read_line(&mut buffer)?; + if buffer == "\n" { + return Ok(()); + } - chunk.disassemble("test chunk"); + interpret(&buffer)?; + } +} - let mut vm = VM::new(chunk); - vm.interpret()?; +fn interpret(buffer: &str) -> Result<()> { + todo!() +} +fn run(file: &str) -> Result<()> { + let contents = fs::read_to_string(file).map_err(|e| Error::ReadFile { + path: file.to_string(), + source: e, + })?; + interpret(&contents)?; Ok(()) } diff --git a/rust/src/vm.rs b/rust/src/vm.rs index e13ef97..e610663 100644 --- a/rust/src/vm.rs +++ b/rust/src/vm.rs @@ -1,7 +1,6 @@ use std::ops::{Add, Div, Mul, Sub}; use color_eyre::eyre::Result; -use thiserror::Error; use crate::{ chunk::{Chunk, DisassembledInstruction, OpCode}, @@ -9,14 +8,6 @@ use crate::{ }; use tracing::debug; -#[derive(Error, Debug)] -pub enum InterpretError { - #[error("compile error")] - Compile, - #[error("runtime error")] - Runtime, -} - pub struct VM { chunk: Chunk, ip: usize,