improved REPL a bit

now uses rustyline for input
This commit is contained in:
Moritz Gmeiner 2024-09-02 03:10:35 +02:00
commit fb88595b6c
13 changed files with 560 additions and 100 deletions

281
Cargo.lock generated
View file

@ -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"

View file

@ -21,3 +21,5 @@ path = "interpreter"
[dependencies]
clap = { version = "4", features = ["derive"] }
colored = "2.1.0"
rustyline = "14.0.0"

View file

@ -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;

View file

@ -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<Token> = scan_tokens(source)?;

View file

@ -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),
},
);
}
}

199
src/repl.rs Normal file
View file

@ -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<E: Error> {
Ok(()),
Err(E),
Exit(i32),
}
#[derive(Default)]
struct ReplHelper {}
impl Validator for ReplHelper {
fn validate(&self, ctx: &mut ValidationContext) -> rustyline::Result<ValidationResult> {
let input = ctx.input();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Brackets {
LeftParen,
LeftBrace,
}
use Brackets::*;
let mut brackets = Vec::new();
let chars: Vec<char> = 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<F: FnMut(&str) -> LoxResult<E>, E: Error>(mut run: F) {
// let mut readline = DefaultEditor::new().unwrap();
let mut readline: Editor<ReplHelper, FileHistory> = 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();
}

View file

@ -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"

View file

@ -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 {
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
);
}
}

View file

@ -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) {

View file

@ -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<RuntimeError> for LoxError {
}
}
fn format_multiple_errors(errs: &Vec<impl std::error::Error>) -> String {
fn format_multiple_errors(errs: &[impl std::error::Error]) -> String {
let msg = if errs.len() == 1 {
errs[0].to_string()
} else {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 => {