if-else ast

This commit is contained in:
Janis 2024-08-30 23:55:13 +02:00
parent ad6a9b00ec
commit 6bab60d168
3 changed files with 134 additions and 2 deletions

View file

@ -185,6 +185,18 @@ pub enum Tag {
lhs: Node, lhs: Node,
rhs: Node, rhs: Node,
}, },
ExprStatement {
expr: Node,
},
IfExpr {
condition: Node,
body: Node,
},
IfElseExpr {
condition: Node,
body: Node,
else_expr: Node,
},
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -930,10 +930,93 @@ impl Tree {
} }
} }
/// EXPR_OR_STATEMENT_OR_BLOCK <-
/// BLOCK
/// EXPR
/// EXPR ;
pub fn parse_expr_or_stmt_or_block(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
let peek = tokens.peek_token_or_err()?;
let body = match peek.token() {
// block
Token::OpenBrace => {
let block = self.nodes.reserve_node();
self.parse_block(tokens, Some(block))?
}
// expr
_ => {
let expr = self.parse_expr(tokens)?;
let block = if tokens.eat_token(Token::Semi).is_some() {
Tag::Block {
statements: vec![expr],
trailing_expr: None,
}
} else {
Tag::Block {
statements: vec![],
trailing_expr: Some(expr),
}
};
self.nodes.push_tag(block)
}
};
Ok(body)
}
/// ELSE_EXPR <-
/// 'else' (IF_EXPR | EXPR_OR_STATEMENT_OR_BLOCK)
pub fn try_parse_else_expr(&mut self, tokens: &mut TokenIterator) -> Result<Option<Node>> {
if tokens.eat_token(Token::Else).is_none() {
return Ok(None);
}
let expr = if let Some(if_expr) = self.try_parse_if_expr(tokens)? {
if_expr
} else {
self.parse_expr_or_stmt_or_block(tokens)?
};
Ok(Some(expr))
}
/// IF_EXPR <-
/// 'if' ( EXPR ) EXPR_OR_STATEMENT_OR_BLOCK ELSE_EXPR?
pub fn try_parse_if_expr(&mut self, tokens: &mut TokenIterator) -> Result<Option<Node>> {
if tokens.eat_token(Token::If).is_none() {
return Ok(None);
}
_ = tokens.expect_token(Token::OpenParens)?;
let condition = self.parse_expr(tokens)?;
_ = tokens.expect_token(Token::CloseParens)?;
let body = self.parse_expr_or_stmt_or_block(tokens)?;
if let Some(else_expr) = self.try_parse_else_expr(tokens)? {
Ok(Some(self.nodes.push_tag(Tag::IfElseExpr {
condition,
body,
else_expr,
})))
} else {
Ok(Some(self.nodes.push_tag(Tag::IfExpr { condition, body })))
}
}
/// IF_EXPR <-
/// 'if' ( EXPR ) EXPR_OR_STATEMENT_OR_BLOCK ELSE_EXPR?
pub fn parse_if_expr(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
self.try_parse_if_expr(tokens)?
.ok_or(Error::ExpectedTokenNotFound(Token::If))
}
/// EXPRESSION <- /// EXPRESSION <-
/// ASSIGNMENT_EXPR /// IF_EXPR
/// | ASSIGNMENT_EXPR
pub fn parse_expr(&mut self, tokens: &mut TokenIterator) -> Result<Node> { pub fn parse_expr(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
self.parse_assignment_expr(tokens) match tokens.peek_token_or_err()?.token() {
Token::If => self.parse_if_expr(tokens),
_ => self.parse_assignment_expr(tokens),
}
} }
/// PROGRAM <- /// PROGRAM <-
@ -1549,6 +1632,36 @@ impl Tree {
self.strings.display_idx(bytes) self.strings.display_idx(bytes)
) )
} }
Tag::ExprStatement { expr } => {
self.render_node(writer, expr, indent)?;
writeln_indented!(indent, writer, "%{node} = expr %{expr}",)
}
Tag::IfExpr { condition, body } => {
self.render_node(writer, condition, indent)?;
writeln_indented!(
indent,
writer,
"%{node} = if (condition: %{condition}, body: %{body}) {{",
)?;
self.render_node(writer, body, indent + 1)?;
writeln_indented!(indent, writer, "}})",)
}
Tag::IfElseExpr {
condition,
body,
else_expr,
} => {
self.render_node(writer, condition, indent)?;
writeln_indented!(
indent,
writer,
"%{node} = if (condition: %{condition}, body: %{body}) {{",
)?;
self.render_node(writer, body, indent + 1)?;
writeln_indented!(indent, writer, "}}, else: %{else_expr} {{",)?;
self.render_node(writer, else_expr, indent + 1)?;
writeln_indented!(indent, writer, "}})",)
}
_ => unreachable!(), _ => unreachable!(),
} }
} }

7
tests/legal/if.sea Normal file
View file

@ -0,0 +1,7 @@
fn square_of_greater(a: i32, b: i32) -> i32 {
if (a < b)
a * a
else
b * b
}