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,
|
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)]
|
||||||
|
|
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 <-
|
/// 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
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