From 84a7bf453f28f73dc96909b8fa7b3a57b4745a00 Mon Sep 17 00:00:00 2001 From: Giulio Agostini Date: Tue, 7 Jul 2026 20:31:23 +0200 Subject: [PATCH] removed waring (have remaind dead code for future feature) --- README.org | 1 + examples/test_struct.lox | 27 +++++++++++++++ src/backend/interpreter.rs | 6 ++-- src/common/base_value.rs | 32 +++++++++--------- src/frontend/lexer.rs | 20 +++++------ src/frontend/parser.rs | 59 ++++++++++++++++++++------------- src/frontend/source_registry.rs | 8 ++++- src/logging/display_ast.rs | 2 +- src/logging/display_token.rs | 8 ++--- src/main.rs | 33 +++++++----------- src/middleend/scope_stack.rs | 10 +++--- 11 files changed, 122 insertions(+), 84 deletions(-) create mode 100644 examples/test_struct.lox diff --git a/README.org b/README.org index 4dce23c..2d8d302 100755 --- a/README.org +++ b/README.org @@ -10,6 +10,7 @@ end * Planning: allora quello che devo fare è: ** TODO Controllare se ho finito la questione del retourn:labe +** TODO Complete the use os source slice inside parser (many node hase syntetic source slice or badly wrpapped) ** TODO implement struct: #+begin_src rlox Cosa :: struct{ diff --git a/examples/test_struct.lox b/examples/test_struct.lox new file mode 100644 index 0000000..a45a801 --- /dev/null +++ b/examples/test_struct.lox @@ -0,0 +1,27 @@ + +Data :: struct { + number: Number, + string: String, + bool: Bool +}; + +Data.new :: fn(number: Number, string: String, bool: Bool) -> Self +do + return Self { + number: number, + string: string, + bool: bool + }; +end; + +Data.function :: fn( + self, + number: Number, + string: String, + bool: Bool,) + {number == 42} : Nil +do + self.number = number; + self.string = string; + self.bool = bool; +end; diff --git a/src/backend/interpreter.rs b/src/backend/interpreter.rs index 3bfe552..99e4676 100755 --- a/src/backend/interpreter.rs +++ b/src/backend/interpreter.rs @@ -3,7 +3,7 @@ use crate::{ common::{ ast::{AstNode, Expr, NodeId}, base_value::{BaseValue, NativeFunction, Number, Truthy}, - lox_result::{runtime_error, LoxError, LoxResult}, + lox_result::{LoxError, LoxResult, runtime_error}, }, frontend::{source_registry::SourceSlice, tokens::TokenType}, }; @@ -32,14 +32,14 @@ impl Interpreter { let mut env = EnvironmentStack::new(); let _ = env.declare( "clock".to_string(), - BaseValue::NativeFunction(NativeFunction::new(Vec::default(), |_args| { + BaseValue::NativeFunction(Box::new(NativeFunction::new(Vec::default(), |_args| { BaseValue::Number(Number::U128( std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_millis(), )) - })), + }))), ); Self { enviorment: env, diff --git a/src/common/base_value.rs b/src/common/base_value.rs index 9d1862d..82aeb88 100755 --- a/src/common/base_value.rs +++ b/src/common/base_value.rs @@ -2,8 +2,9 @@ use core::fmt; use std::collections::HashMap; use std::fmt::Display; use std::ops::{Add, Div, Mul, Not, Rem, Sub}; +use std::ptr::fn_addr_eq; -use crate::common::lox_result::{runtime_error, LoxResult}; +use crate::common::lox_result::{LoxResult, runtime_error}; use crate::common::types::Type; use crate::{ backend::environment::EnvironmentStack, common::ast::AstNode, @@ -270,9 +271,9 @@ pub enum BaseValue { Number(Number), Boolean(bool), Nil, - Function(LoxFunction), - NativeFunction(NativeFunction), - Struct(Struct), + Function(Box), + NativeFunction(Box), + Struct(Box), } struct Dict { @@ -284,18 +285,12 @@ struct ReturnValue { value: Type, } -impl ReturnValue { - pub fn new(label: Vec, value: Type) -> Self { - Self { label, value } - } -} - impl BaseValue { pub fn is_callable(&self) -> bool { - match self { - BaseValue::Function(..) | BaseValue::NativeFunction(..) => true, - _ => false, - } + matches!( + self, + BaseValue::Function(..) | BaseValue::NativeFunction(..) + ) } } @@ -350,11 +345,16 @@ impl LoxFunction { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct NativeFunction { pub parameters: Vec<(String, Type)>, pub function: fn(&[BaseValue]) -> BaseValue, } +impl PartialEq for NativeFunction { + fn eq(&self, other: &Self) -> bool { + self.parameters == other.parameters && fn_addr_eq(self.function, other.function) + } +} impl NativeFunction { pub fn new(parameters: Vec<(String, Type)>, function: fn(&[BaseValue]) -> BaseValue) -> Self { @@ -367,7 +367,7 @@ impl NativeFunction { #[derive(Debug, Clone, PartialEq)] pub struct Struct { - pub fields: Vec<(String, BaseValue)>, + pub fields: Vec<(String, Type)>, } // Trait implementations for BaseValue diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 5a61faf..3c915d9 100755 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -1,5 +1,5 @@ use crate::common::base_value::{BaseValue, Number}; -use crate::common::lox_result::{lexical_error, LoxError, LoxResult}; +use crate::common::lox_result::{LoxError, LoxResult, lexical_error}; use crate::frontend::source_registry::{SourceId, SourcePosition, SourceSlice}; use crate::frontend::tokens::{Token, TokenType}; @@ -102,7 +102,7 @@ impl Lexer { token_type, text, SourceSlice::from_positions( - self.source_id.clone(), + self.source_id, self.start_pos.clone(), self.end_pos.clone(), ), @@ -115,7 +115,7 @@ impl Lexer { text, Some(literal), SourceSlice::from_positions( - self.source_id.clone(), + self.source_id, self.start_pos.clone(), self.end_pos.clone(), ), @@ -174,7 +174,7 @@ impl Lexer { if self.is_at_end() { return lexical_error( SourceSlice::from_positions( - self.source_id.clone(), + self.source_id, self.start_pos.clone(), self.end_pos.clone(), ), @@ -190,11 +190,11 @@ impl Lexer { (' ', _) | ('\r', _) | ('\t', _) => Ok(None), ('\n', _) => Ok(None), ('"', _) => self.string(), - (c, _) if c.is_digit(10) => self.number(), + (c, _) if c.is_ascii_digit() => self.number(), (c, _) if c.is_alphanumeric() || c == '_' => self.identifier(), _ => Err(LoxError::LexicalError { source_slice: SourceSlice::from_positions( - self.source_id.clone(), + self.source_id, self.start_pos.clone(), self.end_pos.clone(), ), @@ -210,7 +210,7 @@ impl Lexer { if self.is_at_end() { return Err(LoxError::LexicalError { source_slice: SourceSlice::from_positions( - self.source_id.clone(), + self.source_id, self.start_pos.clone(), self.end_pos.clone(), ), @@ -226,14 +226,14 @@ impl Lexer { fn number(&mut self) -> LoxResult> { // Leggi la parte intera - while self.peek().is_digit(10) { + while self.peek().is_ascii_digit() { self.advance(); } // Controlla se c'è una parte decimale - let has_decimal = if self.peek() == '.' && self.peek_next().is_digit(10) { + let has_decimal = if self.peek() == '.' && self.peek_next().is_ascii_digit() { self.advance(); // consuma il '.' - while self.peek().is_digit(10) { + while self.peek().is_ascii_digit() { self.advance(); } true diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index d18dea3..c9bc811 100755 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -1,8 +1,8 @@ use crate::{ common::{ ast::{AstNode, Expr}, - base_value::{BaseValue, LoxFunction}, - lox_result::{parse_error, runtime_error, LoxResult}, + base_value::{BaseValue, LoxFunction, Struct}, + lox_result::{LoxResult, parse_error, runtime_error}, types::Type, }, frontend::{ @@ -224,10 +224,31 @@ impl Parser { } fn struct_declaration(&mut self, start_slice: SourceSlice) -> LoxResult { - self.consume(TokenType::Struct, "Expect 'struct' after '::'")?; self.consume(TokenType::LeftBrace, "Expect '{' after 'struct'")?; - - todo!() + let mut fields: Vec<(String, Type)> = vec![]; + while self.peek().token_type != TokenType::RightBrace { + let field_name = self + .consume(TokenType::Identifier, "Expect identifier after '{'")? + .clone(); + self.consume(TokenType::Colon, "Expect ':' after field name")?; + let field_type = self + .consume_type_name("Expect type name after ':'")? + .clone(); + self.consume(TokenType::Comma, "Expect ',' after field type")?; + fields.push((field_name.lexeme, Type::Unresolved(field_type))); + } + let end_slice = self + .consume(TokenType::RightBrace, "Expect '}' after struct fields")? + .source_slice + .clone(); + let source_slice = SourceSlice::from_source_slices(start_slice, end_slice); + Ok(AstNode::new_expression( + Expr::Literal { + value: Box::new(BaseValue::Struct(Box::new(Struct { fields }))), + }, + source_slice, + "Struct".to_string(), + )) } fn function_declaration(&mut self, start_slice: SourceSlice) -> LoxResult { @@ -269,13 +290,13 @@ impl Parser { let body = self.statement()?; Ok(AstNode::new_expression( Expr::Literal { - value: Box::new(BaseValue::Function(LoxFunction { + value: Box::new(BaseValue::Function(Box::new(LoxFunction { parameters, return_type: Type::Unresolved(return_type.clone()), body, closure: None, guard, - })), + }))), }, combine_position.clone(), return_type.clone(), @@ -328,11 +349,7 @@ impl Parser { start_slice.start_position, end_slice.end_position, ); - let label_str = if let Some(label) = label { - label - } else { - String::default() - }; + let label_str = label.unwrap_or_default(); Ok(AstNode::new_statement( Expr::Block { statements: Box::new(statements), @@ -351,7 +368,7 @@ impl Parser { let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice); expr.is_statement = true; expr.source_slice = combined_slice; - return Ok(expr); + Ok(expr) } fn return_statement(&mut self, label: Option) -> LoxResult { @@ -374,11 +391,7 @@ impl Parser { let semicolon = self.consume(TokenType::Semicolon, "Expect ';' after return value.")?; let end_slice = semicolon.source_slice.clone(); let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice); - let label_str = if let Some(label) = label { - label - } else { - String::default() - }; + let label_str = label.unwrap_or_default(); Ok(AstNode::new_statement( Expr::Return { expression: Box::new(expr), @@ -396,7 +409,7 @@ impl Parser { let expr = self.or_and()?; if self.peek().token_type == TokenType::Equal { self.advance(); // consume '=' - // Right-associative: `a = b = c` parses as `a = (b = c)`. + // Right-associative: `a = b = c` parses as `a = (b = c)`. let value = self.assignment()?; let combined_slice = SourceSlice::from_positions( expr.source_slice.source_id, @@ -653,7 +666,7 @@ impl Parser { // Estendi il source_slice per includere le parentesi di chiusura let end_slice = self.previous().source_slice.end_position.clone(); let full_slice = SourceSlice { - source_id: callee.source_slice.source_id.clone(), + source_id: callee.source_slice.source_id, start_position: start_slice.clone(), end_position: end_slice.clone(), }; @@ -779,7 +792,7 @@ impl Parser { fn peek(&self) -> &Token { if self.is_at_end() { - &self.tokens.last().unwrap() + self.tokens.last().unwrap() } else { &self.tokens[self.current] } @@ -787,7 +800,7 @@ impl Parser { fn peek_next(&self) -> &Token { if self.is_at_end() { - &self.peek() + self.peek() } else { &self.tokens[self.current + 1] } @@ -806,7 +819,7 @@ impl Parser { self.advance(); Ok(self.previous()) } else { - return parse_error(self.peek().source_slice.clone(), message); + parse_error(self.peek().source_slice.clone(), message) } } diff --git a/src/frontend/source_registry.rs b/src/frontend/source_registry.rs index 9dc55ef..42c9c3e 100755 --- a/src/frontend/source_registry.rs +++ b/src/frontend/source_registry.rs @@ -4,7 +4,7 @@ use std::{ io::ErrorKind, }; -use crate::common::lox_result::{io_error, LoxResult}; +use crate::common::lox_result::{LoxResult, io_error}; pub struct SourceRegistry { pub sources: Vec, @@ -226,3 +226,9 @@ impl SourceRegistry { line_of_code } } + +impl Default for SourceRegistry { + fn default() -> Self { + Self::new() + } +} diff --git a/src/logging/display_ast.rs b/src/logging/display_ast.rs index 4055696..1b24380 100755 --- a/src/logging/display_ast.rs +++ b/src/logging/display_ast.rs @@ -117,7 +117,7 @@ impl PrettyContext { } fn should_truncate(&self) -> bool { - self.config.max_depth.map_or(false, |max| self.depth >= max) + self.config.max_depth.is_some_and(|max| self.depth >= max) } } diff --git a/src/logging/display_token.rs b/src/logging/display_token.rs index 4910c95..d696f04 100755 --- a/src/logging/display_token.rs +++ b/src/logging/display_token.rs @@ -102,17 +102,17 @@ impl Token { } None => { if config.colored { - format!("{}", self.colored_type()) + self.colored_type().to_string() } else { - format!("{}", self.token_type_symbol()) + self.token_type_symbol().to_string() } } } } else { if config.colored { - format!("{}", self.colored_type()) + self.colored_type().to_string() } else { - format!("{}", self.token_type_symbol()) + self.token_type_symbol().to_string() } } } diff --git a/src/main.rs b/src/main.rs index ff296d4..c601e4d 100755 --- a/src/main.rs +++ b/src/main.rs @@ -33,12 +33,10 @@ fn main() -> LoxResult<()> { println!("running {file_path:?}"); let mut lox = LoxInterpreter::new(debug); - let res = match file_path { + match file_path { Some(path) => lox.run_file(&path, stage), None => lox.run_prompt(stage), - }; - - res + } } fn parse_args(args: &[String]) -> (ExecutionStage, Option, bool) { @@ -140,13 +138,12 @@ impl LoxInterpreter { match self.source_registry.add_source_string(line.to_string()) { Ok(source_id) => { - match self.process_source(source_id, stage, self.debug) { - Ok(result) => match stage { + if let Ok(result) = self.process_source(source_id, stage, self.debug) { + match stage { ExecutionStage::Tokens => println!("Tokens: {}", result), ExecutionStage::Ast => println!("AST: {}", result), ExecutionStage::Full => println!("Result: {}", result), - }, - Err(_) => {} // Errore già stampato in process_source + } } } Err(e) => eprintln!("Error: {}", e), @@ -167,9 +164,8 @@ impl LoxInterpreter { let source_content = self.source_registry.get_by_id(source_id).content.clone(); let mut lexer = Lexer::new(source_content, source_id); - lexer.scans_tokens().or_else(|err| { + lexer.scans_tokens().inspect_err(|err| { err.print_with_context(&self.source_registry); - Err(err) }) } @@ -177,9 +173,8 @@ impl LoxInterpreter { fn parse_to_ast(&self, source_id: SourceId) -> LoxResult> { let tokens = self.tokenize(source_id)?; - Parser::new(tokens).parse().or_else(|err| { + Parser::new(tokens).parse().inspect_err(|err| { err.print_with_context(&self.source_registry); - Err(err) }) } @@ -196,9 +191,8 @@ impl LoxInterpreter { if debug { println!("Executing statement {}: {:?}", index, stmt); } - result = Some(interpreter.evaluate(stmt.clone()).or_else(|err| { + result = Some(interpreter.evaluate(stmt.clone()).inspect_err(|err| { err.print_with_context(&self.source_registry); - Err(err) })?); } @@ -231,9 +225,8 @@ impl LoxInterpreter { let mut lexer = Lexer::new(source_content, source_id); // Stage 1: Tokenization - let tokens = lexer.scans_tokens().or_else(|err| { + let tokens = lexer.scans_tokens().inspect_err(|err| { err.print_with_context(&self.source_registry); - Err(err) })?; // Se debug è attivo, mostra sempre i tokens @@ -247,9 +240,8 @@ impl LoxInterpreter { } // Stage 2: Parsing - let ast = Parser::new(tokens).parse().or_else(|err| { + let ast = Parser::new(tokens).parse().inspect_err(|err| { err.print_with_context(&self.source_registry); - Err(err) })?; // Se debug è attivo, mostra sempre l'AST @@ -272,9 +264,8 @@ impl LoxInterpreter { if debug { println!("Executing statement {}: {:?}", index, stmt); } - result = Some(interpreter.evaluate(stmt.clone()).or_else(|err| { + result = Some(interpreter.evaluate(stmt.clone()).inspect_err(|err| { err.print_with_context(&self.source_registry); - Err(err) })?); } @@ -295,7 +286,7 @@ fn format_tokens(tokens: &[crate::frontend::tokens::Token]) -> String { } fn format_ast(ast: &[AstNode]) -> String { - use crate::logging::display_ast::{pretty_print_with_config, PrettyConfig}; + use crate::logging::display_ast::{PrettyConfig, pretty_print_with_config}; let config = PrettyConfig { indent: " ".to_string(), diff --git a/src/middleend/scope_stack.rs b/src/middleend/scope_stack.rs index c19689a..e72e765 100644 --- a/src/middleend/scope_stack.rs +++ b/src/middleend/scope_stack.rs @@ -52,10 +52,10 @@ impl ScopeStack { /// Update an existing binding in the innermost scope (no-op if absent). pub fn set_local(&mut self, name: &str, state: T) { - if let Some(scope) = self.scopes.last_mut() { - if let Some(slot) = scope.get_mut(name) { - *slot = state; - } + if let Some(scope) = self.scopes.last_mut() + && let Some(slot) = scope.get_mut(name) + { + *slot = state; } } @@ -68,7 +68,7 @@ impl ScopeStack { pub fn declared_in_current(&self, name: &str) -> bool { self.scopes .last() - .map_or(false, |scope| scope.contains_key(name)) + .is_some_and(|scope| scope.contains_key(name)) } /// Distance (in scopes) from the innermost scope to the one declaring