From fb88595b6ccd49be21b67b84619d61c8a3400c7f Mon Sep 17 00:00:00 2001 From: Moritz Gmeiner Date: Mon, 2 Sep 2024 03:10:35 +0200 Subject: [PATCH] improved REPL a bit now uses rustyline for input --- Cargo.lock | 281 +++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 2 + interpreter/src/lib.rs | 2 +- interpreter/src/run.rs | 57 --------- src/main.rs | 12 +- src/repl.rs | 199 +++++++++++++++++++++++++++++ vm/Cargo.toml | 14 +- vm/src/compiler.rs | 26 +++- vm/src/debug.rs | 4 +- vm/src/error.rs | 8 +- vm/src/run.rs | 9 +- vm/src/value.rs | 9 +- vm/src/vm.rs | 37 +++++- 13 files changed, 560 insertions(+), 100 deletions(-) create mode 100644 src/repl.rs diff --git a/Cargo.lock b/Cargo.lock index 37cc2e2..1ab8d78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,7 +38,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -48,9 +48,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "clap" version = "4.5.16" @@ -91,18 +109,70 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "clipboard-win" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +dependencies = [ + "error-code", +] + [[package]] name = "colorchoice" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "error-code" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" + +[[package]] +name = "fd-lock" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "glob" version = "0.3.1" @@ -115,6 +185,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -130,6 +209,57 @@ dependencies = [ "either", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "phf" version = "0.11.2" @@ -190,6 +320,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.8.5" @@ -210,8 +350,10 @@ name = "rlox2" version = "0.1.0" dependencies = [ "clap", + "colored", "rlox2-frontend", "rlox2-interpreter", + "rustyline", ] [[package]] @@ -240,12 +382,53 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustix" +version = "0.38.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustyline" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" +dependencies = [ + "bitflags", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "windows-sys 0.52.0", +] + [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "strsim" version = "0.11.1" @@ -289,19 +472,55 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -310,28 +529,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -344,24 +581,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index 66c265f..4a6fe81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,5 @@ path = "interpreter" [dependencies] clap = { version = "4", features = ["derive"] } +colored = "2.1.0" +rustyline = "14.0.0" diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index 319fd66..ec706b2 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -15,6 +15,6 @@ pub use error::{LoxError, RuntimeError}; pub use function::LoxFunction; pub use object::LoxReference; pub use resolver::{resolve, ResolverError}; -pub use run::{run, run_repl}; +pub use run::run; pub use runtime::Runtime; pub use value::Value; diff --git a/interpreter/src/run.rs b/interpreter/src/run.rs index 1623223..f7d35f5 100644 --- a/interpreter/src/run.rs +++ b/interpreter/src/run.rs @@ -1,5 +1,3 @@ -use std::io::Write; - use rlox2_frontend::lexer::{scan_tokens, Token}; use rlox2_frontend::parser::parse_tokens; @@ -9,61 +7,6 @@ use crate::resolver::resolve; use super::Runtime; -pub fn run_repl(runtime: &mut Runtime) { - let stdin = std::io::stdin(); - - loop { - let mut input_buf = String::new(); - - print!("> "); - std::io::stdout().flush().unwrap(); - - 'inner: loop { - stdin.read_line(&mut input_buf).unwrap_or_else(|err| { - eprintln!("Could not read from stdin: {err}"); - std::process::exit(66); - }); - - let num_open_braces = - (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); - let num_open_parens = - (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); - let num_open_brackets = - (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); - - // all braces/parens/brackets closed => break - if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 { - break 'inner; - } - - // any braces/parens/brackets more closing than opening => break (will be parse error) - if num_open_braces < 0 || num_open_parens < 0 || num_open_brackets < 0 { - break 'inner; - } - - print!("< "); - - // let indentation = " ".repeat((num_open_braces + num_open_brackets + num_open_parens) as usize); - - // print!("{indentation}"); - - std::io::stdout().flush().unwrap(); - } - - if input_buf.is_empty() || input_buf == "exit\n" || input_buf == "quit\n" { - std::process::exit(0); - } - - let input_buf = input_buf.trim(); - - match run(input_buf, runtime) { - Ok(()) => {} - Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code), - Err(err) => eprintln!("{err}"), - } - } -} - pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> { let tokens: Vec = scan_tokens(source)?; diff --git a/src/main.rs b/src/main.rs index f81f1e0..41825ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,9 @@ use clap::{ArgAction, Parser}; +mod repl; + +use repl::{run_repl, LoxResult}; + #[derive(Parser, Debug)] struct CliArgs { #[arg()] @@ -82,6 +86,12 @@ fn main() { } } - rlox2_interpreter::run_repl(&mut runtime); + run_repl( + move |source| match rlox2_interpreter::run(source, &mut runtime) { + Ok(()) => LoxResult::Ok(()), + Err(rlox2_interpreter::LoxError::Exit { exit_code }) => LoxResult::Exit(exit_code), + Err(e) => LoxResult::Err(e), + }, + ); } } diff --git a/src/repl.rs b/src/repl.rs new file mode 100644 index 0000000..f199364 --- /dev/null +++ b/src/repl.rs @@ -0,0 +1,199 @@ +use std::error::Error; + +use colored::Colorize; +use rustyline::completion::Completer; +use rustyline::error::ReadlineError; +use rustyline::highlight::Highlighter; +use rustyline::hint::Hinter; +use rustyline::history::FileHistory; +use rustyline::validate::{ValidationContext, ValidationResult, Validator}; +use rustyline::{Editor, Helper}; + +pub enum LoxResult { + Ok(()), + Err(E), + Exit(i32), +} + +#[derive(Default)] +struct ReplHelper {} + +impl Validator for ReplHelper { + fn validate(&self, ctx: &mut ValidationContext) -> rustyline::Result { + let input = ctx.input(); + + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + enum Brackets { + LeftParen, + LeftBrace, + } + + use Brackets::*; + + let mut brackets = Vec::new(); + + let chars: Vec = input.chars().collect(); + + let mut pos = 0; + + while pos < chars.len() { + match chars[pos] { + '(' => brackets.push(LeftParen), + ')' => { + if brackets.is_empty() || brackets.last().unwrap() != &LeftParen { + // no matching opening paren on the stack -> parser error + return Ok(ValidationResult::Valid(None)); + } + brackets.pop(); + } + '{' => brackets.push(LeftBrace), + '}' => { + if brackets.is_empty() || brackets.last().unwrap() != &LeftBrace { + // no matching opening brace on the stack -> parser error + return Ok(ValidationResult::Valid(None)); + } + brackets.pop(); + } + '/' => { + // line comment + match chars[pos + 1] { + '/' => { + pos += 2; + while pos < chars.len() && chars[pos] != '\n' { + pos += 1; + } + } + '*' => { + pos += 2; + + let mut comment_depth: u32 = 1; + + let match_two = |pos, c1, c2| chars[pos] == c1 && chars[pos + 1] == c2; + + while pos < chars.len() - 1 { + if match_two(pos, '/', '*') { + comment_depth += 1; + pos += 2; + continue; + } + + if match_two(pos, '*', '/') { + comment_depth -= 1; + + pos += 2; + + if comment_depth == 0 { + break; + } + continue; + } + + pos += 1; + } + + continue; + } + _ => {} + } + } + _ => {} + } + + pos += 1; + } + + if !brackets.is_empty() { + return Ok(ValidationResult::Incomplete); + } + + // all braces/parens/brackets closed => Ok + Ok(ValidationResult::Valid(None)) + } + + fn validate_while_typing(&self) -> bool { + false + } +} + +impl Highlighter for ReplHelper {} + +impl Hinter for ReplHelper { + type Hint = String; +} + +impl Completer for ReplHelper { + type Candidate = String; +} + +impl Helper for ReplHelper {} + +pub fn run_repl LoxResult, E: Error>(mut run: F) { + // let mut readline = DefaultEditor::new().unwrap(); + let mut readline: Editor = Editor::new().unwrap(); + readline.set_helper(Some(ReplHelper::default())); + let _ = readline.load_history("/tmp/rlox_history.txt"); + + let mut input_buf = String::new(); + + 'outer: loop { + input_buf.clear(); + + match readline.readline("> ") { + Ok(line) => { + readline.add_history_entry(&line).unwrap(); + input_buf += &line; + } + Err(ReadlineError::Interrupted) => continue 'outer, + Err(ReadlineError::Eof) => break 'outer, + Err(err) => { + println!("Error: {:?}", err); + continue 'outer; + } + }; + + /* 'inner: loop { + let num_open_braces = + (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); + let num_open_parens = + (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); + let num_open_brackets = + (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); + + // all braces/parens/brackets closed => break + if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 { + break 'inner; + } + + // any braces/parens/brackets more closing than opening => break (will be parse error) + if num_open_braces < 0 || num_open_parens < 0 || num_open_brackets < 0 { + break 'inner; + } + + match readline.readline("< ") { + Ok(line) => { + input_buf += &line; + } + Err(ReadlineError::Interrupted) => continue 'outer, + Err(ReadlineError::Eof) => break 'outer, + Err(err) => { + println!("Error: {:?}", err); + continue 'outer; + } + }; + } */ + + if input_buf.is_empty() || input_buf == "exit\n" || input_buf == "quit\n" { + std::process::exit(0); + } + + let input_buf = input_buf.trim(); + + match run(input_buf) { + LoxResult::Ok(()) => {} + LoxResult::Err(err) => println!("{}", err.to_string().red().bold()), + LoxResult::Exit(exit_code) => std::process::exit(exit_code), + } + } + + readline.save_history("/tmp/rlox_history.txt").unwrap(); +} diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 09cd212..c1633d2 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -9,10 +9,10 @@ path = "../frontend" [dependencies] -itertools = "0.10.5" -lazy_static = "1.4.0" -num-derive = "0.3.3" -num-traits = "0.2.15" -regex = "1.7.1" -thiserror = "1.0.38" -static_assertions = "1.1.0" +itertools = "0.13" +lazy_static = "1" +num-derive = "0.4" +num-traits = "0.2" +regex = "1" +thiserror = "1" +static_assertions = "1" diff --git a/vm/src/compiler.rs b/vm/src/compiler.rs index 9937964..895b233 100644 --- a/vm/src/compiler.rs +++ b/vm/src/compiler.rs @@ -236,7 +236,10 @@ impl Compiler { self.emit_opcode(Opcode::Negate); } TokenType::Bang => todo!(), - _ => unreachable!("Called unary, but next token had token_type {:?}", token.token_type), + _ => unreachable!( + "Called unary, but next token had token_type {:?}", + token.token_type + ), } Ok(()) @@ -247,8 +250,10 @@ impl Compiler { self.expression()?; - self.consume_token(TokenType::RightParen, |token| CompilerError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + CompilerError::MissingRightParen { + code_pos: token.code_pos, + } })?; Ok(()) @@ -308,7 +313,10 @@ impl Compiler { Ok(()) } // call err_fn with dummy token so we don't have to eat the EOF token - TokenType::EOF => Err(err_fn(Token::new(TokenType::EOF, self.peek_token().code_pos))), + TokenType::EOF => Err(err_fn(Token::new( + TokenType::EOF, + self.peek_token().code_pos, + ))), _ => Err(err_fn(self.next_token())), } } @@ -346,9 +354,15 @@ impl Compiler { if const_idx <= u8::MAX as usize { self.emit_opcode_byte(Opcode::LoadConst, const_idx.try_into().unwrap()); } else if const_idx <= u16::MAX as usize { - self.emit_opcode_bytes(Opcode::LoadConstLong, &u16_to_bytes(const_idx.try_into().unwrap())) + self.emit_opcode_bytes( + Opcode::LoadConstLong, + &u16_to_bytes(const_idx.try_into().unwrap()), + ) } else { - panic!("Tried to add more than {} constants to current chunk", u16::MAX); + panic!( + "Tried to add more than {} constants to current chunk", + u16::MAX + ); } } diff --git a/vm/src/debug.rs b/vm/src/debug.rs index 2d142bf..d0fe3de 100644 --- a/vm/src/debug.rs +++ b/vm/src/debug.rs @@ -16,7 +16,9 @@ pub struct ChunkDebugInfo { impl ChunkDebugInfo { pub fn new() -> Self { - ChunkDebugInfo { line_infos: Vec::new() } + ChunkDebugInfo { + line_infos: Vec::new(), + } } pub fn write_line(&mut self, line: u32, offset: usize) { diff --git a/vm/src/error.rs b/vm/src/error.rs index 58b203b..c34caa0 100644 --- a/vm/src/error.rs +++ b/vm/src/error.rs @@ -17,7 +17,11 @@ pub enum RuntimeError { #[error("Opcopde {opcode} had invalid operand {operand}")] UnaryInvalidOperand { opcode: Opcode, operand: Value }, #[error("Opcopde {opcode} had invalid operands {left} and {right}")] - BinaryInvalidOperand { opcode: Opcode, left: Value, right: Value }, + BinaryInvalidOperand { + opcode: Opcode, + left: Value, + right: Value, + }, #[error("Division by zero")] DivisionByZero, } @@ -52,7 +56,7 @@ impl From for LoxError { } } -fn format_multiple_errors(errs: &Vec) -> String { +fn format_multiple_errors(errs: &[impl std::error::Error]) -> String { let msg = if errs.len() == 1 { errs[0].to_string() } else { diff --git a/vm/src/run.rs b/vm/src/run.rs index 14591dc..5794fdf 100644 --- a/vm/src/run.rs +++ b/vm/src/run.rs @@ -51,9 +51,12 @@ pub fn run_repl(vm: &mut VM) { std::process::exit(66); }); - let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); - let num_open_parens = (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); - let num_open_brackets = (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); + let num_open_braces = + (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); + let num_open_parens = + (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); + let num_open_brackets = + (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); // all braces/parens/brackets closed => break if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 { diff --git a/vm/src/value.rs b/vm/src/value.rs index 53fc080..95aaa50 100644 --- a/vm/src/value.rs +++ b/vm/src/value.rs @@ -1,17 +1,12 @@ use std::fmt::Display; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Default, Clone, PartialEq)] pub enum Value { + #[default] Nil, Number(f64), } -impl Default for Value { - fn default() -> Self { - Value::Nil - } -} - impl Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index c487e1a..77b3e33 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -134,7 +134,13 @@ impl VM { self.push_value(Value::Number(left + right)); } // (Value::String(left), Value::String(right)) => todo!(), - (left, right) => return Err(RuntimeError::BinaryInvalidOperand { opcode, left, right }), + (left, right) => { + return Err(RuntimeError::BinaryInvalidOperand { + opcode, + left, + right, + }) + } } } Opcode::Subtract => { @@ -144,7 +150,13 @@ impl VM { (Value::Number(left), Value::Number(right)) => { self.push_value(Value::Number(left - right)); } - (left, right) => return Err(RuntimeError::BinaryInvalidOperand { opcode, left, right }), + (left, right) => { + return Err(RuntimeError::BinaryInvalidOperand { + opcode, + left, + right, + }) + } } } Opcode::Multiply => { @@ -154,7 +166,13 @@ impl VM { (Value::Number(left), Value::Number(right)) => { self.push_value(Value::Number(left * right)); } - (left, right) => return Err(RuntimeError::BinaryInvalidOperand { opcode, left, right }), + (left, right) => { + return Err(RuntimeError::BinaryInvalidOperand { + opcode, + left, + right, + }) + } } } Opcode::Divide => { @@ -167,7 +185,13 @@ impl VM { } self.push_value(Value::Number(left / right)); } - (left, right) => return Err(RuntimeError::BinaryInvalidOperand { opcode, left, right }), + (left, right) => { + return Err(RuntimeError::BinaryInvalidOperand { + opcode, + left, + right, + }) + } } } Opcode::Negate => { @@ -176,7 +200,10 @@ impl VM { if let Value::Number(num) = value { self.push_value(Value::Number(-num)); } else { - return Err(RuntimeError::UnaryInvalidOperand { opcode, operand: value }); + return Err(RuntimeError::UnaryInvalidOperand { + opcode, + operand: value, + }); } } Opcode::Return => {