Skip to content

Commit

Permalink
feat: parse while loop
Browse files Browse the repository at this point in the history
  • Loading branch information
viddrobnic committed May 29, 2024
1 parent b1a0376 commit 8aad265
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
28 changes: 27 additions & 1 deletion parser/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl Parser<'_> {
let (if_node, end) = self.parse_if()?;
(ast::NodeValue::If(if_node), end)
}
TokenKind::While => todo!("parse while loop"),
TokenKind::While => self.parse_while()?,
TokenKind::For => todo!("parse for loop"),
TokenKind::Break => (ast::NodeValue::Break, range.end),
TokenKind::Continue => (ast::NodeValue::Continue, range.end),
Expand Down Expand Up @@ -469,6 +469,32 @@ impl Parser<'_> {
}
}

fn parse_while(&mut self) -> Result<(ast::NodeValue, Position)> {
// Read `(`
let token = self.next_token()?;
validate_token_kind(&token, TokenKind::LBracket)?;

// Parse condition
let cond_token = self.next_token()?;
let condition = self.parse_node(cond_token, Precedence::Lowest)?;
validate_node_kind(&condition, NodeKind::Expression)?;

// Read `)`
let token = self.next_token()?;
validate_token_kind(&token, TokenKind::RBracket)?;

let block_token = self.next_token()?;
let (block, end) = self.parse_block(block_token)?;

Ok((
ast::NodeValue::While {
condition: Box::new(condition),
body: block,
},
end,
))
}

// Helper function that reads block { ... }.
// It returns vector of nodes and end position, which is the end
// position of `}`
Expand Down
59 changes: 59 additions & 0 deletions parser/src/parser/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,65 @@ fn if_node() -> Result<()> {
Ok(())
}

#[test]
fn while_loop() -> Result<()> {
let tests = [
(
"while (true) {}",
ast::Node {
value: ast::NodeValue::While {
condition: Box::new(ast::Node {
value: ast::NodeValue::BoolLiteral(true),
range: Range {
start: Position::new(0, 7),
end: Position::new(0, 11),
},
}),
body: vec![],
},
range: Range {
start: Position::new(0, 0),
end: Position::new(0, 15),
},
},
),
(
"while (true) {\nfoo\n}",
ast::Node {
value: ast::NodeValue::While {
condition: Box::new(ast::Node {
value: ast::NodeValue::BoolLiteral(true),
range: Range {
start: Position::new(0, 7),
end: Position::new(0, 11),
},
}),
body: vec![ast::Node {
value: ast::NodeValue::Identifier("foo".to_string()),
range: Range {
start: Position::new(1, 0),
end: Position::new(1, 3),
},
}],
},
range: Range {
start: Position::new(0, 0),
end: Position::new(2, 1),
},
},
),
];

for (input, expected) in tests {
let program = parse(input)?;

assert_eq!(program.statements.len(), 1);
assert_eq!(program.statements[0], expected);
}

Ok(())
}

#[test]
fn errors() {
let tests = [
Expand Down

0 comments on commit 8aad265

Please sign in to comment.