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.
326 lines
11 KiB
Rust
326 lines
11 KiB
Rust
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(),
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|