chapter 9 in rust
This commit is contained in:
parent
1a485ebcb1
commit
f82919414e
5 changed files with 271 additions and 35 deletions
|
@ -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])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue