Files
rlox/src/backend/interpreter.rs
T

407 lines
14 KiB
Rust
Raw Normal View History

use crate::{
backend::environment::Environment,
frontend::{
ast::{AstNode, AstNodeKind, Expr, Stmt},
source_registry::SourceSlice,
tokens::{LiteralValue, TokenType},
},
result::{LoxError, LoxResult},
};
use std::{
fmt::{format, Debug, Display},
ops::{Add, Div, Mul, Neg, Not, Rem, Sub},
};
fn error(message: String) -> LoxError {
LoxError::RuntimeError {
source_slice: SourceSlice::default(), // todo change this with the actual source slice
message: message,
}
}
2025-10-04 19:02:33 +02:00
fn error_at(source_slice: SourceSlice, message: String) -> LoxError {
LoxError::RuntimeError {
source_slice,
message,
}
}
impl Not for LiteralValue {
type Output = LiteralValue;
fn not(self) -> Self::Output {
match self {
LiteralValue::Boolean(b) => LiteralValue::Boolean(!b),
LiteralValue::Number(n) => LiteralValue::Boolean(n == 0.0),
_ => LiteralValue::Boolean(false),
}
}
}
pub trait Truthy {
fn is_truthy(&self) -> bool;
}
impl Truthy for LiteralValue {
fn is_truthy(&self) -> bool {
match self {
LiteralValue::Boolean(b) => *b,
LiteralValue::Number(n) => *n != 0.0,
LiteralValue::String(s) => !s.is_empty(),
_ => false,
}
}
}
impl Neg for LiteralValue {
type Output = LoxResult<LiteralValue>;
fn neg(self) -> Self::Output {
Ok(LiteralValue::Boolean(!self.is_truthy()))
}
}
impl Add for LiteralValue {
type Output = LoxResult<LiteralValue>;
fn add(self, other: LiteralValue) -> Self::Output {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => Ok(LiteralValue::Number(a + b)),
(LiteralValue::String(a), LiteralValue::String(b)) => {
Ok(LiteralValue::String(format!("{}{}", a, b)))
}
_ => Err(error("Cannot add non-numeric values".to_string())),
}
}
}
2025-10-04 19:02:33 +02:00
impl LiteralValue {
pub fn add_with_source(
self,
other: LiteralValue,
source_slice: SourceSlice,
) -> LoxResult<LiteralValue> {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => Ok(LiteralValue::Number(a + b)),
(LiteralValue::String(a), LiteralValue::String(b)) => {
Ok(LiteralValue::String(format!("{}{}", a, b)))
}
_ => Err(error_at(
source_slice,
"Cannot add non-numeric values".to_string(),
)),
}
}
}
impl Sub for LiteralValue {
type Output = LoxResult<LiteralValue>;
fn sub(self, other: LiteralValue) -> Self::Output {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => Ok(LiteralValue::Number(a - b)),
_ => Err(error("Cannot subtract non-numeric values".to_string())),
}
}
}
impl Div for LiteralValue {
type Output = LoxResult<LiteralValue>;
fn div(self, other: LiteralValue) -> Self::Output {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => {
if b == 0.0 {
Err(error("Division by zero".to_string()))
} else {
Ok(LiteralValue::Number(a / b))
}
}
_ => Err(error("Cannot divide non-numeric values".to_string())),
}
}
}
impl Mul for LiteralValue {
type Output = LoxResult<LiteralValue>;
fn mul(self, other: LiteralValue) -> Self::Output {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => Ok(LiteralValue::Number(a * b)),
_ => Err(error("Cannot multiply non-numeric values".to_string())),
}
}
}
impl Rem for LiteralValue {
type Output = LoxResult<LiteralValue>;
fn rem(self, other: LiteralValue) -> Self::Output {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => {
if b == 0.0 {
Err(error("Division by zero".to_string()))
} else {
Ok(LiteralValue::Number(a % b))
}
}
_ => Err(error("Cannot divide non-numeric values".to_string())),
}
}
}
impl PartialOrd for LiteralValue {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
(LiteralValue::Number(a), LiteralValue::Number(b)) => a.partial_cmp(b),
_ => None,
}
}
}
impl From<LiteralValue> for bool {
fn from(value: LiteralValue) -> Self {
match value {
LiteralValue::Boolean(b) => b,
LiteralValue::Number(n) => n != 0.0,
_ => false,
}
}
}
pub struct Interpreter<'a> {
enviorment: &'a mut Environment<'a>,
}
impl<'a> Interpreter<'a> {
pub fn new(env: &'a mut Environment<'a>) -> Self {
Self { enviorment: env }
}
fn interpret_binary(
&mut self,
2025-10-04 19:02:33 +02:00
left: AstNode<Expr>,
operator: TokenType,
2025-10-04 19:02:33 +02:00
right: AstNode<Expr>,
source_slice: SourceSlice,
) -> LoxResult<LiteralValue> {
let left_value = self.interpret(left)?;
let right_value = self.interpret(right)?;
match operator {
TokenType::Minus => left_value - right_value,
2025-10-04 19:02:33 +02:00
TokenType::Plus => left_value.add_with_source(right_value, source_slice.clone()),
TokenType::Slash => left_value / right_value,
TokenType::Star => left_value * right_value,
TokenType::EqualEqual => Ok(LiteralValue::Boolean(left_value == right_value)),
TokenType::BangEqual => Ok(LiteralValue::Boolean(left_value != right_value)),
TokenType::Greater => Ok(LiteralValue::Boolean(left_value > right_value)),
TokenType::GreaterEqual => Ok(LiteralValue::Boolean(left_value >= right_value)),
TokenType::Less => Ok(LiteralValue::Boolean(left_value < right_value)),
TokenType::LessEqual => Ok(LiteralValue::Boolean(left_value <= right_value)),
TokenType::Percent => left_value % right_value,
TokenType::And => Ok(LiteralValue::Boolean(
left_value.is_truthy() && right_value.is_truthy(),
)),
TokenType::Or => Ok(LiteralValue::Boolean(
left_value.is_truthy() || right_value.is_truthy(),
)),
_ => Err(LoxError::RuntimeError {
source_slice: SourceSlice::default(), // todo change this to the actual source slice
message: format!("Unsupported binary operator {}", operator),
}),
}
}
}
pub trait EvaluateInterpreter<T> {
fn interpret(&mut self, stmt: T) -> LoxResult<LiteralValue>;
}
impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter<AstNode<R>>
for Interpreter<'a>
where
Interpreter<'a>: EvaluateInterpreter<R>,
{
fn interpret(&mut self, stmt: AstNode<R>) -> LoxResult<LiteralValue> {
match self.interpret(stmt.node.clone()) {
Ok(value) => Ok(value),
Err(err) => Err(LoxError::RuntimeError {
source_slice: stmt.source_slice,
message: err.get_message(),
}),
}
}
}
2025-10-04 19:02:33 +02:00
// Direct Expr evaluation to avoid infinite recursion
impl<'a> EvaluateInterpreter<Expr> for Interpreter<'a> {
2025-10-04 19:02:33 +02:00
fn interpret(&mut self, expr: Expr) -> LoxResult<LiteralValue> {
match expr {
Expr::Literal { value } => Ok(value),
Expr::Variable { name } => self.enviorment.get(&name),
Expr::Binary {
left,
operator,
right,
2025-10-04 19:02:33 +02:00
} => {
let left_val = self.interpret(*left)?;
let right_val = self.interpret(*right)?;
self.evaluate_binary(left_val, operator, right_val)
}
Expr::Unary { operator, operand } => {
2025-10-04 19:02:33 +02:00
let operand_val = self.interpret(*operand)?;
self.evaluate_unary(operator, operand_val)
}
Expr::Grouping { expression } => self.interpret(*expression),
}
}
}
2025-10-04 19:02:33 +02:00
impl<'a> EvaluateInterpreter<AstNode<Stmt>> for Interpreter<'a> {
fn interpret(&mut self, node: AstNode<Stmt>) -> LoxResult<LiteralValue> {
let stmt = node.node;
let _source_slice = node.source_slice;
self.interpret_stmt_inner(stmt)
}
}
impl<'a> Interpreter<'a> {
fn evaluate_binary(
&mut self,
left: LiteralValue,
operator: TokenType,
right: LiteralValue,
) -> LoxResult<LiteralValue> {
match operator {
TokenType::Plus => left + right,
TokenType::Minus => left - right,
TokenType::Star => left * right,
TokenType::Slash => left / right,
TokenType::Greater => Ok(LiteralValue::Boolean(left > right)),
TokenType::GreaterEqual => Ok(LiteralValue::Boolean(left >= right)),
TokenType::Less => Ok(LiteralValue::Boolean(left < right)),
TokenType::LessEqual => Ok(LiteralValue::Boolean(left <= right)),
TokenType::EqualEqual => Ok(LiteralValue::Boolean(left == right)),
TokenType::BangEqual => Ok(LiteralValue::Boolean(left != right)),
_ => Err(error(format!(
"Unsupported binary operator: {:?}",
operator
))),
}
}
fn evaluate_unary(
&mut self,
operator: TokenType,
operand: LiteralValue,
) -> LoxResult<LiteralValue> {
match operator {
TokenType::Minus => -operand,
TokenType::Bang => Ok(!operand),
_ => Err(error(format!("Unsupported unary operator: {:?}", operator))),
}
}
fn interpret_stmt_inner(&mut self, stmt: Stmt) -> LoxResult<LiteralValue> {
match stmt {
Stmt::Expression { expression } => self.interpret(*expression),
Stmt::Print { expression } => {
let value = self.interpret(*expression)?;
println!("print interpreter: \t{}", value);
Ok(LiteralValue::Nil)
}
Stmt::Block { statements } => {
let (elements, final_expr) = match statements.split_last() {
2025-10-04 19:02:33 +02:00
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.interpret((*statement).clone())?;
}
// Gestisci l'espressione finale se presente
match final_expr {
2025-10-04 19:02:33 +02:00
Some(expr) => self.interpret(*expr.clone()),
None => Ok(LiteralValue::Nil),
}
}
2025-10-04 19:02:33 +02:00
Stmt::Stmt { expression } => self.interpret(*expression.clone()),
Stmt::Return { expression } => self.interpret(*expression),
Stmt::Var { name, initializer } => {
let value = if let Some(expr) = initializer {
self.interpret(*expr)?
} else {
LiteralValue::Nil
};
self.enviorment.set(name.clone(), value);
return Ok(LiteralValue::Nil);
}
Stmt::Assign { name, value } => {
2025-10-04 19:02:33 +02:00
let result = self.interpret(*value)?;
self.enviorment.set(name.clone(), result);
Ok(LiteralValue::Nil)
}
Stmt::If {
condition,
then_branch,
elif_branch,
else_branch,
} => {
let condition = self.interpret(*condition)?;
match condition {
LiteralValue::Boolean(true) => self.interpret(*then_branch),
LiteralValue::Boolean(false) => {
for (elif_condition, elif_then_branch) in elif_branch {
let condition = self.interpret(*elif_condition)?;
match condition {
LiteralValue::Boolean(true) => {
return self.interpret(*elif_then_branch);
}
LiteralValue::Boolean(false) => continue,
_ => {
return Err(LoxError::TypeMismatch {
source_slice: SourceSlice::default(), // todo change this to the actual source slice
expected: "boolean".to_string(),
found: condition.to_string(),
});
}
};
}
if let Some(else_block) = else_branch {
self.interpret(*else_block)
} else {
Ok(LiteralValue::Nil)
}
}
_ => Err(LoxError::TypeMismatch {
source_slice: SourceSlice::default(), // todo change this to the actual source slice
expected: "boolean".to_string(),
found: condition.to_string(),
}),
}
}
Stmt::While { condition, body } => {
while self.interpret(*condition.clone())?.is_truthy() {
self.interpret(*body.clone())?;
}
Ok(LiteralValue::Nil)
}
Stmt::For {
variable,
iterable,
body,
} => todo!(),
}
}
}