chapter 10 in rust

This commit is contained in:
Sebastian Hugentobler 2025-02-13 12:29:31 +01:00
parent a13db8e29c
commit a98d249399
9 changed files with 401 additions and 35 deletions

View file

@ -4,8 +4,11 @@ use thiserror::Error;
use tracing::error;
use crate::{
callable::CallingError,
environment::{Environment, EnvironmentError},
expression::Expression,
function::Function,
native_functions,
statement::Statement,
token::{Literal, Token, TokenType},
value::Value,
@ -25,14 +28,39 @@ pub enum InterpreterError {
BinaryExpressionNeedsNumberOrString(usize),
#[error("{0}")]
UndefinedVariable(EnvironmentError),
#[error("[line {0}] {1} is not callable.")]
NotACallable(usize, Value),
#[error("[line {0}] {1}.")]
FailedToCall(usize, CallingError),
}
/// Interpreter for the Lox language.
#[derive(Default, Debug)]
#[derive(Debug)]
pub struct Interpreter {
pub globals: Rc<RefCell<Environment>>,
environment: Rc<RefCell<Environment>>,
}
/// Default configuration for the interpreter, with builtin native functions.
impl Default for Interpreter {
fn default() -> Self {
let env: Rc<RefCell<Environment>> = Default::default();
{
// add all native functions to global environment
let mut env = env.borrow_mut();
for (name, fun) in native_functions::all() {
env.define(name, fun);
}
}
Self {
globals: env.clone(),
environment: env.clone(),
}
}
}
impl Interpreter {
/// Try to evaluate an expression and return its result.
pub fn run(&mut self, statements: Vec<Statement>) -> Result<(), InterpreterError> {
@ -47,18 +75,16 @@ impl Interpreter {
}
///Execute a statement.
fn execute(&mut self, statement: &Statement) -> Result<(), InterpreterError> {
fn execute(&mut self, statement: &Statement) -> Result<Option<Value>, 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)?;
self.block(statements, sub_env)
}
Statement::Print(expression) => self.print_statement(expression),
Statement::Expression(expression) => Ok(Some(self.evaluate(expression)?)),
Statement::Var { name, initializer } => {
self.var_statement(name, initializer.as_ref().as_ref())?
self.var_statement(name, initializer.as_ref().as_ref())
}
Statement::If {
condition,
@ -66,33 +92,43 @@ impl Interpreter {
else_branch,
} => {
let else_branch = else_branch.as_ref().map(|x| *x.clone());
self.if_statement(condition, then_branch, else_branch.as_ref())?
self.if_statement(condition, then_branch, else_branch.as_ref())
}
Statement::While { condition, body } => self.while_statement(condition, body)?,
};
Ok(())
Statement::While { condition, body } => self.while_statement(condition, body),
Statement::Function { name, params, body } => {
self.function_statement(name, params, body)
}
Statement::Return { keyword: _, value } => self.return_statement(value),
}
}
/// Execute all statements within a block, using a new environment (with the old one as the
/// enclosing one).
fn block(
/// enclosing one). Immediately return the value if a Return Value is encountered after
/// execution of a statement.
pub fn block(
&mut self,
statements: &Vec<Statement>,
statements: &[Statement],
environment: Environment,
) -> Result<(), InterpreterError> {
) -> Result<Option<Value>, InterpreterError> {
let prev_env = self.environment.clone();
self.environment = Rc::new(RefCell::new(environment));
for stmt in statements {
if let Err(e) = self.execute(stmt) {
error!("{e}");
let execution = self.execute(stmt);
match execution {
Ok(x) => {
if let Some(Value::Return(x)) = x {
self.environment = prev_env.clone();
return Ok(Some(*x));
}
}
Err(e) => error!("{e}"),
}
}
self.environment = prev_env.clone();
Ok(())
Ok(None)
}
/// Evaluate an expression and return its value.
@ -116,31 +152,95 @@ impl Interpreter {
operator,
right,
} => self.logical_expression(left, operator, right),
Expression::Call {
callee,
paren,
args,
} => self.call(callee, paren, args),
}
}
/// Call a callable if it is one (meaning it starts with a LeftParen after an identifier),
/// otherwise evaluate the expression.
fn call(
&mut self,
callee: &Expression,
paren: &Token,
arg_expressions: &[Expression],
) -> Result<Value, InterpreterError> {
let callee = self.evaluate(callee)?;
let mut args = Vec::new();
for arg in arg_expressions {
args.push(self.evaluate(arg)?);
}
if let Value::Callable(f) = callee {
f.call(self, args)
.map_err(|e| InterpreterError::FailedToCall(paren.line, e))
} else {
Err(InterpreterError::NotACallable(paren.line, callee))
}
}
/// Define a new function.
fn function_statement(
&mut self,
name: &Token,
params: &[Token],
body: &[Statement],
) -> Result<Option<Value>, InterpreterError> {
let fn_name = name.lexeme.clone();
let fun = Function {
name: name.clone(),
params: params.to_vec(),
body: body.to_vec(),
closure: self.environment.clone(),
};
self.environment
.borrow_mut()
.define(fn_name, Value::Callable(Rc::new(fun)));
Ok(None)
}
/// If the condition evaluates to truthy, execute the then branch, otherwise the else branch.
fn if_statement(
&mut self,
condition: &Expression,
then_branch: &Statement,
else_branch: Option<&Statement>,
) -> Result<(), InterpreterError> {
) -> Result<Option<Value>, InterpreterError> {
if self.evaluate(condition)?.is_truthy() {
self.execute(then_branch)
} else if let Some(else_branch) = else_branch {
self.execute(else_branch)
} else {
Ok(())
Ok(None)
}
}
/// Evaluate an expression and print its value to stdout.
fn print_statement(&mut self, expression: &Expression) -> Result<(), InterpreterError> {
fn print_statement(
&mut self,
expression: &Expression,
) -> Result<Option<Value>, InterpreterError> {
let value = self.evaluate(expression)?;
println!("{value}");
Ok(())
Ok(None)
}
/// Return a value from a statement.
fn return_statement(
&mut self,
value: &Option<Expression>,
) -> Result<Option<Value>, InterpreterError> {
Ok(match value {
Some(x) => Some(Value::Return(Box::new(self.evaluate(x)?))),
None => Some(Value::Return(Box::new(Value::Nil))),
})
}
/// Initialize a variable with an initializer expression or nil.
@ -148,7 +248,7 @@ impl Interpreter {
&mut self,
name: &Token,
initializer: Option<&Expression>,
) -> Result<(), InterpreterError> {
) -> Result<Option<Value>, InterpreterError> {
let value = if let Some(initializer) = initializer {
self.evaluate(initializer)
} else {
@ -159,7 +259,7 @@ impl Interpreter {
.borrow_mut()
.define(name.lexeme.clone(), value);
Ok(())
Ok(None)
}
/// Execute the body as long as the condition evaluates to true.
@ -167,12 +267,12 @@ impl Interpreter {
&mut self,
condition: &Expression,
body: &Statement,
) -> Result<(), InterpreterError> {
) -> Result<Option<Value>, InterpreterError> {
while self.evaluate(condition)?.is_truthy() {
self.execute(body)?;
}
Ok(())
Ok(None)
}
/// Assign the value of an expression to a variable.