diff --git a/frontend/src/lexer/_lexer.rs b/frontend/src/lexer/_lexer.rs index 8d54966..abce6fc 100644 --- a/frontend/src/lexer/_lexer.rs +++ b/frontend/src/lexer/_lexer.rs @@ -3,7 +3,7 @@ use smol_str::SmolStr; use super::{CodePos, LexerError, Token, TokenType}; -/*====================================================================================================================*/ +// ================================================================================================= static KEYWORDS: phf::Map<&'static str, TokenType> = phf_map! { "and" => TokenType::And, @@ -25,7 +25,7 @@ static KEYWORDS: phf::Map<&'static str, TokenType> = phf_map! { "while" => TokenType::While }; -/*====================================================================================================================*/ +// ================================================================================================= pub fn scan_tokens(source_code: &str) -> Result, Vec> { let lexer = Lexer::new(source_code); @@ -33,7 +33,7 @@ pub fn scan_tokens(source_code: &str) -> Result, Vec> { lexer.scan_tokens() } -/*====================================================================================================================*/ +// ================================================================================================= #[derive(Debug)] struct Lexer { @@ -242,18 +242,6 @@ impl Lexer { } fn try_parse_string(&mut self) { - // first '"' already consumed - - // advance until second " - /* while self.advance() != '"' { - if self.source_is_empty() { - self.errors.push(LexerError::UnterminatedStringLiteral { - code_pos: self.code_pos, - }); - return; - } - } */ - let mut s = String::new(); let starting_pos = self.code_pos; @@ -356,11 +344,6 @@ impl Lexer { let lexeme: String = self.source[self.start..self.current].iter().collect(); - /* let token_type = KEYWORDS - .get(&lexeme) - .cloned() - .unwrap_or(TokenType::Identifier(Box::new(lexeme))); */ - if let Some(token_type) = KEYWORDS.get(&lexeme) { // Token::new(token_type, self.code_pos) self.push_token(token_type.clone()); diff --git a/frontend/src/parser/_parser.rs b/frontend/src/parser/_parser.rs index 68a1024..511459e 100644 --- a/frontend/src/parser/_parser.rs +++ b/frontend/src/parser/_parser.rs @@ -1,12 +1,11 @@ use smol_str::SmolStr; -use crate::lexer::{Token, TokenType}; -use crate::parser::expr::BinaryOp; - use super::expr::{Expr, UnaryOp}; use super::{LogicalOp, ParserError, Stmt}; +use crate::lexer::{Token, TokenType}; +use crate::parser::expr::BinaryOp; -/*====================================================================================================================*/ +// ================================================================================================= type ParserResult = Result; @@ -14,7 +13,7 @@ pub fn parse_tokens(tokens: Vec) -> Result, Vec> { Parser::new(tokens).parse() } -/*====================================================================================================================*/ +// ================================================================================================= // takes care of token iteration struct TokenIter { @@ -71,7 +70,7 @@ impl Iterator for TokenIter { } } -/*====================================================================================================================*/ +// ================================================================================================= struct Parser { token_iter: TokenIter, @@ -413,6 +412,7 @@ impl Parser { })?; let is_in_init = self.is_in_init; + if &*method_name == "init" { self.is_in_init = true; } @@ -841,21 +841,7 @@ impl Parser { } fn next_token(&mut self) -> Token { - /* let token = self.token_iter.next().unwrap(); - - // println!("Next token: {next:?}"); - - if token.token_type == TokenType::EOF { - panic!("Someone ate a EOF token"); - } - - // if token.token_type == TokenType::Print { - // panic!("Found the print"); - // } - - token */ - - self.token_iter.next().unwrap() // .ok_or(ParserError::TokenStreamEnded) + self.token_iter.next().unwrap() } fn peek_token(&mut self) -> &Token { @@ -866,14 +852,6 @@ impl Parser { where F: Fn(&Token) -> ParserError, { - /* let token = self.next_token(); - - if token.token_type == token_type { - Ok(()) - } else { - Err(err_fn(token)) - } */ - match &self.peek_token().token_type { tt if tt == &token_type => { let _ = self.next_token(); diff --git a/frontend/src/parser/error.rs b/frontend/src/parser/error.rs index daec9fc..4f7b6cd 100644 --- a/frontend/src/parser/error.rs +++ b/frontend/src/parser/error.rs @@ -1,8 +1,7 @@ use thiserror::Error; -use crate::lexer::{CodePos, Token}; - use super::Expr; +use crate::lexer::{CodePos, Token}; #[derive(Error, Debug)] pub enum ParserError { diff --git a/frontend/src/parser/expr.rs b/frontend/src/parser/expr.rs index 1c08947..0044cd7 100644 --- a/frontend/src/parser/expr.rs +++ b/frontend/src/parser/expr.rs @@ -155,10 +155,9 @@ impl Expr { pub fn function(name: impl Into, param_names: Vec, body: Stmt) -> Self { let name = name.into(); - #[allow(clippy::box_default)] - // let closure_vars = Box::new(Vec::new()); let closure_vars = Vec::new(); let body = Box::new(body); + Self::Function { name, param_names, @@ -264,7 +263,7 @@ impl Display for Expr { } } -/*====================================================================================================================*/ +// ================================================================================================= #[derive(Debug, Clone)] pub enum Literal { @@ -285,7 +284,7 @@ impl Display for Literal { } } -/*====================================================================================================================*/ +// ================================================================================================= #[derive(Debug, Clone, Copy)] pub enum UnaryOp { @@ -302,7 +301,7 @@ impl Display for UnaryOp { } } -/*====================================================================================================================*/ +// ================================================================================================= #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[rustfmt::skip] diff --git a/interpreter/src/class.rs b/interpreter/src/class.rs index c4e28ac..420da8b 100644 --- a/interpreter/src/class.rs +++ b/interpreter/src/class.rs @@ -16,7 +16,8 @@ pub struct LoxClass { methods: FxHashMap, } -/// Representation of a class in Lox. Always behind an Rc to ensure uniqueness. Should never be handled raw. +/// Representation of a class in Lox. Always behind an Rc to ensure uniqueness. Should never be +/// handled raw. impl LoxClass { pub fn new( name: impl Into, @@ -81,19 +82,10 @@ impl LoxClass { return method.arity(); } - /* if let Some(superclass) = self.superclass { - return superclass.arity(); - } */ - 0 } pub fn get_method(&self, name: &str, this: LoxReference) -> Option { - /* self.methods - .get(name) - .cloned() - .or_else(|| self.superclass.as_ref().and_then(|cls| cls.get_method(name))) */ - if let Some(method) = self.methods.get(name) { match method { Value::Function(method) => { @@ -111,19 +103,6 @@ impl LoxClass { None } - - /* pub fn init(&self, args: Vec, env: &mut Environment) -> EvalResult<()> { - if let Some(ref superclass) = self.superclass { - let args = args.clone(); - superclass.init(args, env)?; - } - - if let Some(Value::Function(method)) = self.get_method("init") { - method.call(args, env)?; - } - - Ok(()) - } */ } impl Display for LoxClass { @@ -138,7 +117,8 @@ impl Display for LoxClass { } // slightly hacky: two classes are equal if they are stored at the same location -// since a LoxClass is always (supposed to be) behind an Rc anyways, we might as well compare their pointers +// since a LoxClass is always (supposed to be) behind an Rc anyways, we might as well compare their +// pointers impl PartialEq for LoxClass { fn eq(&self, other: &Self) -> bool { let self_ptr = self as *const LoxClass; diff --git a/interpreter/src/environment.rs b/interpreter/src/environment.rs index 958c945..e610cb1 100644 --- a/interpreter/src/environment.rs +++ b/interpreter/src/environment.rs @@ -6,9 +6,8 @@ use std::rc::Rc; use rustc_hash::FxHashMap; use smol_str::SmolStr; -use crate::error::RuntimeError; - use super::{Runtime, Value}; +use crate::error::RuntimeError; #[derive(Debug, Clone)] pub struct HeapedValue { @@ -145,9 +144,9 @@ impl<'a> Environment<'a> { !self.scope_stack.is_empty() } - /* fn current_scope(&self) -> &Scope { - self.scope_stack.last().unwrap() - } */ + // fn current_scope(&self) -> &Scope { + // self.scope_stack.last().unwrap() + // } fn current_scope_mut(&mut self) -> &mut Scope { self.scope_stack.last_mut().unwrap() @@ -193,11 +192,7 @@ impl<'a> Environment<'a> { } } - panic!("Name not defined not caught by resolver"); - - /* Err(RuntimeError::NameNotDefined { - name: name.to_owned(), - }) */ + panic!("{self}\n\nvar {name} not at level {level} where expected"); } pub fn get_local_heaped( @@ -213,11 +208,7 @@ impl<'a> Environment<'a> { return Ok(scoped_value.heapified()); } - panic!("Name not defined not caught by resolver"); - - /* Err(RuntimeError::NameNotDefined { - name: name.to_owned(), - }) */ + panic!("{self}\n\nheaped var {name} not at level {level} where expected"); } pub fn define(&mut self, name: impl Into, value: Value) { @@ -314,59 +305,3 @@ impl Write for Environment<'_> { self.runtime.flush() } } - -/*====================================================================================================================*/ - -/* struct Frame { - scopes: Vec, -} - -impl Frame { - fn new(base_scope: Scope) -> Self { - Frame { - scopes: vec![base_scope], - } - } - - fn new_global() -> Self { - Frame { scopes: Vec::new() } - } - - fn enter_scope(&mut self) { - self.scopes.push(Scope::new()); - } - - fn exit_scope(&mut self) { - self.scopes.pop().expect("Tried to exit scope, but no scope to exit"); - } - - fn get(&self, name: &str) -> Option { - for scope in self.scopes.iter().rev() { - if let Some(heap_value) = scope.get(name) { - return Some(heap_value.get_clone()); - } - } - - None - } - - fn try_define(&mut self, name: impl Into + Borrow, value: Value) -> Result<(), Value> { - if let Some(scope) = self.scopes.last_mut() { - scope.insert(name.into(), HeapValue::new(value)); - Ok(()) - } else { - Err(value) - } - } - - fn try_assign(&mut self, name: &str, value: Value) -> Result<(), Value> { - for scope in self.scopes.iter_mut().rev() { - if let Some(heap_value) = scope.get_mut(name) { - heap_value.replace(value); - return Ok(()); - } - } - - Err(value) - } -} */ diff --git a/interpreter/src/error.rs b/interpreter/src/error.rs index 5128a23..9467d23 100644 --- a/interpreter/src/error.rs +++ b/interpreter/src/error.rs @@ -6,8 +6,7 @@ use rlox2_frontend::parser::{BinaryOp, ParserError, UnaryOp}; use smol_str::SmolStr; use thiserror::Error; -use crate::Value; -use crate::{LoxClass, ResolverError}; +use crate::{LoxClass, ResolverError, Value}; #[derive(Error, Debug)] pub enum RuntimeError { diff --git a/interpreter/src/function.rs b/interpreter/src/function.rs index 1790f28..b45d1c2 100644 --- a/interpreter/src/function.rs +++ b/interpreter/src/function.rs @@ -69,7 +69,8 @@ impl Display for LoxFunction { } // slightly hacky: two functions are equal if they are stored at the same location -// since a LoxFunction is always (supposed to be) behind an Rc anyways, we might as well compare their pointers +// since a LoxFunction is always (supposed to be) behind an Rc anyways, we might as well compare +// their pointers impl PartialEq for LoxFunction { fn eq(&self, other: &Self) -> bool { let self_ptr = self as *const LoxFunction; @@ -78,7 +79,7 @@ impl PartialEq for LoxFunction { } } -/*====================================================================================================================*/ +// ================================================================================================= pub type ExternFunClosure = fn(Vec, &mut Environment) -> EvalResult; @@ -135,7 +136,8 @@ impl Debug for LoxExternFunction { } // slightly hacky: two extern functions are equal if they are stored at the same location -// since a LoxExternFunction is always (supposed to be) behind an Rc anyways, we might as well compare their pointers +// since a LoxExternFunction is always (supposed to be) behind an Rc anyways, we might as well +// compare their pointers impl PartialEq for LoxExternFunction { fn eq(&self, other: &Self) -> bool { let self_ptr = self as *const LoxExternFunction; diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 416d2cf..5dc06ee 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -3,16 +3,15 @@ use std::rc::Rc; use rlox2_frontend::parser::{BinaryOp, Expr, Literal, LogicalOp, Stmt, UnaryOp}; use rustc_hash::FxHashMap; +use super::environment::Environment; +use super::{LoxFunction, Runtime, Value}; use crate::error::RuntimeError; use crate::function::LoxExternFunction; use crate::{LoxClass, LoxReference}; -use super::environment::Environment; -use super::{LoxFunction, Runtime, Value}; - pub type EvalResult = Result; -/*====================================================================================================================*/ +// ================================================================================================= pub fn execute(statement: Stmt, runtime: &mut Runtime) -> Result<(), RuntimeError> { let mut env = Environment::new(runtime); @@ -22,7 +21,7 @@ pub fn execute(statement: Stmt, runtime: &mut Runtime) -> Result<(), RuntimeErro Ok(()) } -/*====================================================================================================================*/ +// ================================================================================================= trait Eval { fn eval(&self, env: &mut Environment) -> EvalResult; @@ -214,6 +213,7 @@ impl Eval for Expr { for method_expr in method_exprs.iter() { let method = method_expr.eval(env)?; + if let Value::Function(ref fun) = method { let name = fun.name().to_owned(); methods.insert(name, method); @@ -307,7 +307,7 @@ impl Eval for Stmt { } } -/*====================================================================================================================*/ +// ================================================================================================= pub fn call_fun(fun: Rc, env: &mut Environment) -> EvalResult { let args = env.collect_args(); diff --git a/interpreter/src/lox_std.rs b/interpreter/src/lox_std.rs index d0c6607..7a3b9ae 100644 --- a/interpreter/src/lox_std.rs +++ b/interpreter/src/lox_std.rs @@ -1,9 +1,8 @@ use smol_str::SmolStr; -use crate::error::RuntimeError; - use super::function::{ExternFunClosure, LoxExternFunction}; use super::{Runtime, Value}; +use crate::error::RuntimeError; pub fn init_std(env: &mut Runtime) { clock().register(env); @@ -13,6 +12,38 @@ pub fn init_std(env: &mut Runtime) { print_globals().register(env); } +fn clock() -> LoxExternFunction { + let closure: ExternFunClosure = |args, _env| { + assert_eq!(args.len(), 0); + let time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs_f64(); + + Ok(Value::Number(time)) + }; + + LoxExternFunction::new("clock", 0, closure) +} + +fn exit() -> LoxExternFunction { + let closure: ExternFunClosure = |args, _env| { + assert_eq!(args.len(), 1); + if let Value::Number(exit_code) = args[0] { + if exit_code.fract() == 0.0 { + let exit_code = exit_code as i32; + return Err(RuntimeError::Exit { exit_code }); + } + } + Err(RuntimeError::ExtFunCallFailed { + name: "exit".to_owned(), + msg: "Arguments to exit() must an integer".to_owned(), + }) + }; + + LoxExternFunction::new("exit", 1, closure) +} + fn input() -> LoxExternFunction { let closure: ExternFunClosure = |args, _env| { assert_eq!(args.len(), 0); @@ -32,18 +63,14 @@ fn input() -> LoxExternFunction { LoxExternFunction::new("input", 0, closure) } -fn clock() -> LoxExternFunction { - let closure: ExternFunClosure = |args, _env| { +fn print_env() -> LoxExternFunction { + let closure: ExternFunClosure = |args, env| { assert_eq!(args.len(), 0); - let time = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs_f64(); - - Ok(Value::Number(time)) + println!("{env}"); + Ok(Value::Nil) }; - LoxExternFunction::new("clock", 0, closure) + LoxExternFunction::new("print_env", 0, closure) } fn print_globals() -> LoxExternFunction { @@ -62,31 +89,3 @@ fn print_globals() -> LoxExternFunction { LoxExternFunction::new("print_globals", 0, closure) } - -fn print_env() -> LoxExternFunction { - let closure: ExternFunClosure = |args, env| { - assert_eq!(args.len(), 0); - println!("{env}"); - Ok(Value::Nil) - }; - - LoxExternFunction::new("print_env", 0, closure) -} - -fn exit() -> LoxExternFunction { - let closure: ExternFunClosure = |args, _env| { - assert_eq!(args.len(), 1); - if let Value::Number(exit_code) = args[0] { - if exit_code.fract() == 0.0 { - let exit_code = exit_code as i32; - return Err(RuntimeError::Exit { exit_code }); - } - } - Err(RuntimeError::ExtFunCallFailed { - name: "exit".to_owned(), - msg: "Arguments to exit() must an integer".to_owned(), - }) - }; - - LoxExternFunction::new("exit", 1, closure) -} diff --git a/interpreter/src/object.rs b/interpreter/src/object.rs index afdc5b0..f5b9168 100644 --- a/interpreter/src/object.rs +++ b/interpreter/src/object.rs @@ -42,11 +42,11 @@ impl LoxObject { } } -/*====================================================================================================================*/ +// ================================================================================================= -/// Pointer-like to LoxObject. Has interior mutability, which means it can't give out references to its interior. -/// Also includes the possibility of weird, self-referential constructions that lead to unsafe beheaviour, -/// so make sure not to do any (too) weird shit here. +/// Pointer-like to LoxObject. Has interior mutability, which means it can't give out references to +/// its interior. Also includes the possibility of weird, self-referential constructions that lead +/// to unsafe beheaviour, so make sure not to do any (too) weird shit here. #[derive(Debug, Clone)] pub struct LoxReference { inner: Rc>, @@ -83,10 +83,6 @@ impl LoxReference { object.set(name, value) } } - - /* pub fn init(&self, args: Vec, env: &mut Environment) -> EvalResult<()> { - self.class().init(self.clone(), args, env) - } */ } impl PartialEq for LoxReference { diff --git a/interpreter/src/resolver/_resolver.rs b/interpreter/src/resolver/_resolver.rs index 6072c24..02d203c 100644 --- a/interpreter/src/resolver/_resolver.rs +++ b/interpreter/src/resolver/_resolver.rs @@ -2,17 +2,16 @@ use rlox2_frontend::parser::{Expr, Stmt}; use rustc_hash::FxHashMap; use smol_str::SmolStr; -use crate::Runtime; -use crate::{LoxError, ResolverError}; +use crate::{LoxError, ResolverError, Runtime}; -/*====================================================================================================================*/ +// ================================================================================================= type ResolverScope = FxHashMap; // type ResolverFrame = Vec; type ResolverResult = Result; -/*====================================================================================================================*/ +// ================================================================================================= #[derive(Debug, Clone, Copy)] enum ResolveStatus { @@ -36,7 +35,7 @@ impl ResolverFrame { } } -/*====================================================================================================================*/ +// ================================================================================================= pub fn resolve(statement: &mut Stmt, runtime: &mut Runtime) -> Result<(), LoxError> { let global_names = runtime.globals().keys().cloned(); @@ -88,9 +87,9 @@ impl Resolver { &mut self.frame_mut().scopes } - /* fn closure_vars(&self) -> &FxHashMap { - &self.frame().closure_vars - } */ + // fn closure_vars(&self) -> &FxHashMap { + // &self.frame().closure_vars + // } fn closure_vars_mut(&mut self) -> &mut FxHashMap { &mut self.frame_mut().closure_vars @@ -186,7 +185,7 @@ impl Resolver { // if we have more than one frame: look for closure variable if self.frames.len() > 1 { - //try to resolve closure variable up from one frame down + // try to resolve closure variable up from one frame down if let Some(level) = self.resolve_closure(name.clone(), self.frames.len() - 2) { self.closure_vars_mut().insert(name.clone(), level); @@ -340,8 +339,6 @@ impl Resolver { closure_vars, body, } => { - // let old_closure_names = std::mem::take(&mut self.closure_vars); - self.push_frame(); self.declare(name.clone())?; diff --git a/interpreter/src/run.rs b/interpreter/src/run.rs index f7d35f5..e5d69ed 100644 --- a/interpreter/src/run.rs +++ b/interpreter/src/run.rs @@ -1,12 +1,11 @@ use rlox2_frontend::lexer::{scan_tokens, Token}; use rlox2_frontend::parser::parse_tokens; +use super::Runtime; use crate::error::LoxError; use crate::interpreter::execute; use crate::resolver::resolve; -use super::Runtime; - pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> { let tokens: Vec = scan_tokens(source)?; diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index c2f3720..9dfaa82 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -6,10 +6,9 @@ use std::rc::Rc; use rustc_hash::FxHashMap; use smol_str::SmolStr; -use crate::error::RuntimeError; - use super::lox_std::init_std; use super::Value; +use crate::error::RuntimeError; pub struct Runtime { globals: FxHashMap, diff --git a/interpreter/src/value.rs b/interpreter/src/value.rs index 40ffa47..25e7fb2 100644 --- a/interpreter/src/value.rs +++ b/interpreter/src/value.rs @@ -3,10 +3,9 @@ use std::rc::Rc; use smol_str::SmolStr; -use crate::{LoxClass, LoxReference}; - use super::function::LoxExternFunction; use super::LoxFunction; +use crate::{LoxClass, LoxReference}; #[derive(Debug, Default, Clone, PartialEq)] pub enum Value { diff --git a/src/main.rs b/src/main.rs index 41825ff..63367cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,44 +19,11 @@ struct CliArgs { debug: bool, } -/* -let source_code = std::fs::read_to_string(script_path).unwrap_or_else(|err| { - eprintln!("Reading script file {script_path} failed: {err}"); - std::process::exit(66); -}); */ - fn main() { let cli_args = CliArgs::parse(); if cli_args.vm { unimplemented!() - /* use rlox2_vm::LoxError; - - let mut vm = rlox2_vm::VM::default(); - - if let Some(file_name) = cli_args.file_name { - let source = std::fs::read_to_string(&file_name).unwrap_or_else(|err| { - eprintln!("Reading script file {file_name} failed: {err}"); - std::process::exit(66); - }); - - if let Err(err) = rlox2_vm::run(&source, &mut vm) { - eprintln!("{err}"); - match err { - LoxError::LexerError { .. } | LoxError::CompileError { .. } => { - std::process::exit(65) - } - LoxError::RuntimeError { .. } => std::process::exit(70), - LoxError::Exit { exit_code } => std::process::exit(exit_code), - } - } - - if !cli_args.interactive { - return; - } - } - - rlox2_vm::run_repl(&mut vm); */ } else { use rlox2_interpreter::LoxError; diff --git a/src/repl.rs b/src/repl.rs index f199364..69ed2fa 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -151,36 +151,7 @@ pub fn run_repl LoxResult, E: Error>(mut run: F) { } }; - /* '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; - } - }; - } */ + readline.save_history("/tmp/rlox_history.txt").unwrap(); if input_buf.is_empty() || input_buf == "exit\n" || input_buf == "quit\n" { std::process::exit(0); @@ -194,6 +165,4 @@ pub fn run_repl LoxResult, E: Error>(mut run: F) { LoxResult::Exit(exit_code) => std::process::exit(exit_code), } } - - readline.save_history("/tmp/rlox_history.txt").unwrap(); }