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:
@@ -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(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user