Move example code to examples directory

The commit moves example and test files to a dedicated examples
directory and updates the code for function and variable handling. The
subject line captures the primary purpose of the move operation.

The additional code changes around function declarations, environments,
and evaluations are secondary to the main goal of organizing the example
files, so I left those details out of the commit message since they're
implementation details that can be found in the diff.
This commit is contained in:
Giulio Agostini
2025-10-06 18:52:32 +02:00
parent 827349cbad
commit fa2e9178fb
16 changed files with 769 additions and 278 deletions
-24
View File
@@ -1,24 +0,0 @@
// var Person :: struct {
// name: String,
// age: Int,
// address: String,
// }
// var func_name :: fn(param, param2) {param is Int} do
do
print "ciao";
1 + 2;
var cavallo = 1 + 2;
cavallo = cavallo + 1;
print cavallo;
cavallo
end
do
var cavallo = 0;
print "cavallo";
while cavallo < 10 do
cavallo = cavallo + 1;
print cavallo;
end
89
end
99
+23
View File
@@ -0,0 +1,23 @@
// var Person :: struct {
// name: String,
// age: Int,
// address: String,
// }
//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;
end
for i := 11; i <= 21; i = i + 1; do
print i;
end
return False or True;
end
func_name(1,2)
+20
View File
@@ -0,0 +1,20 @@
function :: fn() do
print "Function";
end
function_factory :: fn() do
print "Function Factory";
function
end
function_fatcoty_factory :: fn() do
print "Function Factory Factory";
function_factory
end
//function();
//function_factory()();
function_fatcoty_factory()()();
clock()
+26 -3
View File
@@ -5,7 +5,7 @@ use crate::{
result::{runtime_error, LoxResult}, result::{runtime_error, LoxResult},
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq)]
pub struct EnvironmentStack { pub struct EnvironmentStack {
stack: Vec<HashMap<String, LiteralValue>>, stack: Vec<HashMap<String, LiteralValue>>,
} }
@@ -39,7 +39,30 @@ impl EnvironmentStack {
) )
} }
pub fn set(&mut self, name: String, value: LiteralValue) { pub fn declare(&mut self, name: String, value: LiteralValue) -> LoxResult<LiteralValue> {
self.stack.last_mut().unwrap().insert(name, value); self.stack.last_mut().unwrap().insert(name, value.clone());
Ok(value)
}
pub fn set(&mut self, name: String, value: LiteralValue) -> LoxResult<LiteralValue> {
let size = self.stack.len();
for i in (0..size).rev() {
if let Some(_) = self.stack[i].get(&name) {
let mut founded = false;
self.stack[i].entry(name.clone()).and_modify(|v| {
*v = value.clone();
founded = true;
});
if founded {
return Ok(value);
}
}
}
runtime_error(
SourceSlice::default(), // todo change this to the actual source slice
format!("Undefined variable '{}'", name),
)
} }
} }
+152 -47
View File
@@ -3,9 +3,10 @@ use crate::{
frontend::{ frontend::{
ast::{AstNode, AstNodeKind, Expr, Stmt}, ast::{AstNode, AstNodeKind, Expr, Stmt},
source_registry::SourceSlice, source_registry::SourceSlice,
tokens::{LiteralValue, TokenType}, tokens::{LiteralValue, NativeFunction, TokenType},
}, },
result::{LoxError, LoxResult}, logging::display_ast::PrettyPrintExt,
result::{runtime_error, LoxError, LoxResult},
}; };
use std::{ use std::{
fmt::{Debug, Display}, fmt::{Debug, Display},
@@ -174,15 +175,15 @@ pub struct Interpreter {
} }
pub trait EvaluateInterpreter<T> { pub trait EvaluateInterpreter<T> {
fn interpret(&mut self, stmt: T) -> LoxResult<LiteralValue>; fn evaluate(&mut self, stmt: T) -> LoxResult<LiteralValue>;
} }
impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter<AstNode<R>> for Interpreter impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter<AstNode<R>> for Interpreter
where where
Interpreter: EvaluateInterpreter<R>, Interpreter: EvaluateInterpreter<R>,
{ {
fn interpret(&mut self, stmt: AstNode<R>) -> LoxResult<LiteralValue> { fn evaluate(&mut self, stmt: AstNode<R>) -> LoxResult<LiteralValue> {
match self.interpret(stmt.node.clone()) { match self.evaluate(stmt.node.clone()) {
Ok(value) => Ok(value), Ok(value) => Ok(value),
Err(err) => Err(LoxError::RuntimeError { Err(err) => Err(LoxError::RuntimeError {
source_slice: stmt.source_slice, source_slice: stmt.source_slice,
@@ -194,40 +195,109 @@ where
// Direct Expr evaluation to avoid infinite recursion // Direct Expr evaluation to avoid infinite recursion
impl EvaluateInterpreter<Expr> for Interpreter { impl EvaluateInterpreter<Expr> for Interpreter {
fn interpret(&mut self, expr: Expr) -> LoxResult<LiteralValue> { fn evaluate(&mut self, expr: Expr) -> LoxResult<LiteralValue> {
match expr { match expr {
Expr::Literal { value } => Ok(value), Expr::Literal { value } => Ok(value),
Expr::Variable { name } => self.enviorment.get(&name), Expr::Identifier { name } => self.enviorment.get(&name),
Expr::Binary { Expr::Binary {
left, left,
operator, operator,
right, right,
} => { } => {
let left_val = self.interpret(*left)?; let left_val = self.evaluate(*left)?;
let right_val = self.interpret(*right)?; let right_val = self.evaluate(*right)?;
self.evaluate_binary(left_val, operator, right_val) self.evaluate_binary(left_val, operator, right_val)
} }
Expr::Unary { operator, operand } => { Expr::Unary { operator, operand } => {
let operand_val = self.interpret(*operand)?; let operand_val = self.evaluate(*operand)?;
self.evaluate_unary(operator, operand_val) self.evaluate_unary(operator, operand_val)
} }
Expr::Grouping { expression } => self.interpret(*expression), Expr::Grouping { expression } => self.evaluate(*expression),
Expr::Call { callee, arguments } => self.evaluate_call(callee, arguments),
} }
} }
} }
impl EvaluateInterpreter<AstNode<Stmt>> for Interpreter { impl EvaluateInterpreter<AstNode<Stmt>> for Interpreter {
fn interpret(&mut self, node: AstNode<Stmt>) -> LoxResult<LiteralValue> { fn evaluate(&mut self, node: AstNode<Stmt>) -> LoxResult<LiteralValue> {
let stmt = node.node; let stmt = node.node;
let _source_slice = node.source_slice; let result = self.interpret_stmt_inner(stmt);
self.interpret_stmt_inner(stmt) match result {
Ok(value) => Ok(value),
Err(LoxError::RuntimeError {
message,
source_slice,
}) if source_slice == SourceSlice::default() => {
runtime_error(node.source_slice.clone(), message)
}
Err(err) => Err(err),
}
} }
} }
impl Interpreter { impl Interpreter {
pub fn new() -> Self { pub fn new() -> Self {
Self { let mut env = EnvironmentStack::new();
enviorment: EnvironmentStack::new(), let _ = env.declare(
"clock".to_string(),
LiteralValue::NativeFunction(NativeFunction::new(0, |_args| {
LiteralValue::Number(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as f64,
)
})),
);
Self { enviorment: env }
}
fn evaluate_call(
&mut self,
callee: Box<AstNode<Expr>>,
arguments: Vec<AstNode<Expr>>,
) -> LoxResult<LiteralValue> {
let source_slice = callee.source_slice.clone();
// Estrai il nome della variabile se il callee è un identificatore
let function_name = match &callee.node {
Expr::Identifier { name } => Some(name.clone()),
_ => None,
};
let function = if let Some(name) = function_name {
// Se abbiamo un nome di variabile, ottieni la funzione dall'ambiente
self.enviorment.get(&name)?
} else {
// Altrimenti valuta l'espressione callee (per casi più complessi)
self.evaluate(*callee)?
};
if !function.is_callable() {
return runtime_error(source_slice, "Can only call functions");
}
let evaluated_arguments = arguments
.iter()
.map(|arg| self.evaluate(arg.clone()))
.collect::<Result<Vec<LiteralValue>, LoxError>>()?;
match function {
LiteralValue::NativeFunction(func) => Ok((func.function)(&evaluated_arguments)),
LiteralValue::Function(func) => {
func.parameters
.iter()
.enumerate()
.map(|(index, par)| {
let value = evaluated_arguments.get(index).unwrap();
self.enviorment.declare(par.0.clone(), value.clone())
})
.collect::<LoxResult<Vec<LiteralValue>>>()?;
self.evaluate(func.body)
}
_ => runtime_error(
source_slice.clone(),
"This is callable, but apparently is not implemented",
),
} }
} }
@@ -248,6 +318,8 @@ impl Interpreter {
TokenType::LessEqual => Ok(LiteralValue::Boolean(left <= right)), TokenType::LessEqual => Ok(LiteralValue::Boolean(left <= right)),
TokenType::EqualEqual => Ok(LiteralValue::Boolean(left == right)), TokenType::EqualEqual => Ok(LiteralValue::Boolean(left == right)),
TokenType::BangEqual => Ok(LiteralValue::Boolean(left != right)), TokenType::BangEqual => Ok(LiteralValue::Boolean(left != right)),
TokenType::And => Ok(LiteralValue::Boolean(left.is_truthy() && right.is_truthy())),
TokenType::Or => Ok(LiteralValue::Boolean(left.is_truthy() || right.is_truthy())),
_ => Err(error(format!( _ => Err(error(format!(
"Unsupported binary operator: {:?}", "Unsupported binary operator: {:?}",
operator operator
@@ -269,44 +341,86 @@ impl Interpreter {
fn interpret_stmt_inner(&mut self, stmt: Stmt) -> LoxResult<LiteralValue> { fn interpret_stmt_inner(&mut self, stmt: Stmt) -> LoxResult<LiteralValue> {
match stmt { match stmt {
Stmt::Expression { expression } => self.interpret(*expression), Stmt::Expression { expression } => self.evaluate(*expression),
Stmt::Print { expression } => { Stmt::Print { expression } => {
let value = self.interpret(*expression)?; let value = self.evaluate(*expression)?;
println!("print interpreter: \t{}", value); println!("print interpreter: \t{}", value);
Ok(LiteralValue::Nil) Ok(LiteralValue::Nil)
} }
Stmt::Block { statements } => self.evaluate_block(*statements), Stmt::Block { statements } => self.evaluate_block(*statements),
Stmt::Stmt { expression } => self.interpret(*expression.clone()), Stmt::Stmt { expression } => self.evaluate(*expression.clone()),
Stmt::Return { expression } => self.interpret(*expression), Stmt::Return { expression } => self.evaluate(*expression),
Stmt::Var { name, initializer } => { Stmt::VarDeclaration { name, initializer } => {
let value = if let Some(expr) = initializer { let value = match initializer {
self.interpret(*expr)? Some(expr_node) => match &expr_node.node {
Expr::Literal { value } => {
if value.is_callable() {
value.clone()
} else { } else {
LiteralValue::Nil value.clone()
};
self.enviorment.set(name.clone(), value);
return Ok(LiteralValue::Nil);
} }
Stmt::Assign { name, value } => { }
let result = self.interpret(*value)?; _ => self.evaluate(*expr_node)?,
self.enviorment.set(name.clone(), result); },
Ok(LiteralValue::Nil) None => LiteralValue::Nil,
};
self.enviorment.declare(name.clone(), value)
}
Stmt::VarAssigment { name, value } => {
let result = self.evaluate(*value)?;
self.enviorment.set(name.clone(), result)
} }
Stmt::If { Stmt::If {
condition, condition,
then_branch, then_branch,
elif_branch, elif_branch,
else_branch, else_branch,
} => self.evaluate_if(condition, then_branch, elif_branch, else_branch),
Stmt::While { condition, body } => {
while self.evaluate(*condition.clone())?.is_truthy() {
self.evaluate(*body.clone())?;
}
Ok(LiteralValue::Nil)
}
Stmt::For {
variable,
condition,
increment,
body,
} => { } => {
let condition = self.interpret(*condition)?; self.enviorment.push_new_scope();
let source_slice = variable.source_slice.clone();
let val = self.evaluate(*variable)?;
if !matches!(val, LiteralValue::Number(..)) {
return runtime_error(source_slice, "Expected number literal");
}
let mut ret = LiteralValue::Nil;
while self.evaluate(*condition.clone())?.is_truthy() {
ret = self.evaluate(*body.clone())?;
self.evaluate(*increment.clone())?;
}
Ok(ret)
}
}
}
fn evaluate_if(
&mut self,
condition: Box<AstNode<Expr>>,
then_branch: Box<AstNode<Stmt>>,
elif_branch: Vec<(Box<AstNode<Expr>>, Box<AstNode<Stmt>>)>,
else_branch: Option<Box<AstNode<Stmt>>>,
) -> LoxResult<LiteralValue> {
let condition = self.evaluate(*condition)?;
match condition { match condition {
LiteralValue::Boolean(true) => self.interpret(*then_branch), LiteralValue::Boolean(true) => self.evaluate(*then_branch),
LiteralValue::Boolean(false) => { LiteralValue::Boolean(false) => {
for (elif_condition, elif_then_branch) in elif_branch { for (elif_condition, elif_then_branch) in elif_branch {
let condition = self.interpret(*elif_condition)?; let condition = self.evaluate(*elif_condition)?;
match condition { match condition {
LiteralValue::Boolean(true) => { LiteralValue::Boolean(true) => {
return self.interpret(*elif_then_branch); return self.evaluate(*elif_then_branch);
} }
LiteralValue::Boolean(false) => continue, LiteralValue::Boolean(false) => continue,
_ => { _ => {
@@ -319,7 +433,7 @@ impl Interpreter {
}; };
} }
if let Some(else_block) = else_branch { if let Some(else_block) = else_branch {
self.interpret(*else_block) self.evaluate(*else_block)
} else { } else {
Ok(LiteralValue::Nil) Ok(LiteralValue::Nil)
} }
@@ -331,15 +445,6 @@ impl Interpreter {
}), }),
} }
} }
Stmt::While { condition, body } => {
while self.interpret(*condition.clone())?.is_truthy() {
self.interpret(*body.clone())?;
}
Ok(LiteralValue::Nil)
}
Stmt::For { .. } => todo!(),
}
}
fn evaluate_block(&mut self, statements: Vec<AstNode<Stmt>>) -> LoxResult<LiteralValue> { fn evaluate_block(&mut self, statements: Vec<AstNode<Stmt>>) -> LoxResult<LiteralValue> {
self.enviorment.push_new_scope(); self.enviorment.push_new_scope();
@@ -357,13 +462,13 @@ impl Interpreter {
// Ora elements è sempre disponibile // Ora elements è sempre disponibile
for statement in elements.iter() { for statement in elements.iter() {
self.interpret((*statement).clone())?; self.evaluate((*statement).clone())?;
} }
// Gestisci l'espressione finale se presente // Gestisci l'espressione finale se presente
match final_expr { match final_expr {
Some(expr) => { Some(expr) => {
let res = self.interpret(*expr.clone()); let res = self.evaluate(*expr.clone());
self.enviorment.pop_scope(); self.enviorment.pop_scope();
res res
} }
+61 -30
View File
@@ -15,7 +15,9 @@ use std::fmt::{Debug, Display};
* *
* expression_statement -> expression ";" * expression_statement -> expression ";"
* print_statement -> "print" expression ";" * print_statement -> "print" expression ";"
* var_statement -> "var" IDENTIFIER ("=" expression)? ";" * var_statement -> ("var")? IDENTIFIER (":" IDENTIFIER)? (("=" expression)? ";")| function_declaration
* function_declaration -> "::" "(" parameters? ")" ("->" IDENTIFIER)? block_statement
* parameters -> ( IDENTIFIER (":" IDENTIFIER)? ("," IDENTIFIER (":" IDENTIFIER)? )* )
* assignment_statement -> IDENTIFIER "=" expression ";" * assignment_statement -> IDENTIFIER "=" expression ";"
* block_statement -> "do" statement* "end" * block_statement -> "do" statement* "end"
* if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end" * if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end"
@@ -29,10 +31,12 @@ use std::fmt::{Debug, Display};
* comparison -> term ((">" | ">=" | "<" | "<=") term)* * comparison -> term ((">" | ">=" | "<" | "<=") term)*
* term -> factor (("+" | "-") factor)* * term -> factor (("+" | "-") factor)*
* factor -> unary (("*" | "/") unary)* * factor -> unary (("*" | "/") unary)*
* unary -> ("!" | "-") unary | primary * unary -> ("!" | "-") unary | call
* call -> primary ("(" arguments ")")*
* arguments -> expression ("," expression)*
* primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER * primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER
*/ */
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub enum Expr { pub enum Expr {
Literal { Literal {
value: LiteralValue, value: LiteralValue,
@@ -49,9 +53,13 @@ pub enum Expr {
Grouping { Grouping {
expression: Box<AstNode<Expr>>, expression: Box<AstNode<Expr>>,
}, },
Variable { Identifier {
name: String, name: String,
}, },
Call {
callee: Box<AstNode<Expr>>,
arguments: Vec<AstNode<Expr>>,
},
} }
// Implementazione Display per Expr (per debugging) // Implementazione Display per Expr (per debugging)
@@ -66,7 +74,17 @@ impl std::fmt::Display for Expr {
} => write!(f, "Binary ({} {} {})", left.node, operator, right.node), } => write!(f, "Binary ({} {} {})", left.node, operator, right.node),
Expr::Unary { operator, operand } => write!(f, "Unary ({} {})", operator, operand.node), Expr::Unary { operator, operand } => write!(f, "Unary ({} {})", operator, operand.node),
Expr::Grouping { expression } => write!(f, "Grouping (group {})", expression.node), Expr::Grouping { expression } => write!(f, "Grouping (group {})", expression.node),
Expr::Variable { name } => write!(f, "Variable (variable {})", name), Expr::Identifier { name } => write!(f, "Identifier (variable {})", name),
Expr::Call { callee, arguments } => write!(
f,
"Call ({}({}))",
callee.node,
arguments
.iter()
.map(|arg| arg.node.to_string())
.collect::<Vec<String>>()
.join(", ")
),
} }
} }
} }
@@ -82,12 +100,22 @@ impl Debug for Expr {
} => write!(f, "({:?} {:?} {:?})", operator, left.node, right.node), } => write!(f, "({:?} {:?} {:?})", operator, left.node, right.node),
Expr::Unary { operator, operand } => write!(f, "({:?} {:?})", operator, operand.node), Expr::Unary { operator, operand } => write!(f, "({:?} {:?})", operator, operand.node),
Expr::Grouping { expression } => write!(f, "(group {:?})", expression.node), Expr::Grouping { expression } => write!(f, "(group {:?})", expression.node),
Expr::Variable { name } => write!(f, "(variable {:?})", name), Expr::Identifier { name } => write!(f, "(variable {:?})", name),
Expr::Call { callee, arguments } => write!(
f,
"Call ({}({}))",
callee.node,
arguments
.iter()
.map(|arg| arg.node.to_string())
.collect::<Vec<String>>()
.join(", ")
),
} }
} }
} }
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub enum Stmt { pub enum Stmt {
Expression { Expression {
expression: Box<AstNode<Expr>>, expression: Box<AstNode<Expr>>,
@@ -98,11 +126,11 @@ pub enum Stmt {
Stmt { Stmt {
expression: Box<AstNode<Expr>>, expression: Box<AstNode<Expr>>,
}, },
Var { VarDeclaration {
name: String, name: String,
initializer: Option<Box<AstNode<Expr>>>, initializer: Option<Box<AstNode<Expr>>>,
}, },
Assign { VarAssigment {
name: String, name: String,
value: Box<AstNode<Expr>>, value: Box<AstNode<Expr>>,
}, },
@@ -123,8 +151,9 @@ pub enum Stmt {
body: Box<AstNode<Stmt>>, body: Box<AstNode<Stmt>>,
}, },
For { For {
variable: Box<AstNode<Expr>>, variable: Box<AstNode<Stmt>>,
iterable: Box<AstNode<Expr>>, condition: Box<AstNode<Expr>>,
increment: Box<AstNode<Stmt>>,
body: Box<AstNode<Stmt>>, body: Box<AstNode<Stmt>>,
}, },
} }
@@ -153,11 +182,11 @@ impl Display for Stmt {
} }
Stmt::Print { expression } => write!(f, "Print({});", expression.node), Stmt::Print { expression } => write!(f, "Print({});", expression.node),
Stmt::Stmt { expression } => write!(f, "Stmt({});", expression.node), Stmt::Stmt { expression } => write!(f, "Stmt({});", expression.node),
Stmt::Var { name, initializer } => match initializer { Stmt::VarDeclaration { name, initializer } => match initializer {
Some(init) => write!(f, "Var({} = {});", name, init.node), Some(init) => write!(f, "Var({} = {});", name, init.node),
None => write!(f, "Var({});", name), None => write!(f, "Var({});", name),
}, },
Stmt::Assign { name, value } => write!(f, "Assign({} = {});", name, value.node), Stmt::VarAssigment { name, value } => write!(f, "Assign({} = {});", name, value.node),
Stmt::Return { expression } => write!(f, "Return({});", expression.node), Stmt::Return { expression } => write!(f, "Return({});", expression.node),
Stmt::Block { statements } => write!( Stmt::Block { statements } => write!(
f, f,
@@ -173,12 +202,13 @@ impl Display for Stmt {
} }
Stmt::For { Stmt::For {
variable, variable,
iterable, condition,
increment,
body, body,
} => write!( } => write!(
f, f,
"For({} in {}) {{\n{}\n}}", "For({} = {} in {}) {{\n{}\n}}",
variable.node, iterable.node, body.node variable.node, condition.node, increment.node, body.node
), ),
} }
} }
@@ -209,11 +239,13 @@ impl Debug for Stmt {
} }
Stmt::Print { expression } => write!(f, "Print({:?});", expression.node), Stmt::Print { expression } => write!(f, "Print({:?});", expression.node),
Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression.node), Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression.node),
Stmt::Var { name, initializer } => match initializer { Stmt::VarDeclaration { name, initializer } => match initializer {
Some(init) => write!(f, "Var({:?} = {:?});", name, init.node), Some(init) => write!(f, "Var({:?} = {:?});", name, init.node),
None => write!(f, "Var({:?});", name), None => write!(f, "Var({:?});", name),
}, },
Stmt::Assign { name, value } => write!(f, "Assign({:?} = {:?});", name, value.node), Stmt::VarAssigment { name, value } => {
write!(f, "Assign({:?} = {:?});", name, value.node)
}
Stmt::Return { expression } => write!(f, "Return({:?});", expression.node), Stmt::Return { expression } => write!(f, "Return({:?});", expression.node),
Stmt::Block { statements } => write!( Stmt::Block { statements } => write!(
f, f,
@@ -229,12 +261,13 @@ impl Debug for Stmt {
} }
Stmt::For { Stmt::For {
variable, variable,
iterable, condition,
increment,
body, body,
} => write!( } => write!(
f, f,
"For({:?} in {:?}) {{\n{:?}\n}}", "For({:?} = {:?} in {:?}) {{\n{:?}\n}}",
variable.node, iterable.node, body.node variable.node, condition.node, increment.node, body.node
), ),
} }
} }
@@ -253,12 +286,10 @@ impl AstNodeKind for Expr {
operator: _, operator: _,
right: _, right: _,
} => "binary expression", } => "binary expression",
Expr::Unary { Expr::Unary { .. } => "unary expression",
operator: _, Expr::Grouping { .. } => "grouping expression",
operand: _, Expr::Identifier { .. } => "variable expression",
} => "unary expression", Expr::Call { .. } => "call expression",
Expr::Grouping { expression: _ } => "grouping expression",
Expr::Variable { name: _ } => "variable expression",
} }
} }
} }
@@ -267,8 +298,8 @@ impl AstNodeKind for Stmt {
fn kind(&self) -> &'static str { fn kind(&self) -> &'static str {
match self { match self {
Stmt::Expression { .. } => "expression", Stmt::Expression { .. } => "expression",
Stmt::Var { .. } => "variable declaration", Stmt::VarDeclaration { .. } => "variable declaration",
Stmt::Assign { .. } => "assignment", Stmt::VarAssigment { .. } => "assignment",
Stmt::Return { .. } => "return statement", Stmt::Return { .. } => "return statement",
Stmt::Block { .. } => "block statement", Stmt::Block { .. } => "block statement",
Stmt::If { .. } => "if statement", Stmt::If { .. } => "if statement",
@@ -280,7 +311,7 @@ impl AstNodeKind for Stmt {
} }
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq, Default)]
pub struct AstNode<T: AstNodeKind + Debug + Display> { pub struct AstNode<T: AstNodeKind + Debug + Display> {
pub node: T, pub node: T,
pub source_slice: SourceSlice, pub source_slice: SourceSlice,
+3 -1
View File
@@ -38,6 +38,7 @@ fn get_keyword_token(word: &str) -> Option<TokenType> {
"True" => Some(TokenType::True), "True" => Some(TokenType::True),
"False" => Some(TokenType::False), "False" => Some(TokenType::False),
"Nil" => Some(TokenType::Nil), "Nil" => Some(TokenType::Nil),
"fn" => Some(TokenType::Fn),
_ => None, _ => None,
} }
} }
@@ -146,6 +147,7 @@ impl Lexer {
('-', _) => Ok(Some(self.make_token(TokenType::Minus))), ('-', _) => Ok(Some(self.make_token(TokenType::Minus))),
('+', _) => Ok(Some(self.make_token(TokenType::Plus))), ('+', _) => Ok(Some(self.make_token(TokenType::Plus))),
(';', _) => Ok(Some(self.make_token(TokenType::Semicolon))), (';', _) => Ok(Some(self.make_token(TokenType::Semicolon))),
(':', _) => Ok(Some(self.make_token(TokenType::Colon))),
('*', _) => Ok(Some(self.make_token(TokenType::Star))), ('*', _) => Ok(Some(self.make_token(TokenType::Star))),
('%', _) => Ok(Some(self.make_token(TokenType::Percent))), ('%', _) => Ok(Some(self.make_token(TokenType::Percent))),
('!', '=') => { ('!', '=') => {
@@ -262,7 +264,7 @@ impl Lexer {
} }
fn identifier(&mut self) -> LoxResult<Option<Token>> { fn identifier(&mut self) -> LoxResult<Option<Token>> {
while self.peek().is_alphanumeric() { while self.peek().is_alphanumeric() || self.peek() == '_' {
self.advance(); self.advance();
} }
let text = self.input[self.start_char..self.current_char].to_string(); let text = self.input[self.start_char..self.current_char].to_string();
+217 -53
View File
@@ -1,11 +1,11 @@
use crate::{ use crate::{
frontend::{ frontend::{
ast::{AstNode, Expr, Stmt}, ast::{AstNode, Expr, Stmt},
source_registry::SourceSlice, source_registry::{SourcePosition, SourceSlice},
tokens::{LiteralValue, Token, TokenType}, tokens::{LiteralValue, LoxFunction, Token, TokenType},
}, },
logging::display_ast::{pretty_print_with_config, PrettyConfig}, logging::display_ast::{pretty_print_with_config, PrettyConfig},
result::{parse_error, LoxError, LoxResult}, result::{parse_error, runtime_error, LoxResult},
}; };
pub struct Parser { pub struct Parser {
@@ -58,10 +58,14 @@ impl Parser {
fn statement(&mut self) -> LoxResult<AstNode<Stmt>> { fn statement(&mut self) -> LoxResult<AstNode<Stmt>> {
match (&self.peek().token_type, &self.peek_next().token_type) { match (&self.peek().token_type, &self.peek_next().token_type) {
(TokenType::Var, _) => self.var_statement(),
(TokenType::Print, _) => self.print_statement(), (TokenType::Print, _) => self.print_statement(),
(TokenType::Return, _) => self.return_statement(), (TokenType::Return, _) => self.return_statement(),
(TokenType::StartBlock, _) => self.block_statement(), (TokenType::StartBlock, _) => self.block_statement(),
(TokenType::Var, TokenType::Identifier) => {
self.advance();
self.var_statement()
}
(TokenType::Identifier, TokenType::Colon) => self.var_statement(),
(TokenType::Identifier, TokenType::Equal) => self.assignment_statement(), (TokenType::Identifier, TokenType::Equal) => self.assignment_statement(),
(TokenType::If, _) => self.if_statement(), (TokenType::If, _) => self.if_statement(),
(TokenType::While, _) => self.while_statement(), (TokenType::While, _) => self.while_statement(),
@@ -72,46 +76,78 @@ impl Parser {
fn for_statement(&mut self) -> LoxResult<AstNode<Stmt>> { fn for_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
let start_slice = self.peek().source_slice.clone(); let start_slice = self.peek().source_slice.clone();
self.advance(); self.advance(); // consume 'for'
let variable = if let Token {
token_type: TokenType::Identifier, let variable = self.var_statement()?;
literal: Some(variable_name), let condition = self.expression()?;
source_slice, self.consume(TokenType::Semicolon, "Expected ';' after for condition")?;
.. let increment = self.assignment_statement()?;
} = self.peek()
{ self.consume(TokenType::StartBlock, "Expected 'do' after for range")?;
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 body = self.statement()?;
let end_slice = body.source_slice.clone(); self.consume(TokenType::EndBlock, "Expected 'end' after for body")?;
let end_slice = self.previous().source_slice.clone();
let combined_slice = SourceSlice::from_positions( let combined_slice = SourceSlice::from_positions(
start_slice.source_id, start_slice.source_id,
start_slice.start_position, start_slice.start_position,
end_slice.end_position, end_slice.end_position,
); );
Ok(AstNode::new( Ok(AstNode::new(
Stmt::For { Stmt::For {
variable: Box::new(variable), variable: Box::new(variable),
iterable: Box::new(iterable), condition: Box::new(condition),
increment: Box::new(increment),
body: Box::new(body), body: Box::new(body),
}, },
combined_slice, combined_slice,
)) ))
} }
// 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>> { fn while_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
let start_slice = self.peek().source_slice.clone(); let start_slice = self.peek().source_slice.clone();
self.advance(); self.advance();
@@ -178,11 +214,103 @@ impl Parser {
fn var_statement(&mut self) -> LoxResult<AstNode<Stmt>> { fn var_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
let start_slice = self.peek().source_slice.clone(); let start_slice = self.peek().source_slice.clone();
self.advance();
let name = self.consume(TokenType::Identifier, "Expect variable name.")?; let name = self.consume(TokenType::Identifier, "Expect variable name.")?;
let name_lexeme = name.lexeme.clone(); let name_lexeme = name.lexeme.clone();
self.consume(TokenType::Equal, "Expect '=' after variable name.")?;
let value = self.expression()?; let mut _type_annotation = LiteralValue::Nil;
self.consume(TokenType::Colon, "Expect column")?;
match self.peek().token_type {
TokenType::Equal | TokenType::Identifier => {
self.variable_declaration(start_slice, name_lexeme)
}
TokenType::Colon => self.function_declaration(start_slice, name_lexeme),
_ => runtime_error(start_slice, "this is not supposed to be here"),
}
}
fn function_declaration(
&mut self,
start_slice: SourceSlice,
name_lexeme: String,
) -> LoxResult<AstNode<Stmt>> {
self.advance();
self.consume(TokenType::Fn, "Expect 'fn' after '::'")?;
self.consume(TokenType::LeftParen, "Expect '(' after 'fn' ")?;
let mut parameters: Vec<(String, String)> = vec![];
while self.peek().token_type != TokenType::RightParen {
let expr = self
.consume(TokenType::Identifier, "Expect identifier after '('")?
.clone();
if self.peek().token_type == TokenType::Colon {
self.advance();
let type_ =
self.consume(TokenType::Identifier, "Expected identifier after ':' ")?;
parameters.push((expr.lexeme, type_.lexeme.clone()));
} else {
parameters.push((expr.lexeme, "Any".to_string()));
}
if self.peek().token_type == TokenType::Comma {
self.advance();
}
}
self.advance();
let end_position = self.peek().source_slice.clone();
let combine_position = SourceSlice {
source_id: start_slice.source_id,
start_position: start_slice.start_position.clone(),
end_position: end_position.end_position,
};
let mut guard: Option<Box<Expr>> = None;
if self.peek().token_type == TokenType::RightBrace {
self.advance();
guard = Some(Box::new(self.expression()?.node.clone()));
self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?;
}
let body = self.statement()?;
let node = AstNode {
node: Expr::Literal {
value: LiteralValue::Function(LoxFunction {
parameters,
body,
closure: None,
guard,
}),
},
source_slice: combine_position.clone(),
};
Ok(AstNode::new(
Stmt::VarDeclaration {
name: name_lexeme,
initializer: Some(Box::new(node)),
},
combine_position.clone(),
))
}
fn variable_declaration(
&mut self,
start_slice: SourceSlice,
name_lexeme: String,
) -> LoxResult<AstNode<Stmt>> {
if self.peek().token_type == TokenType::Identifier {
self.advance();
if self.peek().token_type == TokenType::Identifier {
self.advance();
}
// todo: make type annotation
}
let mut value = AstNode {
node: Expr::Literal {
value: LiteralValue::Nil,
},
source_slice: start_slice.clone(),
};
if self.peek().token_type == TokenType::Equal {
self.advance();
value = self.expression()?;
}
let semicolon = self.consume( let semicolon = self.consume(
TokenType::Semicolon, TokenType::Semicolon,
"Expect ';' after variable declaration.", "Expect ';' after variable declaration.",
@@ -194,14 +322,13 @@ impl Parser {
end_slice.end_position, end_slice.end_position,
); );
Ok(AstNode::new( Ok(AstNode::new(
Stmt::Var { Stmt::VarDeclaration {
name: name_lexeme, name: name_lexeme,
initializer: Some(Box::new(value)), initializer: Some(Box::new(value)),
}, },
combined_slice, combined_slice,
)) ))
} }
fn assignment_statement(&mut self) -> LoxResult<AstNode<Stmt>> { fn assignment_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
let start_slice = self.peek().source_slice.clone(); let start_slice = self.peek().source_slice.clone();
let name = self.consume(TokenType::Identifier, "Expect variable name.")?; let name = self.consume(TokenType::Identifier, "Expect variable name.")?;
@@ -219,7 +346,7 @@ impl Parser {
end_slice.end_position, end_slice.end_position,
); );
Ok(AstNode::new( Ok(AstNode::new(
Stmt::Assign { Stmt::VarAssigment {
name: name_lexeme, name: name_lexeme,
value: Box::new(value), value: Box::new(value),
}, },
@@ -481,7 +608,56 @@ impl Parser {
)); ));
} }
self.primary() self.call()
}
fn call(&mut self) -> LoxResult<AstNode<Expr>> {
let mut expr = self.primary()?;
loop {
if self.peek().token_type == TokenType::LeftParen {
expr = self.finish_call(expr)?;
} else {
break;
}
}
Ok(expr)
}
fn finish_call(&mut self, callee: AstNode<Expr>) -> LoxResult<AstNode<Expr>> {
let start_slice = callee.source_slice.start_position.clone();
self.advance(); // Consume '('
let mut arguments = Vec::new();
if self.peek().token_type != TokenType::RightParen {
loop {
arguments.push(self.expression()?);
if self.peek().token_type == TokenType::Comma {
self.advance();
} else {
break;
}
}
}
self.consume(TokenType::RightParen, "Expect ')' after arguments.")?;
// 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(),
start_position: start_slice.clone(),
end_position: end_slice.clone(),
};
Ok(AstNode::new(
Expr::Call {
callee: Box::new(callee),
arguments,
},
full_slice,
))
} }
fn primary(&mut self) -> LoxResult<AstNode<Expr>> { fn primary(&mut self) -> LoxResult<AstNode<Expr>> {
@@ -523,9 +699,7 @@ impl Parser {
if let Some(literal) = literal { if let Some(literal) = literal {
Ok(AstNode::new(Expr::Literal { value: literal }, source_slice)) Ok(AstNode::new(Expr::Literal { value: literal }, source_slice))
} else { } else {
Err(self parse_error(self.peek().source_slice.clone(), "Expected number literal")
.error(self.previous(), "Expected number literal")
.into())
} }
} }
TokenType::String => { TokenType::String => {
@@ -535,9 +709,7 @@ impl Parser {
if let Some(literal) = literal { if let Some(literal) = literal {
Ok(AstNode::new(Expr::Literal { value: literal }, source_slice)) Ok(AstNode::new(Expr::Literal { value: literal }, source_slice))
} else { } else {
Err(self parse_error(self.peek().source_slice.clone(), "Expected string literal")
.error(self.previous(), "Expected string literal")
.into())
} }
} }
TokenType::LeftParen => { TokenType::LeftParen => {
@@ -556,9 +728,9 @@ impl Parser {
let name = self.peek().lexeme.clone(); let name = self.peek().lexeme.clone();
let source_slice = self.peek().source_slice.clone(); let source_slice = self.peek().source_slice.clone();
self.advance(); self.advance();
Ok(AstNode::new(Expr::Variable { name }, source_slice)) Ok(AstNode::new(Expr::Identifier { name }, source_slice))
} }
_ => Err(self.error(self.peek(), "Expect expression.").into()), _ => parse_error(self.peek().source_slice.clone(), "Expect expression."),
} }
} }
@@ -606,14 +778,7 @@ impl Parser {
self.advance(); self.advance();
Ok(self.previous()) Ok(self.previous())
} else { } else {
Err(self.error(self.peek(), message).into()) return parse_error(self.peek().source_slice.clone(), message);
}
}
fn error(&self, token: &Token, message: &str) -> LoxError {
LoxError::ParseError {
source_slice: token.source_slice.clone(),
message: message.to_string(),
} }
} }
@@ -628,7 +793,6 @@ impl Parser {
match self.peek().token_type { match self.peek().token_type {
TokenType::Class TokenType::Class
| TokenType::Fun | TokenType::Fun
| TokenType::Var
| TokenType::For | TokenType::For
| TokenType::If | TokenType::If
| TokenType::While | TokenType::While
+45 -1
View File
@@ -1,6 +1,13 @@
use std::fmt; use std::fmt;
use crate::frontend::source_registry::SourceSlice; use crate::{
backend::environment::EnvironmentStack,
frontend::{
ast::{AstNode, Expr, Stmt},
source_registry::SourceSlice,
},
result::{runtime_error, LoxResult},
};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum LiteralValue { pub enum LiteralValue {
@@ -9,6 +16,37 @@ pub enum LiteralValue {
Number(f64), Number(f64),
Boolean(bool), Boolean(bool),
Nil, Nil,
Function(LoxFunction),
NativeFunction(NativeFunction),
}
#[derive(Debug, Clone, PartialEq)]
pub struct LoxFunction {
pub parameters: Vec<(String, String)>,
pub body: AstNode<Stmt>,
pub closure: Option<EnvironmentStack>,
pub guard: Option<Box<Expr>>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct NativeFunction {
pub arity: usize,
pub function: fn(&[LiteralValue]) -> LiteralValue,
}
impl NativeFunction {
pub fn new(arity: usize, function: fn(&[LiteralValue]) -> LiteralValue) -> Self {
NativeFunction { arity, function }
}
}
impl LiteralValue {
pub fn is_callable(&self) -> bool {
match self {
LiteralValue::Function(..) | LiteralValue::NativeFunction(..) => true,
_ => false,
}
}
} }
impl fmt::Display for LiteralValue { impl fmt::Display for LiteralValue {
@@ -19,6 +57,8 @@ impl fmt::Display for LiteralValue {
LiteralValue::Number(n) => write!(f, "{}", n), LiteralValue::Number(n) => write!(f, "{}", n),
LiteralValue::Boolean(b) => write!(f, "{}", b), LiteralValue::Boolean(b) => write!(f, "{}", b),
LiteralValue::Nil => write!(f, "nil"), LiteralValue::Nil => write!(f, "nil"),
LiteralValue::Function(..) => write!(f, "<fn lox function>"),
LiteralValue::NativeFunction(..) => write!(f, "<native native function>"),
} }
} }
} }
@@ -37,6 +77,7 @@ pub enum TokenType {
Minus, Minus,
Plus, Plus,
Semicolon, Semicolon,
Colon,
Slash, Slash,
Star, Star,
Percent, Percent,
@@ -57,6 +98,7 @@ pub enum TokenType {
Number, Number,
// Keywords // Keywords
Fn,
And, And,
Class, Class,
StartBlock, StartBlock,
@@ -134,6 +176,8 @@ impl fmt::Display for TokenType {
TokenType::Val => write!(f, "val"), TokenType::Val => write!(f, "val"),
TokenType::Percent => write!(f, "%"), TokenType::Percent => write!(f, "%"),
TokenType::In => write!(f, "in"), TokenType::In => write!(f, "in"),
TokenType::Colon => write!(f, ":"),
TokenType::Fn => write!(f, "fn"),
} }
} }
} }
+26 -11
View File
@@ -165,7 +165,6 @@ impl PrettyPrint for Expr {
write!(f, "{}Literal {{ value: {:?} }}", indent, value) write!(f, "{}Literal {{ value: {:?} }}", indent, value)
} }
} }
Expr::Binary { Expr::Binary {
left, left,
operator, operator,
@@ -195,7 +194,6 @@ impl PrettyPrint for Expr {
write!(f, "{}}}", indent) write!(f, "{}}}", indent)
} }
} }
Expr::Unary { operator, operand } => { Expr::Unary { operator, operand } => {
if ctx.config.compact { if ctx.config.compact {
let operand_str = let operand_str =
@@ -215,7 +213,6 @@ impl PrettyPrint for Expr {
write!(f, "{}}}", indent) write!(f, "{}}}", indent)
} }
} }
Expr::Grouping { expression } => { Expr::Grouping { expression } => {
if ctx.config.compact { if ctx.config.compact {
let expr_str = let expr_str =
@@ -229,12 +226,27 @@ impl PrettyPrint for Expr {
write!(f, "{}}}", indent) write!(f, "{}}}", indent)
} }
} }
Expr::Identifier { name } => {
Expr::Variable { name } => {
if ctx.config.compact { if ctx.config.compact {
write!(f, "{}", name) write!(f, "{}", name)
} else { } else {
write!(f, "{}Variable {{ name: {:?} }}", indent, name) write!(f, "{}Identifier {{ name: {:?} }}", indent, name)
}
}
Expr::Call { callee, arguments } => {
if ctx.config.compact {
write!(f, "{}", callee)
} else {
write!(f, "{}Call {{ callee: ", indent)?;
callee.pretty_print(&ctx.child_context(true), f)?;
write!(f, ", arguments: [")?;
for (i, arg) in arguments.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
arg.pretty_print(&ctx.child_context(true), f)?;
}
write!(f, "] }}")
} }
} }
} }
@@ -276,7 +288,7 @@ impl PrettyPrint for Stmt {
write!(f, "{}}}", indent) write!(f, "{}}}", indent)
} }
} }
Stmt::Var { name, initializer } => { Stmt::VarDeclaration { name, initializer } => {
if ctx.config.compact { if ctx.config.compact {
match initializer { match initializer {
Some(init) => { Some(init) => {
@@ -302,7 +314,7 @@ impl PrettyPrint for Stmt {
write!(f, "{}}}", indent) write!(f, "{}}}", indent)
} }
} }
Stmt::Assign { name, value } => { Stmt::VarAssigment { name, value } => {
if ctx.config.compact { if ctx.config.compact {
let value_str = let value_str =
pretty_print_with_config(value.as_ref(), &PrettyConfig::compact()); pretty_print_with_config(value.as_ref(), &PrettyConfig::compact());
@@ -412,13 +424,16 @@ impl PrettyPrint for Stmt {
} }
Stmt::For { Stmt::For {
variable, variable,
iterable, condition,
increment,
body, body,
} => { } => {
write!(f, "{}for (", ctx.child_context(true).indent())?; write!(f, "{}for (", ctx.child_context(true).indent())?;
variable.pretty_print(&ctx.child_context(true), f)?; variable.pretty_print(&ctx.child_context(true), f)?;
write!(f, " in ")?; write!(f, "; ")?;
iterable.pretty_print(&ctx.child_context(true), f)?; condition.pretty_print(&ctx.child_context(true), f)?;
write!(f, "; ")?;
increment.pretty_print(&ctx.child_context(true), f)?;
writeln!(f, ") {{")?; writeln!(f, ") {{")?;
body.pretty_print(&ctx.child_context(true), f)?; body.pretty_print(&ctx.child_context(true), f)?;
writeln!(f, "{}}}", ctx.child_context(true).indent()) writeln!(f, "{}}}", ctx.child_context(true).indent())
+4
View File
@@ -196,6 +196,8 @@ impl Token {
TokenType::Val => "VAL", TokenType::Val => "VAL",
TokenType::Eof => "EOF", TokenType::Eof => "EOF",
TokenType::In => "IN", TokenType::In => "IN",
TokenType::Colon => ":",
TokenType::Fn => "FN",
} }
} }
@@ -232,6 +234,7 @@ impl Token {
| TokenType::Super | TokenType::Super
| TokenType::This | TokenType::This
| TokenType::Var | TokenType::Var
| TokenType::Fn
| TokenType::Val => ("\x1b[34m", self.token_type_symbol()), | TokenType::Val => ("\x1b[34m", self.token_type_symbol()),
TokenType::Identifier | TokenType::String | TokenType::Number => { TokenType::Identifier | TokenType::String | TokenType::Number => {
("\x1b[32m", self.token_type_symbol()) ("\x1b[32m", self.token_type_symbol())
@@ -243,6 +246,7 @@ impl Token {
| TokenType::LeftBracket | TokenType::LeftBracket
| TokenType::RightBracket | TokenType::RightBracket
| TokenType::Comma | TokenType::Comma
| TokenType::Colon
| TokenType::Dot | TokenType::Dot
| TokenType::Semicolon => ("\x1b[37m", self.token_type_symbol()), | TokenType::Semicolon => ("\x1b[37m", self.token_type_symbol()),
TokenType::StartBlock | TokenType::EndBlock => ("\x1b[35m", self.token_type_symbol()), TokenType::StartBlock | TokenType::EndBlock => ("\x1b[35m", self.token_type_symbol()),
+167 -55
View File
@@ -1,43 +1,82 @@
mod backend; mod backend;
mod frontend; mod frontend;
mod logging; mod logging;
mod prompt;
mod result; mod result;
use crate::{ use crate::{
backend::{ backend::interpreter::{EvaluateInterpreter, Interpreter},
environment::EnvironmentStack,
interpreter::{EvaluateInterpreter, Interpreter},
},
frontend::{ frontend::{
lexer::Lexer, lexer::Lexer,
parser::Parser, parser::Parser,
source_registry::{SourceId, SourceRegistry, SourceSlice}, source_registry::{SourceId, SourceRegistry},
}, },
prompt::prompt_lines,
result::{LoxError, LoxResult}, result::{LoxError, LoxResult},
}; };
use std::env; use std::env;
use std::fs; use std::fs;
#[derive(Debug, Clone, Copy, PartialEq)]
enum ExecutionStage {
Tokens,
Ast,
Full,
}
fn main() -> LoxResult<()> { fn main() -> LoxResult<()> {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let mut lox = LoxInterpreter::new(); let mut lox = LoxInterpreter::new();
let _ = if args.len() > 2 { let (stage, file_path) = parse_args(&args);
eprintln!("Usage: {} [script]", args[0]);
std::process::exit(64); let _ = match file_path {
} else if args.len() == 2 { Some(path) => lox.run_file(&path, stage),
// Esegui file None => lox.run_prompt(stage),
lox.run_file(&args[1])
} else {
// Modalità interattiva
lox.run_prompt()
}; };
Ok(()) Ok(())
} }
fn parse_args(args: &[String]) -> (ExecutionStage, Option<String>) {
if args.len() == 1 {
// Solo il nome del programma: modalità interattiva completa
(ExecutionStage::Full, None)
} else if args.len() == 2 {
// Un argomento: potrebbe essere file o flag
let arg = &args[1];
if arg == "--tokens" || arg == "--ast" || arg == "--full" {
// Flag senza file: modalità interattiva
let stage = match arg.as_str() {
"--tokens" => ExecutionStage::Tokens,
"--ast" => ExecutionStage::Ast,
"--full" => ExecutionStage::Full,
_ => ExecutionStage::Full,
};
(stage, None)
} else {
// File senza flag: esecuzione completa del file
(ExecutionStage::Full, Some(arg.clone()))
}
} else if args.len() == 3 {
// Due argomenti: flag + file
let flag = &args[1];
let file = &args[2];
let stage = match flag.as_str() {
"--tokens" => ExecutionStage::Tokens,
"--ast" => ExecutionStage::Ast,
"--full" => ExecutionStage::Full,
_ => {
eprintln!("Unknown flag: {}. Use --tokens, --ast, or --full", flag);
eprintln!("Usage: {} [--tokens|--ast|--full] [script]", args[0]);
std::process::exit(64);
}
};
(stage, Some(file.clone()))
} else {
eprintln!("Usage: {} [--tokens|--ast|--full] [script]", args[0]);
std::process::exit(64);
}
}
struct LoxInterpreter { struct LoxInterpreter {
source_registry: SourceRegistry, source_registry: SourceRegistry,
} }
@@ -50,60 +89,133 @@ impl LoxInterpreter {
} }
// ✅ Pipeline funzionale per file // ✅ Pipeline funzionale per file
fn run_file(&mut self, path: &str) -> LoxResult<()> { fn run_file(&mut self, path: &str, stage: ExecutionStage) -> LoxResult<()> {
fs::read_to_string(path) fs::read_to_string(path)
.map_err(|e| LoxError::IoError { .map_err(|e| LoxError::IoError {
message: e.to_string(), message: e.to_string(),
}) })
.and_then(|source| self.source_registry.add_source_string(source)) .and_then(|source| self.source_registry.add_source_string(source))
.and_then(|source_id| self.process_source(source_id)) .and_then(|source_id| self.process_source(source_id, stage))
.map(|result| println!("file {}", result)) .map(|result| match stage {
ExecutionStage::Tokens => println!("=== TOKENS ===\n{}", result),
ExecutionStage::Ast => println!("=== AST ===\n{}", result),
ExecutionStage::Full => println!("=== EXECUTION RESULT ===\n{}", result),
})
} }
// ✅ Pipeline funzionale per prompt // ✅ Pipeline funzionale per prompt
fn run_prompt(&mut self) -> LoxResult<()> { fn run_prompt(&mut self, stage: ExecutionStage) -> LoxResult<()> {
println!("Lox REPL - Type 'exit' to quit"); use std::io::{self, Write};
prompt_lines(|source| self.source_registry.add_source_string(source)) println!("Lox REPL (Stage: {:?}) - Type 'exit' to quit", stage);
.for_each(|line| println!("hi: {}", line));
loop {
print!("> ");
io::stdout().flush().ok();
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => {
let line = input.trim();
if line == "exit" || line.is_empty() {
break;
}
match self.source_registry.add_source_string(line.to_string()) {
Ok(source_id) => {
match self.process_source(source_id, stage) {
Ok(result) => 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),
}
}
Err(e) => {
eprintln!("Error reading input: {}", e);
break;
}
}
}
Ok(()) Ok(())
} }
fn process_source(&self, source_id: SourceId) -> LoxResult<String> { fn process_source(&self, source_id: SourceId, stage: ExecutionStage) -> LoxResult<String> {
let mut lexer = Lexer::new( let source_content = self.source_registry.get_by_id(source_id).content.clone();
self.source_registry.get_by_id(source_id).content.clone(), let mut lexer = Lexer::new(source_content, source_id);
source_id,
); // Stage 1: Tokenization
let res = lexer let tokens = lexer.scans_tokens().or_else(|err| {
.scans_tokens()
.and_then(|tokens| Parser::new(tokens).parse())
.and_then(|asts| {
// println!("asts: {:?}", asts);
Ok(asts)
})
.and_then(|stmts| {
let mut interpreter = Interpreter::new();
let mut result = None;
for (index, stmt) in stmts.iter().enumerate() {
println!("executing stmt {}: {:?}", index, stmt);
result = Some(interpreter.interpret(stmt.clone())?);
}
match result {
Some(res) => Ok(res),
_ => Err(LoxError::RuntimeError {
source_slice: SourceSlice::default(),
message: "what?????".to_string(),
}),
}
})
.and_then(|result| Ok(format!("{}", result)))
.or_else(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err) Err(err)
}); })?;
// println!("result {}", res);
res if stage == ExecutionStage::Tokens {
return Ok(format_tokens(&tokens));
}
// Stage 2: Parsing
let ast = Parser::new(tokens).parse().or_else(|err| {
err.print_with_context(&self.source_registry);
Err(err)
})?;
if stage == ExecutionStage::Ast {
return Ok(format_ast(&ast));
}
// Stage 3: Interpretation
let mut interpreter = Interpreter::new();
let mut result = None;
for (index, stmt) in ast.iter().enumerate() {
println!("Executing statement {}: {:?}", index, stmt);
result = Some(interpreter.evaluate(stmt.clone()).or_else(|err| {
err.print_with_context(&self.source_registry);
Err(err)
})?);
}
match result {
Some(res) => Ok(format!("{}", res)),
None => Ok("No statements executed".to_string()),
} }
} }
}
fn format_tokens(tokens: &[crate::frontend::tokens::Token]) -> String {
tokens
.iter()
.enumerate()
.map(|(i, token)| format!("{:3}: {:?}", i, token))
.collect::<Vec<_>>()
.join("\n")
}
fn format_ast(ast: &[crate::frontend::ast::AstNode<crate::frontend::ast::Stmt>]) -> String {
use crate::logging::display_ast::{pretty_print_with_config, PrettyConfig};
let config = PrettyConfig {
indent: " ".to_string(),
max_depth: None,
show_positions: false,
..Default::default()
};
ast.iter()
.enumerate()
.map(|(i, stmt)| {
format!(
"Statement {}:\n{}",
i,
pretty_print_with_config(&stmt.node, &config)
)
})
.collect::<Vec<_>>()
.join("\n\n")
}
-29
View File
@@ -1,29 +0,0 @@
use std::io::{self, Write};
use crate::{frontend::source_registry::SourceId, result::LoxResult};
pub fn prompt_lines<T>(mut process_source: T) -> impl Iterator<Item = SourceId>
where
T: FnMut(String) -> LoxResult<SourceId>,
{
std::iter::from_fn(move || {
print!("> ");
io::stdout().flush().ok()?;
let mut input = String::new();
io::stdin().read_line(&mut input).ok()?;
let line = input.trim();
if line == "exit" || line.is_empty() {
None
} else {
match process_source(line.to_string()) {
Ok(source_id) => Some(source_id),
Err(err) => {
eprintln!("Error: {}", err);
None
}
}
}
})
}
+2 -1
View File
@@ -402,6 +402,7 @@ impl std::error::Error for LoxError {}
pub type LoxResult<T> = Result<T, LoxError>; pub type LoxResult<T> = Result<T, LoxError>;
/// Helper function to create a lexical error /// Helper function to create a lexical error
#[allow(dead_code)]
pub fn lexical_error<T>(source_slice: SourceSlice, message: impl Into<String>) -> LoxResult<T> { pub fn lexical_error<T>(source_slice: SourceSlice, message: impl Into<String>) -> LoxResult<T> {
Err(LoxError::LexicalError { Err(LoxError::LexicalError {
source_slice, source_slice,
@@ -410,6 +411,7 @@ pub fn lexical_error<T>(source_slice: SourceSlice, message: impl Into<String>) -
} }
/// Helper function to create a parse error /// Helper function to create a parse error
#[allow(dead_code)]
pub fn parse_error<T>(source_slice: SourceSlice, message: impl Into<String>) -> LoxResult<T> { pub fn parse_error<T>(source_slice: SourceSlice, message: impl Into<String>) -> LoxResult<T> {
Err(LoxError::ParseError { Err(LoxError::ParseError {
source_slice, source_slice,
@@ -418,7 +420,6 @@ pub fn parse_error<T>(source_slice: SourceSlice, message: impl Into<String>) ->
} }
/// Helper function to create a runtime error /// Helper function to create a runtime error
#[allow(dead_code)]
pub fn runtime_error<T>(source_slice: SourceSlice, message: impl Into<String>) -> LoxResult<T> { pub fn runtime_error<T>(source_slice: SourceSlice, message: impl Into<String>) -> LoxResult<T> {
Err(LoxError::RuntimeError { Err(LoxError::RuntimeError {
source_slice, source_slice,