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; use thiserror::Error;
@ -15,14 +15,15 @@ pub enum EnvironmentError {
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct Environment { pub struct Environment {
values: HashMap<String, Value>, values: HashMap<String, Value>,
enclosing: Option<Box<Environment>>, enclosing: Option<Rc<RefCell<Environment>>>,
} }
impl 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 { Self {
values: HashMap::default(), values: HashMap::default(),
enclosing: Some(Box::new(enclosing)), enclosing: Some(enclosing),
} }
} }
@ -40,7 +41,7 @@ impl Environment {
self.values.insert(token.lexeme.clone(), value); self.values.insert(token.lexeme.clone(), value);
Ok(()) Ok(())
} else if let Some(enclosing) = &mut self.enclosing { } else if let Some(enclosing) = &mut self.enclosing {
enclosing.assign(token, value) enclosing.borrow_mut().assign(token, value)
} else { } else {
Err(EnvironmentError::UndefinedVariable( Err(EnvironmentError::UndefinedVariable(
token.line, token.line,
@ -55,7 +56,7 @@ impl Environment {
if let Some(v) = self.values.get(token.lexeme.as_str()) { if let Some(v) = self.values.get(token.lexeme.as_str()) {
Ok(v.clone()) Ok(v.clone())
} else if let Some(enclosing) = &self.enclosing { } else if let Some(enclosing) = &self.enclosing {
enclosing.get(token) enclosing.borrow().get(token)
} else { } else {
Err(EnvironmentError::UndefinedVariable( Err(EnvironmentError::UndefinedVariable(
token.line, token.line,

View File

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

View File

@ -1,3 +1,5 @@
use std::{cell::RefCell, rc::Rc};
use thiserror::Error; use thiserror::Error;
use tracing::error; use tracing::error;
@ -28,14 +30,14 @@ pub enum InterpreterError {
/// Interpreter for the Lox language. /// Interpreter for the Lox language.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Interpreter { pub struct Interpreter {
environment: Environment, environment: Rc<RefCell<Environment>>,
} }
impl Interpreter { impl Interpreter {
/// Try to evaluate an expression and return its result. /// Try to evaluate an expression and return its result.
pub fn run(&mut self, statements: Vec<Statement>) -> Result<(), InterpreterError> { pub fn run(&mut self, statements: Vec<Statement>) -> Result<(), InterpreterError> {
for stmt in statements { for stmt in statements {
match self.execute(stmt) { match self.execute(&stmt) {
Ok(_) => {} Ok(_) => {}
Err(e) => error!("{e}"), Err(e) => error!("{e}"),
}; };
@ -45,7 +47,7 @@ impl Interpreter {
} }
///Execute a statement. ///Execute a statement.
fn execute(&mut self, statement: Statement) -> Result<(), InterpreterError> { fn execute(&mut self, statement: &Statement) -> Result<(), InterpreterError> {
match statement { match statement {
Statement::Block(statements) => { Statement::Block(statements) => {
let sub_env = Environment::with_enclosing(self.environment.clone()); let sub_env = Environment::with_enclosing(self.environment.clone());
@ -55,7 +57,18 @@ impl Interpreter {
Statement::Expression(expression) => { Statement::Expression(expression) => {
self.evaluate(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(()) Ok(())
@ -65,11 +78,11 @@ impl Interpreter {
/// enclosing one). /// enclosing one).
fn block( fn block(
&mut self, &mut self,
statements: Vec<Statement>, statements: &Vec<Statement>,
environment: Environment, environment: Environment,
) -> Result<(), InterpreterError> { ) -> Result<(), InterpreterError> {
let prev_env = &self.environment.clone(); let prev_env = self.environment.clone();
self.environment = environment; self.environment = Rc::new(RefCell::new(environment));
for stmt in statements { for stmt in statements {
if let Err(e) = self.execute(stmt) { if let Err(e) = self.execute(stmt) {
@ -83,26 +96,47 @@ impl Interpreter {
} }
/// Evaluate an expression and return its value. /// 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 { match expression {
Expression::Literal { value } => self.literal(value), Expression::Literal { value } => self.literal(value.clone()),
Expression::Grouping { expression } => self.grouping(*expression), Expression::Grouping { expression } => self.grouping(expression),
Expression::Unary { Expression::Unary {
operator: op, operator: op,
right, right,
} => self.unary(op, *right), } => self.unary(op, right),
Expression::Binary { Expression::Binary {
left, left,
operator, operator,
right, right,
} => self.binary(*left, operator, *right), } => self.binary(left, operator, right),
Expression::Variable { name } => self.var_expression(&name), Expression::Variable { name } => self.var_expression(name),
Expression::Assign { name, value } => self.assign(&name, *value), 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. /// 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)?; let value = self.evaluate(expression)?;
println!("{value}"); println!("{value}");
@ -112,8 +146,8 @@ impl Interpreter {
/// Initialize a variable with an initializer expression or nil. /// Initialize a variable with an initializer expression or nil.
fn var_statement( fn var_statement(
&mut self, &mut self,
name: Token, name: &Token,
initializer: Option<Expression>, initializer: Option<&Expression>,
) -> Result<(), InterpreterError> { ) -> Result<(), InterpreterError> {
let value = if let Some(initializer) = initializer { let value = if let Some(initializer) = initializer {
self.evaluate(initializer) self.evaluate(initializer)
@ -121,16 +155,32 @@ impl Interpreter {
Ok(Value::Nil) 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(()) Ok(())
} }
/// Assign the value of an expression to a variable. /// 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)?; let value = self.evaluate(value)?;
self.environment self.environment
.borrow_mut()
.assign(name, value.clone()) .assign(name, value.clone())
.map_err(InterpreterError::UndefinedVariable)?; .map_err(InterpreterError::UndefinedVariable)?;
Ok(value) Ok(value)
@ -141,13 +191,36 @@ impl Interpreter {
Ok(literal.into()) 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. /// 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) self.evaluate(inner)
} }
/// Evaluate the expression on the right and use its result when evaluating the unary operator. /// 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)?; let right = self.evaluate(right)?;
match op.token_type { match op.token_type {
@ -159,13 +232,17 @@ impl Interpreter {
} }
} }
TokenType::Bang => Ok(Value::Boolean(!right.is_truthy())), 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. /// Get the value of a variable.
fn var_expression(&mut self, name: &Token) -> Result<Value, InterpreterError> { fn var_expression(&mut self, name: &Token) -> Result<Value, InterpreterError> {
self.environment self.environment
.borrow()
.get(name) .get(name)
.map_err(InterpreterError::UndefinedVariable) .map_err(InterpreterError::UndefinedVariable)
} }
@ -196,9 +273,9 @@ impl Interpreter {
/// specified operator. /// specified operator.
fn binary( fn binary(
&mut self, &mut self,
left: Expression, left: &Expression,
op: Token, op: &Token,
right: Expression, right: &Expression,
) -> Result<Value, InterpreterError> { ) -> Result<Value, InterpreterError> {
let left = self.evaluate(left)?; let left = self.evaluate(left)?;
let right = self.evaluate(right)?; let right = self.evaluate(right)?;
@ -227,7 +304,10 @@ impl Interpreter {
} }
TokenType::BangEqual => Ok(Value::Boolean(left != right)), TokenType::BangEqual => Ok(Value::Boolean(left != right)),
TokenType::EqualEqual => 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, expression::Expression,
statement::Statement, statement::Statement,
token::{ token::{
self, Token, self, Literal, Token,
TokenType::{self, *}, TokenType::{self, *},
}, },
}; };
@ -32,6 +32,18 @@ pub enum ParserError {
InvalidAssignmentTarget(usize), InvalidAssignmentTarget(usize),
#[error("[line {0}] expected '}}' after block.")] #[error("[line {0}] expected '}}' after block.")]
RightBraceAfterBlockExpected(usize), 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. /// Parse the Lox language.
@ -157,8 +169,14 @@ impl Parser {
} }
fn statement(&mut self) -> Result<Statement, ParserError> { 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() self.print_statement()
} else if self.matches(&[While]) {
self.while_statement()
} else if self.matches(&[LeftBrace]) { } else if self.matches(&[LeftBrace]) {
Ok(Statement::Block(self.block()?)) Ok(Statement::Block(self.block()?))
} else { } 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> { fn print_statement(&mut self) -> Result<Statement, ParserError> {
let value = self.expression()?; let value = self.expression()?;
let line = self.current_token.line; 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> { fn expression_statement(&mut self) -> Result<Statement, ParserError> {
let expr = self.expression()?; let expr = self.expression()?;
let line = self.current_token.line; let line = self.current_token.line;
@ -221,7 +330,7 @@ impl Parser {
} }
fn assignment(&mut self) -> Result<Expression, ParserError> { fn assignment(&mut self) -> Result<Expression, ParserError> {
let expr = self.equality()?; let expr = self.or()?;
if self.matches(&[Equal]) { if self.matches(&[Equal]) {
let equals = self.previous()?.clone(); 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 )* ; /// equality -> comparison ( ( "!=" | "==" ) comparison )* ;
fn equality(&mut self) -> Result<Expression, ParserError> { fn equality(&mut self) -> Result<Expression, ParserError> {
self.binary_expr(Self::comparison, &[BangEqual, EqualEqual]) self.binary_expr(Self::comparison, &[BangEqual, EqualEqual])

View File

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