Refactor environment to use stack-based scoping
The commit rewrites the environment to use a stack of hash maps for managing variable scopes. This replaces the old parent-reference approach with a simpler and more efficient stack-based model. Key changes: - Rename Environment to EnvironmentStack - Store scopes in a Vec of HashMaps - Add push/pop scope operations for block handling - Update interpreter to properly manage scope lifetimes - Clean up error handling with helper functions
This commit is contained in:
+11
-51
@@ -1,5 +1,5 @@
|
||||
use crate::frontend::{
|
||||
source_registry::{SourceId, SourcePosition, SourceSlice},
|
||||
source_registry::SourceSlice,
|
||||
tokens::{LiteralValue, TokenType},
|
||||
};
|
||||
use std::fmt::{Debug, Display};
|
||||
@@ -54,34 +54,6 @@ pub enum Expr {
|
||||
},
|
||||
}
|
||||
|
||||
pub trait ExprPrint {
|
||||
fn print(&self) -> String;
|
||||
}
|
||||
|
||||
impl ExprPrint for Expr {
|
||||
fn print(&self) -> String {
|
||||
match self {
|
||||
Expr::Literal { value } => format!("Literal {}", value),
|
||||
Expr::Binary {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => {
|
||||
format!("Binary ({} {} {})", left.node, operator, right.node)
|
||||
}
|
||||
Expr::Unary { operator, operand } => {
|
||||
format!("Unary ({} {})", operator, operand.node)
|
||||
}
|
||||
Expr::Grouping { expression } => {
|
||||
format!("Grouping (group {})", expression.node)
|
||||
}
|
||||
Expr::Variable { name } => {
|
||||
format!("Variable (variable {})", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementazione Display per Expr (per debugging)
|
||||
impl std::fmt::Display for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -294,28 +266,16 @@ impl AstNodeKind for Expr {
|
||||
impl AstNodeKind for Stmt {
|
||||
fn kind(&self) -> &'static str {
|
||||
match self {
|
||||
Stmt::Expression { expression: _ } => "expression",
|
||||
Stmt::Var {
|
||||
name: _,
|
||||
initializer: _,
|
||||
} => "variable declaration",
|
||||
Stmt::Assign { name: _, value: _ } => "assignment",
|
||||
Stmt::Return { expression: _ } => "return statement",
|
||||
Stmt::Block { statements: _ } => "block statement",
|
||||
Stmt::If {
|
||||
condition: _,
|
||||
then_branch: _,
|
||||
elif_branch: _,
|
||||
else_branch: _,
|
||||
} => "if statement",
|
||||
Stmt::Print { expression: _ } => "print statement",
|
||||
Stmt::Stmt { expression: _ } => "statement",
|
||||
Stmt::While { condition, body } => "while statement",
|
||||
Stmt::For {
|
||||
variable,
|
||||
iterable,
|
||||
body,
|
||||
} => "for statement",
|
||||
Stmt::Expression { .. } => "expression",
|
||||
Stmt::Var { .. } => "variable declaration",
|
||||
Stmt::Assign { .. } => "assignment",
|
||||
Stmt::Return { .. } => "return statement",
|
||||
Stmt::Block { .. } => "block statement",
|
||||
Stmt::If { .. } => "if statement",
|
||||
Stmt::Print { .. } => "print statement",
|
||||
Stmt::Stmt { .. } => "statement",
|
||||
Stmt::While { .. } => "while statement",
|
||||
Stmt::For { .. } => "for statement",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ fn get_keyword_token(word: &str) -> Option<TokenType> {
|
||||
"elif" => Some(TokenType::Elif),
|
||||
"else" => Some(TokenType::Else),
|
||||
"or" => Some(TokenType::Or),
|
||||
"in" => Some(TokenType::In),
|
||||
"print" => Some(TokenType::Print),
|
||||
"return" => Some(TokenType::Return),
|
||||
"super" => Some(TokenType::Super),
|
||||
@@ -146,6 +147,7 @@ impl Lexer {
|
||||
('+', _) => Ok(Some(self.make_token(TokenType::Plus))),
|
||||
(';', _) => Ok(Some(self.make_token(TokenType::Semicolon))),
|
||||
('*', _) => Ok(Some(self.make_token(TokenType::Star))),
|
||||
('%', _) => Ok(Some(self.make_token(TokenType::Percent))),
|
||||
('!', '=') => {
|
||||
self.advance(); // consuma il '='
|
||||
Ok(Some(self.make_token(TokenType::BangEqual)))
|
||||
|
||||
+44
-1
@@ -5,7 +5,7 @@ use crate::{
|
||||
tokens::{LiteralValue, Token, TokenType},
|
||||
},
|
||||
logging::display_ast::{pretty_print_with_config, PrettyConfig},
|
||||
result::{LoxError, LoxResult},
|
||||
result::{parse_error, LoxError, LoxResult},
|
||||
};
|
||||
|
||||
pub struct Parser {
|
||||
@@ -65,10 +65,53 @@ impl Parser {
|
||||
(TokenType::Identifier, TokenType::Equal) => self.assignment_statement(),
|
||||
(TokenType::If, _) => self.if_statement(),
|
||||
(TokenType::While, _) => self.while_statement(),
|
||||
(TokenType::For, _) => self.for_statement(),
|
||||
_ => self.expression_statement(),
|
||||
}
|
||||
}
|
||||
|
||||
fn for_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
let start_slice = self.peek().source_slice.clone();
|
||||
self.advance();
|
||||
let variable = if let Token {
|
||||
token_type: TokenType::Identifier,
|
||||
literal: Some(variable_name),
|
||||
source_slice,
|
||||
..
|
||||
} = self.peek()
|
||||
{
|
||||
AstNode {
|
||||
node: Expr::Literal {
|
||||
value: variable_name.clone(),
|
||||
},
|
||||
source_slice: source_slice.clone(),
|
||||
}
|
||||
} else {
|
||||
return parse_error(
|
||||
self.peek().source_slice.clone(),
|
||||
"Expect variable name after 'for' keyword.",
|
||||
);
|
||||
};
|
||||
self.advance();
|
||||
self.consume(TokenType::In, "Expect 'in' after for variable.")?;
|
||||
let iterable = self.expression()?;
|
||||
let body = self.statement()?;
|
||||
let end_slice = body.source_slice.clone();
|
||||
let combined_slice = SourceSlice::from_positions(
|
||||
start_slice.source_id,
|
||||
start_slice.start_position,
|
||||
end_slice.end_position,
|
||||
);
|
||||
Ok(AstNode::new(
|
||||
Stmt::For {
|
||||
variable: Box::new(variable),
|
||||
iterable: Box::new(iterable),
|
||||
body: Box::new(body),
|
||||
},
|
||||
combined_slice,
|
||||
))
|
||||
}
|
||||
|
||||
fn while_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
let start_slice = self.peek().source_slice.clone();
|
||||
self.advance();
|
||||
|
||||
@@ -72,6 +72,7 @@ pub enum TokenType {
|
||||
Else,
|
||||
Nil,
|
||||
Or,
|
||||
In,
|
||||
Print,
|
||||
Return,
|
||||
Super,
|
||||
@@ -132,6 +133,7 @@ impl fmt::Display for TokenType {
|
||||
TokenType::Elif => write!(f, "elif"),
|
||||
TokenType::Val => write!(f, "val"),
|
||||
TokenType::Percent => write!(f, "%"),
|
||||
TokenType::In => write!(f, "in"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user