chapter 9 in rust
This commit is contained in:
parent
1a485ebcb1
commit
f82919414e
@ -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,
|
||||
|
@ -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>,
|
||||
|
@ -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(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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])
|
||||
|
@ -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>,
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user