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;
|
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,
|
||||||
|
@ -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>,
|
||||||
|
@ -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(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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])
|
||||||
|
@ -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>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user