2025-02-11 11:19:56 +01:00
|
|
|
use thiserror::Error;
|
2025-02-12 10:30:51 +01:00
|
|
|
use tracing::error;
|
2025-02-11 11:19:56 +01:00
|
|
|
|
|
|
|
use crate::{
|
2025-02-12 10:30:51 +01:00
|
|
|
environment::{Environment, EnvironmentError},
|
2025-02-11 11:19:56 +01:00
|
|
|
expression::Expression,
|
2025-02-12 10:30:51 +01:00
|
|
|
statement::Statement,
|
2025-02-11 11:19:56 +01:00
|
|
|
token::{Literal, Token, TokenType},
|
2025-02-11 14:09:52 +01:00
|
|
|
value::Value,
|
2025-02-11 11:19:56 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
pub enum InterpreterError {
|
2025-02-12 10:30:51 +01:00
|
|
|
#[error("[line {0}] MINUS unary expression expects a number on the right")]
|
2025-02-11 11:19:56 +01:00
|
|
|
UnaryExpressionNotANumber(usize),
|
2025-02-12 10:30:51 +01:00
|
|
|
#[error("[line {0}] unknown unary operator: {1}")]
|
2025-02-11 11:19:56 +01:00
|
|
|
UnaryOperatorUnknown(usize, String),
|
2025-02-12 10:30:51 +01:00
|
|
|
#[error("[line {0}] unknown binary operator: {1}")]
|
2025-02-11 11:19:56 +01:00
|
|
|
BinaryOperatorUnknown(usize, String),
|
2025-02-12 10:30:51 +01:00
|
|
|
#[error("[line {0}] left or right is not a number.")]
|
|
|
|
BinaryExpressionNeedsNumber(usize),
|
|
|
|
#[error("[line {0}] left or right is neither a number nor string.")]
|
|
|
|
BinaryExpressionNeedsNumberOrString(usize),
|
|
|
|
#[error("{0}")]
|
|
|
|
UndefinedVariable(EnvironmentError),
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
/// Interpreter for the Lox language.
|
|
|
|
#[derive(Default, Debug)]
|
|
|
|
pub struct Interpreter {
|
|
|
|
environment: Environment,
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
impl Interpreter {
|
|
|
|
/// Try to evaluate an expression and return its result.
|
|
|
|
pub fn run(&mut self, statements: Vec<Statement>) -> Result<(), InterpreterError> {
|
|
|
|
for stmt in statements {
|
|
|
|
match self.execute(stmt) {
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(e) => error!("{e}"),
|
|
|
|
};
|
|
|
|
}
|
2025-02-11 11:19:56 +01:00
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
2025-02-11 11:19:56 +01:00
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
///Execute a statement.
|
|
|
|
fn execute(&mut self, statement: Statement) -> Result<(), InterpreterError> {
|
|
|
|
match statement {
|
|
|
|
Statement::Block(statements) => {
|
|
|
|
let sub_env = Environment::with_enclosing(self.environment.clone());
|
|
|
|
self.block(statements, sub_env)?
|
|
|
|
}
|
|
|
|
Statement::Print(expression) => self.print_statement(expression)?,
|
|
|
|
Statement::Expression(expression) => {
|
|
|
|
self.evaluate(expression)?;
|
|
|
|
}
|
|
|
|
Statement::Var { name, initializer } => self.var_statement(name, *initializer)?,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2025-02-11 11:19:56 +01:00
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
/// Execute all statements within a block, using a new environment (with the old one as the
|
|
|
|
/// enclosing one).
|
|
|
|
fn block(
|
|
|
|
&mut self,
|
|
|
|
statements: Vec<Statement>,
|
|
|
|
environment: Environment,
|
|
|
|
) -> Result<(), InterpreterError> {
|
|
|
|
let prev_env = &self.environment.clone();
|
|
|
|
self.environment = environment;
|
|
|
|
|
|
|
|
for stmt in statements {
|
|
|
|
if let Err(e) = self.execute(stmt) {
|
|
|
|
error!("{e}");
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
}
|
2025-02-12 10:30:51 +01:00
|
|
|
|
|
|
|
self.environment = prev_env.clone();
|
|
|
|
|
|
|
|
Ok(())
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
/// Evaluate an expression and return its value.
|
|
|
|
fn evaluate(&mut self, expression: Expression) -> Result<Value, InterpreterError> {
|
|
|
|
match expression {
|
|
|
|
Expression::Literal { value } => self.literal(value),
|
|
|
|
Expression::Grouping { expression } => self.grouping(*expression),
|
|
|
|
Expression::Unary {
|
|
|
|
operator: op,
|
|
|
|
right,
|
|
|
|
} => self.unary(op, *right),
|
|
|
|
Expression::Binary {
|
|
|
|
left,
|
|
|
|
operator,
|
|
|
|
right,
|
|
|
|
} => self.binary(*left, operator, *right),
|
|
|
|
Expression::Variable { name } => self.var_expression(&name),
|
|
|
|
Expression::Assign { name, value } => self.assign(&name, *value),
|
|
|
|
}
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
/// Evaluate an expression and print its value to stdout.
|
|
|
|
fn print_statement(&mut self, expression: Expression) -> Result<(), InterpreterError> {
|
|
|
|
let value = self.evaluate(expression)?;
|
|
|
|
println!("{value}");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Initialize a variable with an initializer expression or nil.
|
|
|
|
fn var_statement(
|
|
|
|
&mut self,
|
|
|
|
name: Token,
|
|
|
|
initializer: Option<Expression>,
|
|
|
|
) -> Result<(), InterpreterError> {
|
|
|
|
let value = if let Some(initializer) = initializer {
|
|
|
|
self.evaluate(initializer)
|
|
|
|
} else {
|
|
|
|
Ok(Value::Nil)
|
|
|
|
}?;
|
|
|
|
|
|
|
|
self.environment.define(name.lexeme, value);
|
|
|
|
|
|
|
|
Ok(())
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
|
2025-02-12 10:30:51 +01:00
|
|
|
/// Assign the value of an expression to a variable.
|
|
|
|
fn assign(&mut self, name: &Token, value: Expression) -> Result<Value, InterpreterError> {
|
|
|
|
let value = self.evaluate(value)?;
|
|
|
|
|
|
|
|
self.environment
|
|
|
|
.assign(name, value.clone())
|
|
|
|
.map_err(InterpreterError::UndefinedVariable)?;
|
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert the literal value into a Value.
|
|
|
|
fn literal(&self, literal: Literal) -> Result<Value, InterpreterError> {
|
|
|
|
Ok(literal.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Evaluate the inner expression.
|
|
|
|
fn grouping(&mut self, inner: Expression) -> Result<Value, InterpreterError> {
|
|
|
|
self.evaluate(inner)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Evaluate the expression on the right and use its result when evaluating the unary operator.
|
|
|
|
fn unary(&mut self, op: Token, right: Expression) -> Result<Value, InterpreterError> {
|
|
|
|
let right = self.evaluate(right)?;
|
|
|
|
|
|
|
|
match op.token_type {
|
|
|
|
TokenType::Minus => {
|
|
|
|
if let Value::Number(val) = right {
|
|
|
|
Ok(Value::Number(-val))
|
|
|
|
} else {
|
|
|
|
Err(InterpreterError::UnaryExpressionNotANumber(op.line))
|
|
|
|
}
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
2025-02-12 10:30:51 +01:00
|
|
|
TokenType::Bang => Ok(Value::Boolean(!right.is_truthy())),
|
|
|
|
_ => Err(InterpreterError::UnaryOperatorUnknown(op.line, op.lexeme)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the value of a variable.
|
|
|
|
fn var_expression(&mut self, name: &Token) -> Result<Value, InterpreterError> {
|
|
|
|
self.environment
|
|
|
|
.get(name)
|
|
|
|
.map_err(InterpreterError::UndefinedVariable)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Calculate number operations.
|
|
|
|
fn number_op(&self, left: f64, op: TokenType, right: f64) -> f64 {
|
|
|
|
match op {
|
|
|
|
TokenType::Minus => left - right,
|
|
|
|
TokenType::Plus => left + right,
|
|
|
|
TokenType::Slash => left / right,
|
|
|
|
TokenType::Star => left * right,
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Calculate boolean operations.
|
|
|
|
fn boolean_op(&self, left: f64, op: TokenType, right: f64) -> bool {
|
|
|
|
match op {
|
|
|
|
TokenType::Greater => left > right,
|
|
|
|
TokenType::GreaterEqual => left >= right,
|
|
|
|
TokenType::Less => left < right,
|
|
|
|
TokenType::LessEqual => left <= right,
|
|
|
|
_ => unreachable!(),
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
2025-02-12 10:30:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Evaluate the left and right expressions (in that order) and then combine them with the
|
|
|
|
/// specified operator.
|
|
|
|
fn binary(
|
|
|
|
&mut self,
|
|
|
|
left: Expression,
|
|
|
|
op: Token,
|
|
|
|
right: Expression,
|
|
|
|
) -> Result<Value, InterpreterError> {
|
|
|
|
let left = self.evaluate(left)?;
|
|
|
|
let right = self.evaluate(right)?;
|
|
|
|
|
|
|
|
match op.token_type {
|
|
|
|
TokenType::Minus | TokenType::Slash | TokenType::Star | TokenType::Plus => {
|
|
|
|
if let (Value::Number(left), Value::Number(right)) = (left.clone(), right.clone()) {
|
|
|
|
Ok(Value::Number(self.number_op(left, op.token_type, right)))
|
|
|
|
} else if let (Value::String(left), Value::String(right)) = (left, right) {
|
|
|
|
Ok(Value::String(format!("{}{}", left.clone(), right.clone())))
|
|
|
|
} else {
|
|
|
|
Err(InterpreterError::BinaryExpressionNeedsNumberOrString(
|
|
|
|
op.line,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TokenType::Greater
|
|
|
|
| TokenType::GreaterEqual
|
|
|
|
| TokenType::Less
|
|
|
|
| TokenType::LessEqual => {
|
|
|
|
if let (Value::Number(left), Value::Number(right)) = (left, right) {
|
|
|
|
Ok(Value::Boolean(self.boolean_op(left, op.token_type, right)))
|
|
|
|
} else {
|
|
|
|
Err(InterpreterError::BinaryExpressionNeedsNumber(op.line))
|
|
|
|
}
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
2025-02-12 10:30:51 +01:00
|
|
|
TokenType::BangEqual => Ok(Value::Boolean(left != right)),
|
|
|
|
TokenType::EqualEqual => Ok(Value::Boolean(left == right)),
|
|
|
|
_ => Err(InterpreterError::BinaryOperatorUnknown(op.line, op.lexeme)),
|
2025-02-11 11:19:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|