diff --git a/Cargo.lock b/Cargo.lock index 1ab8d78..13353d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,6 +362,7 @@ version = "0.1.0" dependencies = [ "itertools", "phf", + "smol_str", "thiserror", ] @@ -373,6 +374,7 @@ dependencies = [ "itertools", "rlox2-frontend", "rustc-hash", + "smol_str", "thiserror", ] @@ -417,6 +419,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "serde" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -429,6 +451,15 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + [[package]] name = "strsim" version = "0.11.1" @@ -437,9 +468,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.76" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 4a6fe81..f73553d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,6 @@ path = "interpreter" # path = "vm" [dependencies] -clap = { version = "4", features = ["derive"] } +clap = { version = "4.5.16", features = ["derive"] } colored = "2.1.0" rustyline = "14.0.0" diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 3e970c6..1c26894 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -phf = { version = "0.11", features = ["macros"] } -thiserror = "1" -itertools = "0.13" +smol_str = "0.2.2" +phf = { version = "0.11.2", features = ["macros"] } +thiserror = "1.0.63" +itertools = "0.13.0" diff --git a/frontend/src/lexer/_lexer.rs b/frontend/src/lexer/_lexer.rs index f296e47..8d54966 100644 --- a/frontend/src/lexer/_lexer.rs +++ b/frontend/src/lexer/_lexer.rs @@ -1,4 +1,5 @@ use phf::phf_map; +use smol_str::SmolStr; use super::{CodePos, LexerError, Token, TokenType}; @@ -130,8 +131,9 @@ impl Lexer { // advance until either source is empty or newline if found while !self.source_is_empty() && self.advance() != '\n' {} - let comment: Box = - self.source[self.start + 2..self.current].iter().collect(); + let comment = SmolStr::from_iter( + self.source[self.start + 2..self.current].iter().cloned(), + ); self.push_token(TokenType::Comment(comment)); } else if self.consume('*') { @@ -170,9 +172,11 @@ impl Lexer { self.advance(); } - let comment: Box = self.source[self.start + 2..self.current - 2] - .iter() - .collect(); + let comment = SmolStr::from_iter( + self.source[self.start + 2..self.current - 2] + .iter() + .cloned(), + ); self.push_token(TokenType::Comment(comment)); } else { @@ -289,11 +293,6 @@ impl Lexer { } } - // let string_literal: Box = self.source[self.start + 1..self.current - 1] - // .iter() - // .collect(); - - // Some(TokenType::String(Box::new(string_literal))) self.tokens.push(Token::new_string(s, self.code_pos)); } diff --git a/frontend/src/lexer/token.rs b/frontend/src/lexer/token.rs index 7d49ec7..d173809 100644 --- a/frontend/src/lexer/token.rs +++ b/frontend/src/lexer/token.rs @@ -1,5 +1,7 @@ use std::fmt::{Debug, Display}; +use smol_str::SmolStr; + use super::CodePos; #[repr(u8)] @@ -17,13 +19,13 @@ pub enum TokenType { Less, LessEqual, // Identifier and literals - Identifier(Box), String(Box), Number(f64), + Identifier(SmolStr), String(SmolStr), Number(f64), // Keywords And, Break, Class, Else, False, Fun, For, If, Nil, Or, Print, Return, Super, This, True, Var, While, - Comment(Box), + Comment(SmolStr), #[allow(clippy::upper_case_acronyms)] EOF @@ -42,14 +44,14 @@ impl Token { } } - pub fn new_string(s: impl Into>, code_pos: CodePos) -> Self { + pub fn new_string(s: impl Into, code_pos: CodePos) -> Self { Token { token_type: TokenType::String(s.into()), code_pos, } } - pub fn new_identifier(name: impl Into>, code_pos: CodePos) -> Self { + pub fn new_identifier(name: impl Into, code_pos: CodePos) -> Self { Token { token_type: TokenType::Identifier(name.into()), code_pos, diff --git a/frontend/src/parser/_parser.rs b/frontend/src/parser/_parser.rs index a0eeba6..68a1024 100644 --- a/frontend/src/parser/_parser.rs +++ b/frontend/src/parser/_parser.rs @@ -1,3 +1,5 @@ +use smol_str::SmolStr; + use crate::lexer::{Token, TokenType}; use crate::parser::expr::BinaryOp; @@ -481,7 +483,7 @@ impl Parser { Ok(Expr::function(name, param_names, body)) } - fn collect_params(&mut self) -> ParserResult>> { + fn collect_params(&mut self) -> ParserResult> { assert_eq!(self.next_token().token_type, TokenType::LeftParen); if self.peek_token().token_type == TokenType::RightParen { @@ -825,7 +827,7 @@ impl Parser { }) } - fn identifier(&mut self, msg: &str) -> ParserResult> { + fn identifier(&mut self, msg: &str) -> ParserResult { match self.peek_token().token_type { TokenType::Identifier(_) => match self.next_token().token_type { TokenType::Identifier(s) => Ok(s), diff --git a/frontend/src/parser/expr.rs b/frontend/src/parser/expr.rs index c5ea76b..1c08947 100644 --- a/frontend/src/parser/expr.rs +++ b/frontend/src/parser/expr.rs @@ -1,6 +1,7 @@ use std::fmt::Display; use itertools::Itertools; +use smol_str::SmolStr; use super::Stmt; @@ -27,14 +28,14 @@ pub enum Expr { expr: Box, }, Variable { - name: Box, + name: SmolStr, }, LocalVariable { - name: Box, + name: SmolStr, level: usize, }, GlobalVariable { - name: Box, + name: SmolStr, }, Assignment { target: Box, @@ -46,21 +47,21 @@ pub enum Expr { }, Get { target: Box, - name: Box, + name: SmolStr, }, Set { target: Box, - name: Box, + name: SmolStr, value: Box, }, Function { - name: Box, - param_names: Vec>, - closure_vars: Vec<(Box, usize)>, + name: SmolStr, + param_names: Vec, + closure_vars: Vec<(SmolStr, usize)>, body: Box, }, Class { - name: Box, + name: SmolStr, superclass: Option>, methods: Box>, }, @@ -68,12 +69,12 @@ pub enum Expr { Super { super_var: Box, this_var: Box, - method: Box, + method: SmolStr, }, } impl Expr { - pub fn string(s: impl Into>) -> Self { + pub fn string(s: impl Into) -> Self { let s = s.into(); Expr::Literal { literal: Literal::String(s), @@ -120,17 +121,17 @@ impl Expr { Expr::Grouping { expr } } - pub fn variable(name: impl Into>) -> Self { + pub fn variable(name: impl Into) -> Self { let name = name.into(); Expr::Variable { name } } - pub fn local_variable(name: impl Into>, level: usize) -> Self { + pub fn local_variable(name: impl Into, level: usize) -> Self { let name = name.into(); Expr::LocalVariable { name, level } } - pub fn global_variable(name: impl Into>) -> Self { + pub fn global_variable(name: impl Into) -> Self { let name = name.into(); Expr::GlobalVariable { name } } @@ -146,13 +147,13 @@ impl Expr { Expr::Call { callee, args } } - pub fn get(target: Expr, name: impl Into>) -> Self { + pub fn get(target: Expr, name: impl Into) -> Self { let target = Box::new(target); let name = name.into(); Expr::Get { target, name } } - pub fn function(name: impl Into>, param_names: Vec>, body: Stmt) -> Self { + 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()); @@ -166,7 +167,7 @@ impl Expr { } } - pub fn class(name: impl Into>, methods: Vec, superclass: Option) -> Self { + pub fn class(name: impl Into, methods: Vec, superclass: Option) -> Self { let superclass = superclass.map(Box::new); let name = name.into(); let methods = Box::new(methods); @@ -181,7 +182,7 @@ impl Expr { pub fn super_( super_var: impl Into>, this_var: impl Into>, - method: impl Into>, + method: impl Into, ) -> Self { let super_var = super_var.into(); let this_var = this_var.into(); @@ -267,7 +268,7 @@ impl Display for Expr { #[derive(Debug, Clone)] pub enum Literal { - String(Box), + String(SmolStr), Number(f64), Bool(bool), Nil, diff --git a/frontend/src/parser/stmt.rs b/frontend/src/parser/stmt.rs index 18f5dec..bbc7aa0 100644 --- a/frontend/src/parser/stmt.rs +++ b/frontend/src/parser/stmt.rs @@ -1,5 +1,7 @@ use std::fmt::Display; +use smol_str::SmolStr; + use super::misc::indent; use super::Expr; @@ -18,7 +20,7 @@ pub enum Stmt { body: Box, }, VarDecl { - name: Box, + name: SmolStr, initializer: Box, }, Block { @@ -62,7 +64,7 @@ impl Stmt { Stmt::While { condition, body } } - pub fn var_decl(name: impl Into>, initializer: impl Into>) -> Self { + pub fn var_decl(name: impl Into, initializer: impl Into>) -> Self { let name = name.into(); let initializer = initializer.into(); diff --git a/interpreter/Cargo.toml b/interpreter/Cargo.toml index aa3599b..ee19381 100644 --- a/interpreter/Cargo.toml +++ b/interpreter/Cargo.toml @@ -12,6 +12,7 @@ path = "../frontend" glob = "0.3" [dependencies] -thiserror = "1" -itertools = "0.13" -rustc-hash = "2" +itertools = "0.13.0" +rustc-hash = "2.0.0" +smol_str = "0.2.2" +thiserror = "1.0.63" diff --git a/interpreter/src/class.rs b/interpreter/src/class.rs index 20cc1e7..c4e28ac 100644 --- a/interpreter/src/class.rs +++ b/interpreter/src/class.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use rlox2_frontend::parser::{Expr, Stmt}; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use crate::{LoxFunction, LoxReference, Value}; @@ -10,7 +11,7 @@ use crate::{LoxFunction, LoxReference, Value}; pub struct LoxClass { superclass: Option>, - name: Box, + name: SmolStr, methods: FxHashMap, } @@ -18,7 +19,7 @@ pub struct LoxClass { /// 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>, + name: impl Into, methods: FxHashMap, superclass: Option>, ) -> Rc { diff --git a/interpreter/src/environment.rs b/interpreter/src/environment.rs index a77872b..9f0f494 100644 --- a/interpreter/src/environment.rs +++ b/interpreter/src/environment.rs @@ -4,6 +4,7 @@ use std::io::{Read, Write}; use std::rc::Rc; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use crate::error::RuntimeError; @@ -89,8 +90,8 @@ impl Display for ScopedValue { } } -type Scope = FxHashMap, ScopedValue>; -pub type ClosureScope = FxHashMap, HeapedValue>; +type Scope = FxHashMap; +pub type ClosureScope = FxHashMap; #[derive(Debug)] pub struct Environment<'a> { @@ -128,7 +129,7 @@ impl<'a> Environment<'a> { std::mem::take(&mut self.arg_stack) } - pub fn globals(&self) -> &FxHashMap, Value> { + pub fn globals(&self) -> &FxHashMap { self.runtime.globals() } @@ -219,7 +220,7 @@ impl<'a> Environment<'a> { }) */ } - pub fn define(&mut self, name: impl Into>, value: Value) { + pub fn define(&mut self, name: impl Into, value: Value) { if self.has_scope() { let name = name.into(); self.current_scope_mut() @@ -246,7 +247,7 @@ impl<'a> Environment<'a> { }) } - pub fn collect_closure(&mut self, closure_vars: &[(Box, usize)]) -> ClosureScope { + pub fn collect_closure(&mut self, closure_vars: &[(SmolStr, usize)]) -> ClosureScope { let mut closure_scope = ClosureScope::default(); for (name, level) in closure_vars { diff --git a/interpreter/src/error.rs b/interpreter/src/error.rs index 9244b31..8d6ca8c 100644 --- a/interpreter/src/error.rs +++ b/interpreter/src/error.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use rlox2_frontend::lexer::LexerError; use rlox2_frontend::parser::{BinaryOp, ParserError, UnaryOp}; +use smol_str::SmolStr; use thiserror::Error; use crate::Value; @@ -45,7 +46,7 @@ pub enum RuntimeError { #[error("only objects have attributes")] InvalidSetTarget, #[error("class {0} has no property {name}", class.name())] - UndefinedAttribute { class: Rc, name: Box }, + UndefinedAttribute { class: Rc, name: SmolStr }, #[error("{value} is not a valid superclass")] InvalidSuperclass { value: Value }, #[error("stack overflow")] diff --git a/interpreter/src/function.rs b/interpreter/src/function.rs index a428322..acde3fb 100644 --- a/interpreter/src/function.rs +++ b/interpreter/src/function.rs @@ -2,6 +2,7 @@ use std::fmt::{Debug, Display}; use std::rc::Rc; use rlox2_frontend::parser::Stmt; +use smol_str::SmolStr; use crate::environment::{ClosureScope, HeapedValue}; @@ -11,17 +12,17 @@ use super::{Runtime, Value}; #[derive(Debug, Clone)] pub struct LoxFunction { - name: Box, + name: SmolStr, closure: ClosureScope, - param_names: Vec>, + param_names: Vec, body: Box, } impl LoxFunction { pub fn new( - name: impl Into>, + name: impl Into, closure: ClosureScope, - param_names: Vec>, + param_names: Vec, body: Stmt, ) -> Rc { let name = name.into(); @@ -43,7 +44,7 @@ impl LoxFunction { &self.closure } - pub fn param_names(&self) -> &[Box] { + pub fn param_names(&self) -> &[SmolStr] { &self.param_names } @@ -55,7 +56,7 @@ impl LoxFunction { self.param_names().len() } - pub fn inject_closed_var(&mut self, name: impl Into>, value: Value) { + pub fn inject_closed_var(&mut self, name: impl Into, value: Value) { let name = name.into(); let heaped_value = HeapedValue::new(value); self.closure.insert(name, heaped_value); diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 92c8d99..eb54f34 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -154,7 +154,8 @@ impl Eval for Expr { if let Value::Object(object) = target { object.get(name).ok_or_else(|| { let class = object.class(); - let name = name.to_owned(); + let name = name.clone(); + RuntimeError::UndefinedAttribute { class, name } }) } else { diff --git a/interpreter/src/lox_std.rs b/interpreter/src/lox_std.rs index ff0ba3b..6b9b785 100644 --- a/interpreter/src/lox_std.rs +++ b/interpreter/src/lox_std.rs @@ -1,3 +1,5 @@ +use smol_str::SmolStr; + use crate::error::RuntimeError; use super::function::{ExternFunClosure, LoxExternFunction}; @@ -47,7 +49,7 @@ fn clock() -> LoxExternFunction { fn print_globals() -> LoxExternFunction { let closure: ExternFunClosure = |args, env| { assert_eq!(args.len(), 0); - let mut globals: Vec<(&Box, &Value)> = env.globals().iter().collect(); + let mut globals: Vec<(&SmolStr, &Value)> = env.globals().iter().collect(); globals.sort_by_key(|&(name, _value)| name); diff --git a/interpreter/src/object.rs b/interpreter/src/object.rs index d857658..afdc5b0 100644 --- a/interpreter/src/object.rs +++ b/interpreter/src/object.rs @@ -3,6 +3,7 @@ use std::fmt::Display; use std::rc::Rc; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use crate::{LoxClass, Value}; @@ -12,7 +13,7 @@ use crate::{LoxClass, Value}; struct LoxObject { class: Rc, - attrs: FxHashMap, Value>, + attrs: FxHashMap, } impl LoxObject { @@ -35,7 +36,7 @@ impl LoxObject { self.class.get_method(name, this) } - fn set(&mut self, name: impl Into>, value: Value) { + fn set(&mut self, name: impl Into, value: Value) { let name = name.into(); self.attrs.insert(name, value); } @@ -75,7 +76,7 @@ impl LoxReference { } } - pub fn set(&mut self, name: impl Into>, value: Value) { + pub fn set(&mut self, name: impl Into, value: Value) { unsafe { let ptr = self.inner.get(); let object = &mut *ptr; diff --git a/interpreter/src/resolver/_resolver.rs b/interpreter/src/resolver/_resolver.rs index d73c0a0..70a3f2a 100644 --- a/interpreter/src/resolver/_resolver.rs +++ b/interpreter/src/resolver/_resolver.rs @@ -1,12 +1,13 @@ use rlox2_frontend::parser::{Expr, Stmt}; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use crate::Runtime; use crate::{LoxError, ResolverError}; /*====================================================================================================================*/ -type ResolverScope = FxHashMap, ResolveStatus>; +type ResolverScope = FxHashMap; type ResolverFrame = Vec; type ResolverResult = Result; @@ -37,11 +38,11 @@ struct Resolver { // local_scopes: Vec, frames: Vec, - closure_vars: FxHashMap, usize>, + closure_vars: FxHashMap, } impl Resolver { - fn new(global_names: impl Iterator>) -> Self { + fn new(global_names: impl Iterator) -> Self { let mut global_scope = ResolverScope::default(); for name in global_names { @@ -83,7 +84,7 @@ impl Resolver { .expect("Tried to pop non-existant ResolverFrame"); } - fn declare(&mut self, name: impl Into>) -> ResolverResult<()> { + fn declare(&mut self, name: impl Into) -> ResolverResult<()> { let name = name.into(); if let Some(local_scope) = self.local_scopes_mut().last_mut() { @@ -100,7 +101,7 @@ impl Resolver { Ok(()) } - fn define(&mut self, name: impl Into>) { + fn define(&mut self, name: impl Into) { let name = name.into(); if let Some(local_scope) = self.local_scopes_mut().last_mut() { diff --git a/interpreter/src/resolver/error.rs b/interpreter/src/resolver/error.rs index 9c36710..f6f35b4 100644 --- a/interpreter/src/resolver/error.rs +++ b/interpreter/src/resolver/error.rs @@ -1,11 +1,12 @@ +use smol_str::SmolStr; use thiserror::Error; #[derive(Error, Debug)] pub enum ResolverError { #[error("can't read variable {name} in its own initializer.")] - VarInOwnInitializer { name: Box }, + VarInOwnInitializer { name: SmolStr }, #[error("variable {name} not defined")] - UnresolvableVariable { name: Box }, + UnresolvableVariable { name: SmolStr }, #[error("return outside of function definition")] ReturnOutsideFunction, #[error("this outside of method")] @@ -13,5 +14,5 @@ pub enum ResolverError { #[error("super outside of subclass method")] SuperOutsideMethod, #[error("local variable {name} declares multiple times")] - LocalMulipleDeclarations { name: Box }, + LocalMulipleDeclarations { name: SmolStr }, } diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index 3d1fd2a..c2f3720 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -4,6 +4,7 @@ use std::io::{stdin, stdout, Read, Write}; use std::rc::Rc; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use crate::error::RuntimeError; @@ -11,7 +12,7 @@ use super::lox_std::init_std; use super::Value; pub struct Runtime { - globals: FxHashMap, Value>, + globals: FxHashMap, in_stream: Rc>, out_stream: Rc>, @@ -53,7 +54,7 @@ impl Runtime { self.out_stream.as_ref().borrow_mut() } - pub fn globals(&self) -> &FxHashMap, Value> { + pub fn globals(&self) -> &FxHashMap { &self.globals } @@ -66,7 +67,7 @@ impl Runtime { }) } - pub fn define_global(&mut self, name: impl Into>, value: Value) { + pub fn define_global(&mut self, name: impl Into, value: Value) { let name = name.into(); self.globals.insert(name, value); } diff --git a/interpreter/src/value.rs b/interpreter/src/value.rs index 1796376..40ffa47 100644 --- a/interpreter/src/value.rs +++ b/interpreter/src/value.rs @@ -1,6 +1,8 @@ use std::fmt::{Debug, Display}; use std::rc::Rc; +use smol_str::SmolStr; + use crate::{LoxClass, LoxReference}; use super::function::LoxExternFunction; @@ -12,7 +14,7 @@ pub enum Value { Class(Rc), Function(Rc), ExternFunction(Rc), - String(Box), + String(SmolStr), Number(f64), Bool(bool), #[default] @@ -34,7 +36,7 @@ impl Value { Value::ExternFunction(fun) } - pub fn string(s: impl Into>) -> Self { + pub fn string(s: impl Into) -> Self { let s = s.into(); Value::String(s) } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index c1633d2..7550340 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -9,10 +9,10 @@ path = "../frontend" [dependencies] -itertools = "0.13" -lazy_static = "1" -num-derive = "0.4" -num-traits = "0.2" -regex = "1" -thiserror = "1" -static_assertions = "1" +itertools = "0.13.0" +lazy_static = "1.5.0" +num-derive = "0.4.2" +num-traits = "0.2.19" +regex = "1.10.6" +static_assertions = "1.1.0" +thiserror = "1.0.63"