implement chapter 11 in rust
This commit is contained in:
parent
8860a1c639
commit
a25b6d1e92
16 changed files with 470 additions and 32 deletions
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue