Files
rlox/src/frontend/ast.rs
T
Giulio Agostini 113a683beb Add while loop support and token pretty printing
The commit adds while loop statements and improves token display
formatting:

- Implements while loop syntax and evaluation - Adds a new token pretty
printing module with configurable formatting - Improves token display
with colors and different output modes
2025-10-03 19:40:25 +02:00

333 lines
10 KiB
Rust

use crate::frontend::{
source_registry::{SourceId, SourcePosition, SourceSlice},
tokens::{LiteralValue, TokenType},
};
use std::fmt::{Debug, Display};
/*
* grammar:
* program -> statement* EOF
* statement -> expression_statement
* | print_statement
* | var_statement
* | block_statement
* | assignment_statement
* | if_statement
*
* expression_statement -> expression ";"
* print_statement -> "print" expression ";"
* var_statement -> "var" IDENTIFIER ("=" expression)? ";"
* assignment_statement -> IDENTIFIER "=" expression ";"
* block_statement -> "do" statement* "end"
* if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end"
* while_statement -> "while" expression "do" statement "end"
*
* expression -> assignment
* assignment -> IDENTIFIER "=" assignment | logical_or
* logical_or -> logical_and (("or" logical_and)*
* logical_and -> equality (("and" equality)*
* equality -> comparison (("==" | "!=") comparison)*
* comparison -> term ((">" | ">=" | "<" | "<=") term)*
* term -> factor (("+" | "-") factor)*
* factor -> unary (("*" | "/") unary)*
* unary -> ("!" | "-") unary | primary
* primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER
*/
#[derive(Clone)]
pub enum Expr {
Literal {
value: LiteralValue,
},
Binary {
left: Box<Expr>,
operator: TokenType,
right: Box<Expr>,
},
Unary {
operator: TokenType,
operand: Box<Expr>,
},
Grouping {
expression: Box<Expr>,
},
Variable {
name: String,
},
}
pub trait ExprPrint {
fn print(&self) -> String;
}
impl ExprPrint for Expr {
fn print(&self) -> String {
match self {
Expr::Literal { value } => format!("Literal {}", value),
Expr::Binary {
left,
operator,
right,
} => {
format!("Binary ({} {} {})", left, operator, right)
}
Expr::Unary { operator, operand } => {
format!("Unary ({} {})", operator, operand)
}
Expr::Grouping { expression } => {
format!("Grouping (group {})", expression)
}
Expr::Variable { name } => {
format!("Variable (variable {})", name)
}
}
}
}
// Implementazione Display per Expr (per debugging)
impl std::fmt::Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Literal { value } => write!(f, "Literal {}", value),
Expr::Binary {
left,
operator,
right,
} => write!(f, "Binary ({} {} {})", left, operator, right),
Expr::Unary { operator, operand } => write!(f, "Unary ({} {})", operator, operand),
Expr::Grouping { expression } => write!(f, "Grouping (group {})", expression),
Expr::Variable { name } => write!(f, "Variable (variable {})", name),
}
}
}
impl Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Literal { value } => write!(f, "{:?}", value),
Expr::Binary {
left,
operator,
right,
} => write!(f, "({:?} {:?} {:?})", operator, left, right),
Expr::Unary { operator, operand } => write!(f, "({:?} {:?})", operator, operand),
Expr::Grouping { expression } => write!(f, "(group {:?})", expression),
Expr::Variable { name } => write!(f, "(variable {:?})", name),
}
}
}
#[derive(Clone)]
pub enum Stmt {
Expression {
expression: Box<Expr>,
},
Print {
expression: Box<Expr>,
},
Stmt {
expression: Box<Expr>,
},
Var {
name: String,
initializer: Option<Box<Expr>>,
},
Assign {
name: String,
value: Box<Expr>,
},
Return {
expression: Box<Expr>,
},
Block {
statements: Box<Vec<Stmt>>,
},
If {
condition: Box<Expr>,
then_branch: Box<Stmt>,
elif_branch: Vec<(Box<Expr>, Box<Stmt>)>,
else_branch: Option<Box<Stmt>>,
},
While {
condition: Box<Expr>,
body: Box<Stmt>,
},
For {
variable: Box<Expr>,
iterable: Box<Expr>,
body: Box<Stmt>,
},
}
impl Display for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Stmt::Expression { expression } => write!(f, "Expression ({})", expression),
Stmt::If {
condition,
then_branch,
elif_branch,
else_branch,
} => {
let mut result = format!("IF ({}) {{\n{}\n}}", condition, then_branch);
for (condition, branch) in elif_branch {
result.push_str(&format!(" ELIF ({}) {{\n{}\n}}", condition, branch));
}
if let Some(else_branch) = else_branch {
result.push_str(&format!(" ELSE {{\n{}\n}}", else_branch));
}
write!(f, "IfStmt {}", result)
}
Stmt::Print { expression } => write!(f, "Print({});", expression),
Stmt::Stmt { expression } => write!(f, "Stmt({});", expression),
Stmt::Var { name, initializer } => {
write!(f, "Var({} = {:?});", name, initializer)
}
Stmt::Assign { name, value } => write!(f, "Assign({} = {});", name, value),
Stmt::Return { expression } => write!(f, "Return({});", expression),
Stmt::Block { statements } => write!(
f,
"Block([\n{}\n])",
statements
.iter()
.map(|stmt| format!("\t \t{}", stmt))
.collect::<Vec<_>>()
.join("\n")
),
Stmt::While { condition, body } => todo!(),
Stmt::For {
variable,
iterable,
body,
} => todo!(),
}
}
}
impl Debug for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Stmt::Expression { expression } => write!(f, " Expression ({:?})", expression),
Stmt::If {
condition,
then_branch,
elif_branch,
else_branch,
} => {
let mut result = format!("IF ({:?}) {{\n{:?}\n}}", condition, then_branch);
for (condition, branch) in elif_branch {
result.push_str(&format!(" ELIF ({:?}) {{\n{:?}\n}}", condition, branch));
}
if let Some(else_branch) = else_branch {
result.push_str(&format!(" ELSE {{\n{:?}\n}}", else_branch));
}
write!(f, "IfStmt {:?}", result)
}
Stmt::Print { expression } => write!(f, "Print({:?});", expression),
Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression),
Stmt::Var { name, initializer } => {
write!(f, "Var({:?} = {:?});", name, initializer)
}
Stmt::Assign { name, value } => write!(f, "Assign({:?} = {:?});", name, value),
Stmt::Return { expression } => write!(f, "Return({:?});", expression),
Stmt::Block { statements } => write!(
f,
"Block([\n{:?}\n])",
statements
.iter()
.map(|stmt| format!("{:?}", stmt))
.collect::<Vec<_>>()
.join("\t\t\n")
),
Stmt::While { condition, body } => todo!(),
Stmt::For {
variable,
iterable,
body,
} => todo!(),
}
}
}
pub trait AstNodeKind {
fn kind(&self) -> &'static str;
}
impl AstNodeKind for Expr {
fn kind(&self) -> &'static str {
match self {
Expr::Literal { value: _ } => "literal",
Expr::Binary {
left: _,
operator: _,
right: _,
} => "binary expression",
Expr::Unary {
operator: _,
operand: _,
} => "unary expression",
Expr::Grouping { expression: _ } => "grouping expression",
Expr::Variable { name: _ } => "variable expression",
}
}
}
impl AstNodeKind for Stmt {
fn kind(&self) -> &'static str {
match self {
Stmt::Expression { expression: _ } => "expression",
Stmt::Var {
name: _,
initializer: _,
} => "variable declaration",
Stmt::Assign { name: _, value: _ } => "assignment",
Stmt::Return { expression: _ } => "return statement",
Stmt::Block { statements: _ } => "block statement",
Stmt::If {
condition: _,
then_branch: _,
elif_branch: _,
else_branch: _,
} => "if statement",
Stmt::Print { expression: _ } => "print statement",
Stmt::Stmt { expression: _ } => "statement",
Stmt::While { condition, body } => todo!(),
Stmt::For {
variable,
iterable,
body,
} => todo!(),
}
}
}
#[derive(Clone, PartialEq)]
pub struct AstNode<T: AstNodeKind + Debug + Display> {
pub node: T,
pub source_slice: SourceSlice,
}
impl<T: AstNodeKind + Debug + Display> Display for AstNode<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"AstNode \n{{ \n\tnode: {},\n\tsource_slice: {}, \n}}",
self.node, self.source_slice
)
}
}
impl<T: AstNodeKind + Debug + Display> Debug for AstNode<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"AstNode \n{{ \n\tnode: {:?},\n\tsource_slice: {:?}, \n}}",
self.node, self.source_slice
)
}
}
impl<T: AstNodeKind + Debug + Display> AstNode<T> {
pub fn new(node: T, source_slice: SourceSlice) -> Self {
AstNode { node, source_slice }
}
}