Skip to content

Commit

Permalink
fix(parser): support for else and elseif expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Mar 5, 2024
1 parent 03f5a86 commit 7101308
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 9 deletions.
27 changes: 20 additions & 7 deletions crates/fuse-parser/src/parsers/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
Parser, ParserResult,
};
use fuse_ast::{
BindingPattern, BindingPatternKind, BooleanLiteral, Expression, Function, FunctionBody,
BindingPattern, BindingPatternKind, BooleanLiteral, Else, Expression, Function, FunctionBody,
FunctionParameter, FunctionParameters, Identifier, If, TypeAnnotation,
};
use fuse_common::Span;
Expand Down Expand Up @@ -57,30 +57,43 @@ impl<'a> Parser<'a> {
}

fn parse_if_expression(&mut self) -> ParserResult<Expression> {
self.parse_if().map(|expr| self.ast.if_expression(expr))
}

fn parse_if(&mut self) -> ParserResult<If> {
let start = self.start_span();
// Consume the keyword
self.consume();
let cond = self.parse_expression()?;
self.consume_expect(TokenKind::Then)?;
let body = self.parse_block_while(|kind| {
matches! {
println!("IF KIND {kind:?}");
!matches! {
kind,
| TokenKind::End
| TokenKind::Else
| TokenKind::ElseIf
}
})?;
let r#else = match self.consume().kind() {
TokenKind::End => None,
_ => todo!(),
let r#else = match self.cur_kind() {
TokenKind::End => {
self.consume();
None
}
TokenKind::ElseIf => Some(Else::If(Box::from(self.parse_if()?))),
TokenKind::Else => {
self.consume();
Some(Else::Block(Box::from(self.parse_block()?)))
}
_ => return Err(Self::unexpected_error(&self.prev_token)),
};
// how to detect end of block?
// maybe via a predicate function?
Ok(self.ast.if_expression(If {
Ok(If {
span: self.end_span(start),
cond,
body,
r#else,
}))
})
}
}
4 changes: 2 additions & 2 deletions crates/fuse-parser/src/parsers/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ impl<'a> Parser<'a> {
/// Parse a block of statements until and including the `end` token.
pub(crate) fn parse_block(&mut self) -> ParserResult<Block> {
let result = self
.parse_statements(|kind| kind == TokenKind::End)
.parse_statements(|kind| kind != TokenKind::End)
.map(|stmts| self.ast.block(stmts));
// Eat the end token.
self.consume();
Expand All @@ -28,7 +28,7 @@ impl<'a> Parser<'a> {
) -> ParserResult<Vec<Statement>> {
let mut statements = Vec::new();

while !self.at(TokenKind::Eof) && !predicate(self.cur_kind()) {
while !self.at(TokenKind::Eof) && predicate(self.cur_kind()) {
match self.parse_statement() {
ParserResult::Ok(stmt) => {
statements.push(stmt);
Expand Down
50 changes: 50 additions & 0 deletions crates/fuse-parser/tests/cases/pass/if-expression-02/ast.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
source: crates/fuse-parser/tests/cases/mod.rs
expression: parsed.chunk
input_file: crates/fuse-parser/tests/cases/pass/if-expression-02/case.fuse
---
Some(Chunk(
span: Span(
start: 0,
end: 35,
),
body: Block(
statements: [
Expression(If(If(
span: Span(
start: 0,
end: 34,
),
cond: Identifier(Identifier(
span: Span(
start: 3,
end: 7,
),
name: Atom("cond"),
)),
body: Block(
statements: [
Expression(BooleanLiteral(BooleanLiteral(
span: Span(
start: 14,
end: 18,
),
value: true,
))),
],
),
else: Some(Block(Block(
statements: [
Expression(BooleanLiteral(BooleanLiteral(
span: Span(
start: 25,
end: 30,
),
value: false,
))),
],
))),
))),
],
),
))
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
if cond then
true
else
false
end
140 changes: 140 additions & 0 deletions crates/fuse-parser/tests/cases/pass/if-expression-02/tokens.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---
source: crates/fuse-parser/tests/cases/mod.rs
expression: tokens
input_file: crates/fuse-parser/tests/cases/pass/if-expression-02/case.fuse
---
[
TokenReference(
token: Token(
span: Span(
start: 0,
end: 2,
),
kind: If,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 2,
end: 3,
),
kind: Whitespace,
),
],
),
TokenReference(
token: Token(
span: Span(
start: 3,
end: 7,
),
kind: Identifier,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 7,
end: 8,
),
kind: Whitespace,
),
],
),
TokenReference(
token: Token(
span: Span(
start: 8,
end: 12,
),
kind: Then,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 12,
end: 14,
),
kind: Whitespace,
),
],
),
TokenReference(
token: Token(
span: Span(
start: 14,
end: 18,
),
kind: True,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 18,
end: 19,
),
kind: Whitespace,
),
],
),
TokenReference(
token: Token(
span: Span(
start: 19,
end: 23,
),
kind: Else,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 23,
end: 25,
),
kind: Whitespace,
),
],
),
TokenReference(
token: Token(
span: Span(
start: 25,
end: 30,
),
kind: False,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 30,
end: 31,
),
kind: Whitespace,
),
],
),
TokenReference(
token: Token(
span: Span(
start: 31,
end: 34,
),
kind: End,
),
leading_trivia: [],
trailing_trivia: [
Token(
span: Span(
start: 34,
end: 35,
),
kind: Whitespace,
),
],
),
]

0 comments on commit 7101308

Please sign in to comment.