This commit is contained in:
2026-02-11 16:35:05 +01:00
parent ee279425f2
commit 4e2645e12d
13 changed files with 229 additions and 176 deletions
View File
+1
View File
@@ -1,4 +1,5 @@
// Test script to verify error positioning
"no"();
var a := 5;
var b := "hello";
print 0;
+12
View File
@@ -0,0 +1,12 @@
closure :: fn() do
value := "Closure";
internal :: fn() do
print value;
return value;
end
return internal;
end
internal := closure();
internal();
+12 -9
View File
@@ -6,23 +6,26 @@
//func_name :: fn(param: Number, param2: String) {param is Int} do
func_name :: fn(param: Int, param2: String) do
print param;
cavallo := 5;
print cavallo;
while cavallo < 10 do
cavallo = cavallo + 1;
print cavallo;
print param2;
while param < param2 do
param = param + 1;
print param;
print param2;
//break;
end
if True then do
if False then do
print "this shoul be stop";
return False;
return "Hahahaha";
end
print "this shoud be un other stop";
return 42;
//return 42;
for i := 11; i <= 21; i = i + 1; do
print i;
print "hello";
break;
end
return False or True;
end
func_name(1,2)
func_name(1,20)
+12 -2
View File
@@ -11,10 +11,20 @@ end
function_fatcoty_factory :: fn() do
print "Function Factory Factory";
function_factory
return function_factory;
end
//function();
//function_factory()();
function_fatcoty_factory()()();
//function_fatcoty_factory()()();
clock()
closure :: fn() do
value = "Closure";
internal :: fn() do
print value;
end
return internal;
end
closure()
+72 -49
View File
@@ -33,7 +33,15 @@ where
impl EvaluateInterpreter<Expr> for Interpreter {
fn evaluate(&mut self, expr: Expr) -> LoxResult<BaseValue> {
match expr {
Expr::Literal { value } => Ok(value),
Expr::Literal { value } => match value {
BaseValue::Function(mut func) => {
func.closure = Some(self.enviorment.clone());
println!("Closure created");
println!("current enviorment: {:?}", self.enviorment);
Ok(BaseValue::Function(func))
}
_ => Ok(value),
},
Expr::Identifier { name } => self.enviorment.get(&name),
Expr::Binary {
left,
@@ -120,15 +128,34 @@ impl Interpreter {
match function {
BaseValue::NativeFunction(func) => Ok((func.function)(&evaluated_arguments)),
BaseValue::Function(func) => {
func.parameters
.iter()
.enumerate()
.map(|(index, par)| {
// Save the current environment
let saved_env = self.enviorment.clone();
// If the function captured a closure, use it as the base environment
if let Some(closure_env) = func.closure {
self.enviorment = closure_env;
}
// Push a new scope for the function's parameters
self.enviorment.push_new_scope();
// Declare parameters in the new scope
for (index, par) in func.parameters.iter().enumerate() {
let value = evaluated_arguments.get(index).unwrap();
self.enviorment.declare(par.0.clone(), value.clone())
})
.collect::<LoxResult<Vec<BaseValue>>>()?;
self.evaluate(func.body)
self.enviorment.declare(par.0.clone(), value.clone())?;
}
// Execute the function body
let result = match self.evaluate(func.body) {
Ok(value) => Ok(value),
Err(LoxError::Return { value, .. }) => Ok(value),
Err(err) => Err(err),
};
// Restore the original environment (cleanup is automatic)
self.enviorment = saved_env;
result
}
_ => runtime_error(
source_slice.clone(),
@@ -194,21 +221,11 @@ impl Interpreter {
name, initializer, ..
} => {
let value = match initializer {
Some(expr_node) => match &expr_node.node {
Expr::Literal { value } => {
if value.is_callable() {
value.clone()
} else {
value.clone()
}
}
_ => self.evaluate(*expr_node)?,
},
Some(expr_node) => self.evaluate(*expr_node)?,
None => BaseValue::Nil,
};
self.enviorment.declare(name.clone(), value)
}
Stmt::VarAssigment { name, value, .. } => {
let result = self.evaluate(*value)?;
self.enviorment.set(name.clone(), result)
@@ -223,10 +240,18 @@ impl Interpreter {
Stmt::While {
condition, body, ..
} => {
let mut ret = BaseValue::Nil;
while self.evaluate(*condition.clone())?.is_truthy() {
self.evaluate(*body.clone())?;
match self.evaluate(*body.clone()) {
Ok(val) => ret = val,
Err(LoxError::Return { value, .. }) => {
ret = value;
break;
}
Ok(BaseValue::Nil)
Err(err) => return Err(err),
};
}
Ok(ret)
}
Stmt::For {
variable,
@@ -235,7 +260,6 @@ impl Interpreter {
body,
..
} => {
self.enviorment.push_new_scope();
let source_slice = variable.source_slice.clone();
let val = self.evaluate(*variable)?;
if !matches!(val, BaseValue::Number(..)) {
@@ -243,7 +267,14 @@ impl Interpreter {
}
let mut ret = BaseValue::Nil;
while self.evaluate(*condition.clone())?.is_truthy() {
ret = self.evaluate(*body.clone())?;
match self.evaluate(*body.clone()) {
Ok(val) => ret = val,
Err(LoxError::Return { value, .. }) => {
ret = value;
break;
}
Err(err) => return Err(err),
};
self.evaluate(*increment.clone())?;
}
@@ -294,34 +325,26 @@ impl Interpreter {
fn evaluate_block(&mut self, statements: Vec<AstNode<Stmt>>) -> LoxResult<BaseValue> {
self.enviorment.push_new_scope();
let (elements, final_expr) = match statements.split_last() {
Some((stmt, body)) => match &stmt.node {
Stmt::Expression { expression, .. } => (body, Some(expression)),
Stmt::Return { expression, .. } => (body, Some(expression)),
_ => (statements.as_slice(), None),
},
None => {
(&[][..], None) // Blocco vuoto
}
};
// Ora elements è sempre disponibile
for statement in elements.iter() {
self.evaluate((*statement).clone())?;
}
let mut result = Ok(BaseValue::Nil);
for statement in statements.iter() {
let node = statement.node.clone();
match node {
Stmt::Return { expression, .. } => {
let value = self.evaluate(*expression)?;
// Gestisci l'espressione finale se presente
match final_expr {
Some(expr) => {
let res = self.evaluate(*expr.clone());
result = Err(LoxError::Return {
source_slice: statement.source_slice.clone(),
value: value,
return_label: "Hi".to_string(),
});
break;
}
_ => result = self.evaluate((*statement).clone()),
};
}
self.enviorment.pop_scope();
res
}
None => {
self.enviorment.pop_scope();
Ok(BaseValue::Nil)
}
}
result
}
}
+13 -2
View File
@@ -138,6 +138,7 @@ pub enum Stmt {
},
Return {
expression: Box<AstNode<Expr>>,
label: String,
return_value: Box<BaseValue>,
},
Block {
@@ -219,7 +220,12 @@ impl Display for Stmt {
Stmt::Return {
expression,
return_value,
} => write!(f, "Return({}) -> {:?};", expression.node, return_value),
label,
} => write!(
f,
"Return({}, {}) -> {:?};",
expression.node, label, return_value
),
Stmt::Block {
statements,
label,
@@ -327,7 +333,12 @@ impl Debug for Stmt {
Stmt::Return {
expression,
return_value,
} => write!(f, "Return({:?}) -> {:?};", expression.node, return_value),
label,
} => write!(
f,
"Return({:?}, {}) -> {:?};",
expression.node, label, return_value
),
Stmt::Block {
label,
statements,
+32
View File
@@ -26,6 +26,11 @@ pub enum LoxError {
expected: String,
found: String,
},
Return {
source_slice: SourceSlice,
value: BaseValue,
return_label: String,
},
}
/// Configuration for error display formatting
@@ -84,6 +89,13 @@ impl LoxError {
} => {
format!("expected {}, found {}", expected, found)
}
LoxError::Return {
value,
return_label,
..
} => {
format!("return value: {} and label: {}", value, return_label)
}
}
}
@@ -94,6 +106,11 @@ impl LoxError {
LoxError::ParseError { source_slice, .. } => Some(source_slice.clone()),
LoxError::IoError { .. } => None,
LoxError::TypeMismatch { source_slice, .. } => Some(source_slice.clone()),
LoxError::Return {
value,
return_label,
..
} => None,
}
}
@@ -104,6 +121,7 @@ impl LoxError {
LoxError::ParseError { .. } => "parse error",
LoxError::IoError { .. } => "io error",
LoxError::TypeMismatch { .. } => "type error",
LoxError::Return { .. } => "return error",
}
}
@@ -396,6 +414,20 @@ impl fmt::Display for LoxError {
found
)
}
LoxError::Return {
value,
return_label,
source_slice,
} => {
write!(
f,
"Return error at {}:{}: value `{}`, label `{}`",
source_slice.start_position.line + 1,
source_slice.start_position.column + 1,
value,
return_label
)
}
}
}
}
+1
View File
@@ -29,6 +29,7 @@ fn get_keyword_token(word: &str) -> Option<TokenType> {
"in" => Some(TokenType::In),
"print" => Some(TokenType::Print),
"return" => Some(TokenType::Return),
"break" => Some(TokenType::Break),
"super" => Some(TokenType::Super),
"this" => Some(TokenType::This),
"true" => Some(TokenType::True),
+51 -21
View File
@@ -2,7 +2,7 @@ use crate::{
common::{
ast::{AstNode, Expr, Stmt},
base_value::{BaseValue, LoxFunction},
lox_result::{parse_error, runtime_error, LoxResult},
lox_result::{parse_error, runtime_error, LoxError, LoxResult},
},
frontend::{
source_registry::SourceSlice,
@@ -24,7 +24,7 @@ impl Parser {
let mut statements = Vec::new();
let mut errors = Vec::new();
while !self.is_at_end() {
match self.statement() {
match self.statement(None) {
Ok(stmt) => {
statements.push(stmt.clone());
}
@@ -42,11 +42,12 @@ impl Parser {
Ok(statements)
}
fn statement(&mut self) -> LoxResult<AstNode<Stmt>> {
fn statement(&mut self, label: Option<String>) -> LoxResult<AstNode<Stmt>> {
match (&self.peek().token_type, &self.peek_next().token_type) {
(TokenType::Print, _) => self.print_statement(),
(TokenType::Return, _) => self.return_statement(),
(TokenType::StartBlock, _) => self.block_statement(),
(TokenType::Return, _) => self.return_statement(label),
(TokenType::Break, _) => self.return_statement(Some("loop".to_string())),
(TokenType::StartBlock, _) => self.block_statement(label),
(TokenType::Var, TokenType::Identifier) => {
self.advance();
self.var_statement()
@@ -68,11 +69,7 @@ impl Parser {
let condition = self.expression()?;
self.consume(TokenType::Semicolon, "Expected ';' after for condition")?;
let increment = self.assignment_statement()?;
self.consume(TokenType::StartBlock, "Expected 'do' after for range")?;
let body = self.statement()?;
self.consume(TokenType::EndBlock, "Expected 'end' after for body")?;
let body = self.statement(Some("loop".to_string()))?;
let end_slice = self.previous().source_slice.clone();
let combined_slice = SourceSlice::from_positions(
@@ -118,7 +115,7 @@ impl Parser {
// self.advance();
// self.consume(TokenType::In, "Expect 'in' after for variable.")?;
// let iterable = self.expression()?;
// let body = self.statement()?;
// let body = self.statement(None)?;
// let end_slice = body.source_slice.clone();
// let combined_slice = SourceSlice::from_positions(
// start_slice.source_id,
@@ -139,7 +136,7 @@ impl Parser {
let start_slice = self.peek().source_slice.clone();
self.advance();
let condition = self.expression()?;
let body = self.statement()?;
let body = self.statement(Some("loop".to_string()))?;
let end_slice = body.source_slice.clone();
let combined_slice = SourceSlice::from_positions(
start_slice.source_id,
@@ -161,7 +158,7 @@ impl Parser {
self.advance(); // consume 'if'
let condition = self.expression()?;
self.consume(TokenType::Then, "Expect 'then' after if condition.")?;
let then_branch = self.statement()?;
let then_branch = self.statement(None)?;
let mut elif_branches = Vec::new();
let mut last_slice = then_branch.source_slice.clone();
@@ -169,14 +166,14 @@ impl Parser {
self.advance(); // consume 'elif'
let elif_condition = self.expression()?;
self.consume(TokenType::Then, "Expect 'then' after elif condition.")?;
let elif_branch = self.statement()?;
let elif_branch = self.statement(None)?;
last_slice = elif_branch.source_slice.clone();
elif_branches.push((Box::new(elif_condition), Box::new(elif_branch)));
}
let else_branch = if self.peek().token_type == TokenType::Else {
self.advance(); // consume 'else'
let else_stmt = self.statement()?;
let else_stmt = self.statement(None)?;
last_slice = else_stmt.source_slice.clone();
Some(Box::new(else_stmt))
} else {
@@ -259,7 +256,7 @@ impl Parser {
self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?;
}
let body = self.statement()?;
let body = self.statement(None)?;
let node = AstNode {
node: Expr::Literal {
value: BaseValue::Function(LoxFunction {
@@ -370,12 +367,13 @@ impl Parser {
))
}
fn block_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
fn block_statement(&mut self, label: Option<String>) -> LoxResult<AstNode<Stmt>> {
let start_slice = self.peek().source_slice.clone();
self.advance();
let mut statements = Vec::new();
while self.peek().token_type != TokenType::EndBlock && !self.is_at_end() {
let stmt = self.statement()?;
let stmt = self.statement(label.clone())?;
let should_break = matches!(stmt.node, Stmt::Expression { .. });
statements.push(stmt);
if should_break {
@@ -389,10 +387,15 @@ impl Parser {
start_slice.start_position,
end_slice.end_position,
);
let label_str = if let Some(label) = label {
label
} else {
String::default()
};
Ok(AstNode::new(
Stmt::Block {
statements: Box::new(statements),
label: String::default(),
label: label_str,
return_value: Box::new(BaseValue::Nil),
},
combined_slice,
@@ -429,10 +432,31 @@ impl Parser {
))
}
fn return_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
fn return_statement(&mut self, label: Option<String>) -> LoxResult<AstNode<Stmt>> {
let start_slice = self.peek().source_slice.clone();
self.advance();
let expr = self.expression()?;
let expr = match self.expression() {
Ok(expr) => expr,
Err(LoxError::ParseError {
message,
source_slice,
}) => {
if message == "Expect expression." {
AstNode {
node: Expr::Literal {
value: BaseValue::Nil,
},
source_slice: start_slice.clone(),
}
} else {
return Err(LoxError::ParseError {
message,
source_slice,
});
}
}
Err(err) => return Err(err),
};
let semicolon = self.consume(TokenType::Semicolon, "Expect ';' after return value.")?;
let end_slice = semicolon.source_slice.clone();
let combined_slice = SourceSlice::from_positions(
@@ -440,10 +464,16 @@ impl Parser {
start_slice.start_position,
end_slice.end_position,
);
let label_str = if let Some(label) = label {
label
} else {
String::default()
};
Ok(AstNode::new(
Stmt::Return {
expression: Box::new(expr),
return_value: Box::new(BaseValue::Nil),
label: label_str,
},
combined_slice,
))
+2
View File
@@ -57,6 +57,7 @@ pub enum TokenType {
Is,
Print,
Return,
Break,
Super,
This,
Var,
@@ -92,6 +93,7 @@ impl fmt::Display for TokenType {
TokenType::Or => write!(f, "or"),
TokenType::Print => write!(f, "print"),
TokenType::Return => write!(f, "return"),
TokenType::Break => write!(f, "break"),
TokenType::Super => write!(f, "super"),
TokenType::This => write!(f, "this"),
TokenType::Var => write!(f, "var"),
+2
View File
@@ -190,6 +190,7 @@ impl Token {
TokenType::Or => "OR",
TokenType::Print => "PRINT",
TokenType::Return => "RETURN",
TokenType::Break => "BREAK",
TokenType::Super => "SUPER",
TokenType::This => "THIS",
TokenType::Var => "VAR",
@@ -232,6 +233,7 @@ impl Token {
| TokenType::Or
| TokenType::Print
| TokenType::Return
| TokenType::Break
| TokenType::Super
| TokenType::This
| TokenType::Var
+13 -87
View File
@@ -30,109 +30,35 @@ fn main() -> LoxResult<()> {
let args: Vec<String> = env::args().collect();
let (stage, file_path, debug) = parse_args(&args);
println!("running {file_path:?}");
let mut lox = LoxInterpreter::new(debug);
let _ = match file_path {
let res = match file_path {
Some(path) => lox.run_file(&path, stage),
None => lox.run_prompt(stage),
};
Ok(())
res
}
fn parse_args(args: &[String]) -> (ExecutionStage, Option<String>, bool) {
if args.len() == 1 {
// Solo il nome del programma: modalità interattiva completa
(ExecutionStage::Full, None, false)
} else if args.len() == 2 {
// Un argomento: potrebbe essere file o flag
let arg = &args[1];
if arg == "--tokens" || arg == "--ast" || arg == "--full" || arg == "--debug" {
// Flag senza file: modalità interattiva
let stage = match arg.as_str() {
"--tokens" => ExecutionStage::Tokens,
"--ast" => ExecutionStage::Ast,
"--full" => ExecutionStage::Full,
"--debug" => ExecutionStage::Full,
_ => ExecutionStage::Full,
};
let debug = arg == "--debug";
(stage, None, debug)
} else {
// File senza flag: esecuzione completa del file
(ExecutionStage::Full, Some(arg.clone()), false)
}
} else if args.len() == 3 {
// Due argomenti: potrebbero essere flag + file o due flag
let mut debug = false;
println!("{args:?}");
let mut stage = ExecutionStage::Full;
let mut file_path = None;
let mut debug = false;
for arg in &args[1..3] {
if arg == "--debug" {
debug = true;
} else if arg == "--tokens" || arg == "--ast" || arg == "--full" {
stage = match arg.as_str() {
"--tokens" => ExecutionStage::Tokens,
"--ast" => ExecutionStage::Ast,
"--full" => ExecutionStage::Full,
_ => ExecutionStage::Full,
};
} else if !arg.starts_with("--") {
file_path = Some(arg.clone());
} else {
eprintln!(
"Unknown flag: {}. Use --tokens, --ast, --full, or --debug",
arg
);
eprintln!(
"Usage: {} [--tokens|--ast|--full] [--debug] [script]",
args[0]
);
std::process::exit(64);
for arg in args.iter().skip(1) {
match arg.as_str() {
"-t" | "--tokens" => stage = ExecutionStage::Tokens,
"-a" | "--ast" => stage = ExecutionStage::Ast,
"-f" | "--full" => stage = ExecutionStage::Full,
"-d" | "--debug" => debug = true,
_ => file_path = Some(arg.clone()),
}
}
(stage, file_path, debug)
} else if args.len() == 4 {
// Tre argomenti: flag + flag + file
let mut debug = false;
let mut stage = ExecutionStage::Full;
let mut file_path = None;
for arg in &args[1..4] {
if arg == "--debug" {
debug = true;
} else if arg == "--tokens" || arg == "--ast" || arg == "--full" {
stage = match arg.as_str() {
"--tokens" => ExecutionStage::Tokens,
"--ast" => ExecutionStage::Ast,
"--full" => ExecutionStage::Full,
_ => ExecutionStage::Full,
};
} else if !arg.starts_with("--") {
file_path = Some(arg.clone());
} else {
eprintln!(
"Unknown flag: {}. Use --tokens, --ast, --full, or --debug",
arg
);
eprintln!(
"Usage: {} [--tokens|--ast|--full] [--debug] [script]",
args[0]
);
std::process::exit(64);
}
}
(stage, file_path, debug)
} else {
eprintln!(
"Usage: {} [--tokens|--ast|--full] [--debug] [script]",
args[0]
);
std::process::exit(64);
}
}
struct LoxInterpreter {