Initialize Rust implementation of Lox interpreter

This initial commit sets up the basic structure for a Rust
implementation of the Lox interpreter, including:

- Lexer for tokenizing source code - Parser for building AST - Basic
interpreter functionality - Environment for variable storage

The core components include source tracking, error handling, and basic
expression evaluation.
This commit is contained in:
Giulio Agostini
2025-10-03 19:07:12 +02:00
commit a7df45dc72
18 changed files with 2710 additions and 0 deletions
+325
View File
@@ -0,0 +1,325 @@
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,
}
}
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())),
}
}
}
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,
left: Expr,
operator: TokenType,
right: Expr,
) -> LoxResult<LiteralValue> {
let left_value = self.interpret(left)?;
let right_value = self.interpret(right)?;
match operator {
TokenType::Minus => left_value - right_value,
TokenType::Plus => left_value + right_value,
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(),
}),
}
}
}
impl<'a> EvaluateInterpreter<Expr> for Interpreter<'a> {
fn interpret(&mut self, stmt: Expr) -> LoxResult<LiteralValue> {
match stmt {
Expr::Literal { value } => Ok(value.clone()),
Expr::Binary {
left,
operator,
right,
} => self.interpret_binary(*left, operator, *right),
Expr::Unary { operator, operand } => {
let right = self.interpret(*operand)?;
match operator {
TokenType::Minus => Ok((-right)?),
TokenType::Bang => Ok(!right),
_ => Err(error("Unsupported unary operator".to_string())),
}
}
Expr::Grouping { expression } => self.interpret(*expression),
Expr::Variable { name } => self.enviorment.get(&name),
}
}
}
impl<'a> EvaluateInterpreter<Stmt> for Interpreter<'a> {
fn interpret(&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() {
Some((Stmt::Expression { expression }, body)) => (body, Some(expression)),
Some((Stmt::Return { expression }, body)) => (body, Some(expression)),
Some((_last_stmt, _body)) => {
(statements.as_slice(), None) // Non è un'Expression finale
}
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 {
Some(expr) => self.interpret((**expr).clone()),
None => Ok(LiteralValue::Nil),
}
}
Stmt::Stmt { expression } => {
let _ = self.interpret(*expression);
Ok(LiteralValue::Nil)
}
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 } => {
let value = self.interpret(*value)?;
self.enviorment.set(name.clone(), value);
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(),
}),
}
}
}
}
}