chapter 9 in rust

This commit is contained in:
Sebastian Hugentobler 2025-02-12 13:10:07 +01:00
parent 1a485ebcb1
commit f82919414e
5 changed files with 271 additions and 35 deletions

View File

@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use thiserror::Error;
@ -15,14 +15,15 @@ pub enum EnvironmentError {
#[derive(Default, Debug, Clone)]
pub struct Environment {
values: HashMap<String, Value>,
enclosing: Option<Box<Environment>>,
enclosing: Option<Rc<RefCell<Environment>>>,
}
impl Environment {
pub fn with_enclosing(enclosing: Environment) -> Self {
/// Initialize a new environment with an enclosing one.
pub fn with_enclosing(enclosing: Rc<RefCell<Environment>>) -> Self {
Self {
values: HashMap::default(),
enclosing: Some(Box::new(enclosing)),
enclosing: Some(enclosing),
}
}
@ -40,7 +41,7 @@ impl Environment {
self.values.insert(token.lexeme.clone(), value);
Ok(())
} else if let Some(enclosing) = &mut self.enclosing {
enclosing.assign(token, value)
enclosing.borrow_mut().assign(token, value)
} else {
Err(EnvironmentError::UndefinedVariable(
token.line,
@ -55,7 +56,7 @@ impl Environment {
if let Some(v) = self.values.get(token.lexeme.as_str()) {
Ok(v.clone())
} else if let Some(enclosing) = &self.enclosing {
enclosing.get(token)
enclosing.borrow().get(token)
} else {
Err(EnvironmentError::UndefinedVariable(
token.line,

View File

@ -18,6 +18,11 @@ pub enum Expression {
Literal {
value: token::Literal,
},
Logical {
left: Box<Expression>,
operator: Token,
right: Box<Expression>,
},
Unary {
operator: Token,
right: Box<Expression>,

View File

@ -1,3 +1,5 @@
use std::{cell::RefCell, rc::Rc};
use thiserror::Error;
use tracing::error;
@ -28,14 +30,14 @@ pub enum InterpreterError {
/// Interpreter for the Lox language.
#[derive(Default, Debug)]
pub struct Interpreter {
environment: Environment,
environment: Rc<RefCell<Environment>>,
}
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) {
match self.execute(&stmt) {
Ok(_) => {}
Err(e) => error!("{e}"),
};
@ -45,7 +47,7 @@ impl Interpreter {
}
///Execute a statement.
fn execute(&mut self, statement: Statement) -> Result<(), InterpreterError> {
fn execute(&mut self, statement: &Statement) -> Result<(), InterpreterError> {
match statement {
Statement::Block(statements) => {
let sub_env = Environment::with_enclosing(self.environment.clone());
@ -55,7 +57,18 @@ impl Interpreter {
Statement::Expression(expression) => {
self.evaluate(expression)?;
}
Statement::Var { name, initializer } => self.var_statement(name, *initializer)?,
Statement::Var { name, initializer } => {
self.var_statement(name, initializer.as_ref().as_ref())?
}
Statement::If {
condition,
then_branch,
else_branch,
} => {
let else_branch = else_branch.as_ref().map(|x| *x.clone());
self.if_statement(condition, then_branch, else_branch.as_ref())?
}
Statement::While { condition, body } => self.while_statement(condition, body)?,
};
Ok(())
@ -65,11 +78,11 @@ impl Interpreter {
/// enclosing one).
fn block(
&mut self,
statements: Vec<Statement>,
statements: &Vec<Statement>,
environment: Environment,
) -> Result<(), InterpreterError> {
let prev_env = &self.environment.clone();
self.environment = environment;
let prev_env = self.environment.clone();
self.environment = Rc::new(RefCell::new(environment));
for stmt in statements {
if let Err(e) = self.execute(stmt) {
@ -83,26 +96,47 @@ impl Interpreter {
}
/// Evaluate an expression and return its value.
fn evaluate(&mut self, expression: Expression) -> Result<Value, InterpreterError> {
fn evaluate(&mut self, expression: &Expression) -> Result<Value, InterpreterError> {
match expression {
Expression::Literal { value } => self.literal(value),
Expression::Grouping { expression } => self.grouping(*expression),
Expression::Literal { value } => self.literal(value.clone()),
Expression::Grouping { expression } => self.grouping(expression),
Expression::Unary {
operator: op,
right,
} => self.unary(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),
} => self.binary(left, operator, right),
Expression::Variable { name } => self.var_expression(name),
Expression::Assign { name, value } => self.assign(name, value),
Expression::Logical {
left,
operator,
right,
} => self.logical_expression(left, operator, right),
}
}
/// 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> {
if self.evaluate(condition)?.is_truthy() {
self.execute(then_branch)
} else if let Some(else_branch) = else_branch {
self.execute(else_branch)
} else {
Ok(())
}
}
/// 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<(), InterpreterError> {
let value = self.evaluate(expression)?;
println!("{value}");
@ -112,8 +146,8 @@ impl Interpreter {
/// Initialize a variable with an initializer expression or nil.
fn var_statement(
&mut self,
name: Token,
initializer: Option<Expression>,
name: &Token,
initializer: Option<&Expression>,
) -> Result<(), InterpreterError> {
let value = if let Some(initializer) = initializer {
self.evaluate(initializer)
@ -121,16 +155,32 @@ impl Interpreter {
Ok(Value::Nil)
}?;
self.environment.define(name.lexeme, value);
self.environment
.borrow_mut()
.define(name.lexeme.clone(), value);
Ok(())
}
/// Execute the body as long as the condition evaluates to true.
fn while_statement(
&mut self,
condition: &Expression,
body: &Statement,
) -> Result<(), InterpreterError> {
while self.evaluate(condition)?.is_truthy() {
self.execute(body)?;
}
Ok(())
}
/// Assign the value of an expression to a variable.
fn assign(&mut self, name: &Token, value: Expression) -> Result<Value, InterpreterError> {
fn assign(&mut self, name: &Token, value: &Expression) -> Result<Value, InterpreterError> {
let value = self.evaluate(value)?;
self.environment
.borrow_mut()
.assign(name, value.clone())
.map_err(InterpreterError::UndefinedVariable)?;
Ok(value)
@ -141,13 +191,36 @@ impl Interpreter {
Ok(literal.into())
}
/// Evaluate left and if the operator is Or and left is truthy or the operator is not Or and
/// not leftis truthy short circuit and return left. Otherwise evaluate and return right.
fn logical_expression(
&mut self,
left: &Expression,
operator: &Token,
right: &Expression,
) -> Result<Value, InterpreterError> {
let left = self.evaluate(left)?;
let truthy = if operator.token_type == TokenType::Or {
left.is_truthy()
} else {
!left.is_truthy()
};
if truthy {
Ok(left)
} else {
self.evaluate(right)
}
}
/// Evaluate the inner expression.
fn grouping(&mut self, inner: Expression) -> Result<Value, InterpreterError> {
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> {
fn unary(&mut self, op: &Token, right: &Expression) -> Result<Value, InterpreterError> {
let right = self.evaluate(right)?;
match op.token_type {
@ -159,13 +232,17 @@ impl Interpreter {
}
}
TokenType::Bang => Ok(Value::Boolean(!right.is_truthy())),
_ => Err(InterpreterError::UnaryOperatorUnknown(op.line, op.lexeme)),
_ => Err(InterpreterError::UnaryOperatorUnknown(
op.line,
op.lexeme.clone(),
)),
}
}
/// 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)
}
@ -196,9 +273,9 @@ impl Interpreter {
/// specified operator.
fn binary(
&mut self,
left: Expression,
op: Token,
right: Expression,
left: &Expression,
op: &Token,
right: &Expression,
) -> Result<Value, InterpreterError> {
let left = self.evaluate(left)?;
let right = self.evaluate(right)?;
@ -227,7 +304,10 @@ impl Interpreter {
}
TokenType::BangEqual => Ok(Value::Boolean(left != right)),
TokenType::EqualEqual => Ok(Value::Boolean(left == right)),
_ => Err(InterpreterError::BinaryOperatorUnknown(op.line, op.lexeme)),
_ => Err(InterpreterError::BinaryOperatorUnknown(
op.line,
op.lexeme.clone(),
)),
}
}
}

View File

@ -5,7 +5,7 @@ use crate::{
expression::Expression,
statement::Statement,
token::{
self, Token,
self, Literal, Token,
TokenType::{self, *},
},
};
@ -32,6 +32,18 @@ pub enum ParserError {
InvalidAssignmentTarget(usize),
#[error("[line {0}] expected '}}' after block.")]
RightBraceAfterBlockExpected(usize),
#[error("[line {0}] expected '(' after if.")]
LeftParenAfterIfExpected(usize),
#[error("[line {0}] expected ')' after condition.")]
RightParenAfterConditionExpected(usize),
#[error("[line {0}] expected '(' after while.")]
LeftParenAfterWhileExpected(usize),
#[error("[line {0}] expected '(' after for.")]
LeftParenAfterForExpected(usize),
#[error("[line {0}] expected ';' after loop condition.")]
SemicolonAfterLoopConditionExpected(usize),
#[error("[line {0}] expected ')' after for clauses.")]
RightParenAfterForClausesExpected(usize),
}
/// Parse the Lox language.
@ -157,8 +169,14 @@ impl Parser {
}
fn statement(&mut self) -> Result<Statement, ParserError> {
if self.matches(&[Print]) {
if self.matches(&[For]) {
self.for_statement()
} else if self.matches(&[If]) {
self.if_statement()
} else if self.matches(&[Print]) {
self.print_statement()
} else if self.matches(&[While]) {
self.while_statement()
} else if self.matches(&[LeftBrace]) {
Ok(Statement::Block(self.block()?))
} else {
@ -166,6 +184,79 @@ impl Parser {
}
}
/// Build up a while statement from a for statement.
fn for_statement(&mut self) -> Result<Statement, ParserError> {
let line = self.current_token.line;
self.consume(&LeftParen)
.ok_or(ParserError::LeftParenAfterForExpected(line))?;
let initializer = if self.matches(&[Semicolon]) {
None
} else if self.matches(&[Var]) {
Some(self.var_declaration()?)
} else {
Some(self.expression_statement()?)
};
let condition = if !self.matches(&[Semicolon]) {
self.expression()?
} else {
Expression::Literal {
value: Literal::Boolean(true),
}
};
self.consume(&Semicolon)
.ok_or(ParserError::SemicolonAfterLoopConditionExpected(line))?;
let increment = if !self.check(&RightParen) {
Some(self.expression()?)
} else {
None
};
self.consume(&RightParen)
.ok_or(ParserError::RightParenAfterForClausesExpected(line))?;
let body = self.statement()?;
let body = match increment {
Some(inc) => Statement::Block(vec![body, Statement::Expression(inc)]),
None => body,
};
let body = Statement::While {
condition,
body: Box::new(body),
};
let body = match initializer {
Some(initializer) => Statement::Block(vec![initializer, body]),
None => body,
};
Ok(body)
}
fn if_statement(&mut self) -> Result<Statement, ParserError> {
let line = self.current_token.line;
self.consume(&LeftParen)
.ok_or(ParserError::LeftParenAfterIfExpected(line))?;
let condition = self.expression()?;
self.consume(&RightParen)
.ok_or(ParserError::RightParenAfterConditionExpected(line))?;
let then_branch = self.statement()?;
let else_branch = if self.matches(&[Else]) {
Some(Box::new(self.statement()?))
} else {
None
};
Ok(Statement::If {
condition,
then_branch: Box::new(then_branch),
else_branch,
})
}
fn print_statement(&mut self) -> Result<Statement, ParserError> {
let value = self.expression()?;
let line = self.current_token.line;
@ -197,6 +288,24 @@ impl Parser {
})
}
fn while_statement(&mut self) -> Result<Statement, ParserError> {
let line = self.current_token.line;
self.consume(&LeftParen)
.ok_or(ParserError::LeftParenAfterWhileExpected(line))?;
let condition = self.expression()?;
self.consume(&RightParen)
.ok_or(ParserError::RightParenAfterConditionExpected(line))?;
let body = self.statement()?;
Ok(Statement::While {
condition,
body: Box::new(body),
})
}
fn expression_statement(&mut self) -> Result<Statement, ParserError> {
let expr = self.expression()?;
let line = self.current_token.line;
@ -221,7 +330,7 @@ impl Parser {
}
fn assignment(&mut self) -> Result<Expression, ParserError> {
let expr = self.equality()?;
let expr = self.or()?;
if self.matches(&[Equal]) {
let equals = self.previous()?.clone();
@ -240,6 +349,38 @@ impl Parser {
}
}
fn logical_operator<F>(
&mut self,
operator: TokenType,
parse_fn: F,
) -> Result<Expression, ParserError>
where
F: Fn(&mut Self) -> Result<Expression, ParserError>,
{
let mut expr = parse_fn(self)?;
while self.matches(&[operator]) {
let operator = self.previous()?.clone();
let right = parse_fn(self)?;
expr = Expression::Logical {
left: Box::new(expr),
operator,
right: Box::new(right),
};
}
Ok(expr)
}
fn or(&mut self) -> Result<Expression, ParserError> {
self.logical_operator(Or, Self::and)
}
fn and(&mut self) -> Result<Expression, ParserError> {
self.logical_operator(And, Self::equality)
}
/// equality -> comparison ( ( "!=" | "==" ) comparison )* ;
fn equality(&mut self) -> Result<Expression, ParserError> {
self.binary_expr(Self::comparison, &[BangEqual, EqualEqual])

View File

@ -10,4 +10,13 @@ pub enum Statement {
name: Token,
initializer: Box<Option<Expression>>,
},
If {
condition: Expression,
then_branch: Box<Statement>,
else_branch: Option<Box<Statement>>,
},
While {
condition: Expression,
body: Box<Statement>,
},
}