if-else ast
This commit is contained in:
parent
ad6a9b00ec
commit
6bab60d168
12
src/ast.rs
12
src/ast.rs
|
@ -185,6 +185,18 @@ pub enum Tag {
|
|||
lhs: 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)]
|
||||
|
|
117
src/parser.rs
117
src/parser.rs
|
@ -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 <-
|
||||
/// ASSIGNMENT_EXPR
|
||||
/// IF_EXPR
|
||||
/// | ASSIGNMENT_EXPR
|
||||
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 <-
|
||||
|
@ -1549,6 +1632,36 @@ impl Tree {
|
|||
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!(),
|
||||
}
|
||||
}
|
||||
|
|
7
tests/legal/if.sea
Normal file
7
tests/legal/if.sea
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
fn square_of_greater(a: i32, b: i32) -> i32 {
|
||||
if (a < b)
|
||||
a * a
|
||||
else
|
||||
b * b
|
||||
}
|
Loading…
Reference in a new issue