Parser - Initial implementation of the for loop
This commit is contained in:
parent
14bff1d7bc
commit
f95fcc4e3e
1 changed files with 94 additions and 8 deletions
102
src/parser.rs
102
src/parser.rs
|
@ -82,6 +82,7 @@ impl Parser {
|
||||||
/// statement := block
|
/// statement := block
|
||||||
/// statement := if_statement
|
/// statement := if_statement
|
||||||
/// statement := while_statement
|
/// statement := while_statement
|
||||||
|
/// statement := for_statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
if self.expect(&[TokenType::Var]).is_some() {
|
if self.expect(&[TokenType::Var]).is_some() {
|
||||||
|
@ -92,17 +93,27 @@ impl Parser {
|
||||||
self.parse_if_statement()
|
self.parse_if_statement()
|
||||||
} else if self.expect(&[TokenType::While]).is_some() {
|
} else if self.expect(&[TokenType::While]).is_some() {
|
||||||
self.parse_while_statement()
|
self.parse_while_statement()
|
||||||
|
} else if self.expect(&[TokenType::For]).is_some() {
|
||||||
|
self.parse_for_statement()
|
||||||
} else if self.expect(&[TokenType::Print]).is_some() {
|
} else if self.expect(&[TokenType::Print]).is_some() {
|
||||||
let expression = self.parse_expression()?;
|
let expression = self.parse_expression()?;
|
||||||
self.consume(&TokenType::Semicolon, "expected ';' after value")?;
|
self.consume(&TokenType::Semicolon, "expected ';' after value")?;
|
||||||
Ok(ast::StmtNode::Print(expression))
|
Ok(ast::StmtNode::Print(expression))
|
||||||
} else {
|
} else {
|
||||||
let expression = self.parse_expression()?;
|
self.parse_expression_stmt()
|
||||||
self.consume(&TokenType::Semicolon, "expected ';' after expression")?;
|
|
||||||
Ok(ast::StmtNode::Expression(expression))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// expression_stmt := expression ";"
|
||||||
|
/// ```
|
||||||
|
fn parse_expression_stmt(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
|
let expression = self.parse_expression()?;
|
||||||
|
self.consume(&TokenType::Semicolon, "expected ';' after expression")?;
|
||||||
|
Ok(ast::StmtNode::Expression(expression))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
/// ```
|
/// ```
|
||||||
/// declaration := "var" IDENTIFIER ";"
|
/// declaration := "var" IDENTIFIER ";"
|
||||||
|
@ -140,13 +151,16 @@ impl Parser {
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
/// ```
|
/// ```
|
||||||
/// if := "if" condition statement
|
/// if_statement := "if" "(" expression ")" statement
|
||||||
/// if := "if" condition statement "else" statement
|
/// if_statement := "if" "(" expression ")" statement "else" statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_if_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_if_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
self.consume(&TokenType::LeftParen, "expected '(' after 'if'")?;
|
self.consume(&TokenType::LeftParen, "expected '(' after 'if'")?;
|
||||||
let expression = self.parse_expression()?;
|
let expression = self.parse_expression()?;
|
||||||
self.consume(&TokenType::RightParen, "expected ')' after condition in 'if' statement")?;
|
self.consume(
|
||||||
|
&TokenType::RightParen,
|
||||||
|
"expected ')' after condition in 'if' statement",
|
||||||
|
)?;
|
||||||
let then_branch = Box::new(self.parse_statement()?);
|
let then_branch = Box::new(self.parse_statement()?);
|
||||||
let else_branch = match self.expect(&[TokenType::Else]) {
|
let else_branch = match self.expect(&[TokenType::Else]) {
|
||||||
Some(_) => Some(Box::new(self.parse_statement()?)),
|
Some(_) => Some(Box::new(self.parse_statement()?)),
|
||||||
|
@ -161,16 +175,88 @@ impl Parser {
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
/// ```
|
/// ```
|
||||||
/// while := "while" condition statement
|
/// while_statement := "while" "(" expression ")" statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_while_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_while_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
self.consume(&TokenType::LeftParen, "expected '(' after 'while'")?;
|
self.consume(&TokenType::LeftParen, "expected '(' after 'while'")?;
|
||||||
let condition = self.parse_expression()?;
|
let condition = self.parse_expression()?;
|
||||||
self.consume(&TokenType::RightParen, "expected ')' after condition in 'while' statement")?;
|
self.consume(
|
||||||
|
&TokenType::RightParen,
|
||||||
|
"expected ')' after condition in 'while' statement",
|
||||||
|
)?;
|
||||||
let body = Box::new(self.parse_statement()?);
|
let body = Box::new(self.parse_statement()?);
|
||||||
Ok(ast::StmtNode::WhileStmt { condition, body })
|
Ok(ast::StmtNode::WhileStmt { condition, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rules:
|
||||||
|
/// ```
|
||||||
|
/// for_statement := "for" "(" for_initializer ";" expression ";" expression ")" statement
|
||||||
|
/// for_initializer := declaration
|
||||||
|
/// for_initializer := expression
|
||||||
|
/// for_initializer :=
|
||||||
|
/// ```
|
||||||
|
fn parse_for_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
|
self.consume(&TokenType::LeftParen, "expected '(' after 'for'")?;
|
||||||
|
|
||||||
|
let initializer = if self.expect(&[TokenType::Semicolon]).is_some() {
|
||||||
|
None
|
||||||
|
} else if self.expect(&[TokenType::Var]).is_some() {
|
||||||
|
Some(self.parse_declaration()?)
|
||||||
|
} else {
|
||||||
|
Some(self.parse_expression_stmt()?)
|
||||||
|
};
|
||||||
|
|
||||||
|
let condition = if self.check(&TokenType::Semicolon) {
|
||||||
|
ast::ExprNode::Litteral {
|
||||||
|
value: Token {
|
||||||
|
token_type: TokenType::True,
|
||||||
|
lexeme: String::from("true"),
|
||||||
|
line: self.peek().line,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.parse_expression()?
|
||||||
|
};
|
||||||
|
self.consume(
|
||||||
|
&TokenType::Semicolon,
|
||||||
|
"expected ';' after condition in 'for' statement",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let increment = if self.check(&TokenType::RightParen) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.parse_expression()?)
|
||||||
|
};
|
||||||
|
self.consume(
|
||||||
|
&TokenType::RightParen,
|
||||||
|
"expected ')' after increment in 'for' statement",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Generate a while loop, with an optional initializer which may be
|
||||||
|
// inside a specific block if the initializer declares a variable.
|
||||||
|
let body_stmt = self.parse_statement()?;
|
||||||
|
let body_with_incr = if let Some(incr) = increment {
|
||||||
|
ast::StmtNode::Block(vec![
|
||||||
|
Box::new(body_stmt),
|
||||||
|
Box::new(ast::StmtNode::Expression(incr)),
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
body_stmt
|
||||||
|
};
|
||||||
|
let while_stmt = ast::StmtNode::WhileStmt {
|
||||||
|
condition,
|
||||||
|
body: Box::new(body_with_incr),
|
||||||
|
};
|
||||||
|
if let Some(init_stmt) = initializer {
|
||||||
|
Ok(ast::StmtNode::Block(vec![
|
||||||
|
Box::new(init_stmt),
|
||||||
|
Box::new(while_stmt),
|
||||||
|
]))
|
||||||
|
} else {
|
||||||
|
Ok(while_stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
/// ```
|
/// ```
|
||||||
/// expression := assignment
|
/// expression := assignment
|
||||||
|
|
Loading…
Reference in a new issue