implement chapter 11 in rust

This commit is contained in:
Sebastian Hugentobler 2025-05-25 10:52:20 +02:00
parent 8860a1c639
commit a25b6d1e92
Signed by: shu
SSH key fingerprint: SHA256:ppcx6MlixdNZd5EUM1nkHOKoyQYoJwzuQKXM6J/t66M
16 changed files with 470 additions and 32 deletions

View file

@ -1,5 +1,6 @@
use std::{cell::RefCell, rc::Rc};
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use ordered_float::OrderedFloat;
use thiserror::Error;
use tracing::error;
@ -39,6 +40,7 @@ pub enum InterpreterError {
pub struct Interpreter {
pub globals: Rc<RefCell<Environment>>,
environment: Rc<RefCell<Environment>>,
locals: HashMap<Expression, usize>,
}
/// Default configuration for the interpreter, with builtin native functions.
@ -57,6 +59,7 @@ impl Default for Interpreter {
Self {
globals: env.clone(),
environment: env.clone(),
locals: HashMap::new(),
}
}
}
@ -74,6 +77,10 @@ impl Interpreter {
Ok(())
}
pub fn resolve(&mut self, expression: Expression, depth: usize) {
self.locals.insert(expression, depth);
}
///Execute a statement.
fn execute(&mut self, statement: &Statement) -> Result<Option<Value>, InterpreterError> {
match statement {
@ -145,7 +152,7 @@ impl Interpreter {
operator,
right,
} => self.binary(left, operator, right),
Expression::Variable { name } => self.var_expression(name),
Expression::Variable { name } => self.var_expression(name, expression),
Expression::Assign { name, value } => self.assign(name, value),
Expression::Logical {
left,
@ -276,13 +283,26 @@ impl Interpreter {
}
/// 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)?;
fn assign(&mut self, name: &Token, expression: &Expression) -> Result<Value, InterpreterError> {
let value = self.evaluate(expression)?;
self.environment
.borrow_mut()
.assign(name, value.clone())
.map_err(InterpreterError::UndefinedVariable)?;
if let Some(distance) = self.locals.get(expression) {
self.environment
.borrow_mut()
.assign_at(*distance, name, value.clone())
.map_err(InterpreterError::UndefinedVariable)?;
} else {
self.globals
.borrow_mut()
.assign(name, value.clone())
.map_err(InterpreterError::UndefinedVariable)?;
}
Ok(value)
}
@ -340,11 +360,30 @@ impl Interpreter {
}
/// Get the value of a variable.
fn var_expression(&mut self, name: &Token) -> Result<Value, InterpreterError> {
self.environment
.borrow()
.get(name)
.map_err(InterpreterError::UndefinedVariable)
fn var_expression(
&mut self,
name: &Token,
expression: &Expression,
) -> Result<Value, InterpreterError> {
self.lookup_var(name, expression)
}
fn lookup_var(
&mut self,
name: &Token,
expression: &Expression,
) -> Result<Value, InterpreterError> {
if let Some(distance) = self.locals.get(expression) {
self.environment
.borrow()
.get_at(*distance, name)
.map_err(InterpreterError::UndefinedVariable)
} else {
self.globals
.borrow()
.get(name)
.map_err(InterpreterError::UndefinedVariable)
}
}
/// Calculate number operations.
@ -383,7 +422,11 @@ impl Interpreter {
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)))
Ok(Value::Number(OrderedFloat(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 {
@ -397,7 +440,11 @@ impl Interpreter {
| 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)))
Ok(Value::Boolean(self.boolean_op(
*left,
op.token_type,
*right,
)))
} else {
Err(InterpreterError::BinaryExpressionNeedsNumber(op.line))
}