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