Introduce bare else clause in if exprs

With a non-passing test
This commit is contained in:
greg 2019-10-09 01:50:32 -07:00
parent 22efd39114
commit 2ed84de641
4 changed files with 47 additions and 6 deletions

View File

@ -239,6 +239,7 @@ pub struct GuardArm {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Guard { pub enum Guard {
None,
Pat(Pattern), Pat(Pattern),
HalfExpr(HalfExpr) HalfExpr(HalfExpr)
} }

View File

@ -122,7 +122,7 @@
//! simple_pattern_match := pattern "then" conditional //! simple_pattern_match := pattern "then" conditional
//! else_clause := ε | "else" expr_or_block //! else_clause := ε | "else" expr_or_block
//! guard_block := "{" (guard_arm, ",")* "}" //! guard_block := "{" (guard_arm, ",")* "}"
//! guard_arm := guard "then" expr_or_block //! guard_arm := guard "then" expr_or_block | "else" expr_or_block
//! guard := "is" pattern | (operator)+ precedence_expr //! guard := "is" pattern | (operator)+ precedence_expr
//! ``` //! ```
//! //!
@ -893,10 +893,16 @@ impl Parser {
#[recursive_descent_method] #[recursive_descent_method]
fn guard_arm(&mut self) -> ParseResult<GuardArm> { fn guard_arm(&mut self) -> ParseResult<GuardArm> {
let guard = self.guard()?; if let Keyword(Kw::Else) = self.token_handler.peek_kind() {
expect!(self, Keyword(Kw::Then)); self.token_handler.next();
let body = self.expr_or_block()?; let body = self.expr_or_block()?;
Ok(GuardArm { guard, body }) Ok(GuardArm { guard: Guard::None, body })
} else {
let guard = self.guard()?;
expect!(self, Keyword(Kw::Then));
let body = self.expr_or_block()?;
Ok(GuardArm { guard, body })
}
} }
#[recursive_descent_method] #[recursive_descent_method]

View File

@ -4,7 +4,7 @@ use std::str::FromStr;
use super::tokenize; use super::tokenize;
use super::ParseResult; use super::ParseResult;
use crate::ast::{ItemIdStore, AST, Expression, Statement, StatementKind, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp, QualifiedName, ImportSpecifier, ImportedNames}; use crate::ast::{ItemIdStore, AST, Expression, Statement, StatementKind, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp, QualifiedName, ImportSpecifier, ImportedNames, GuardArm, Guard};
use super::Declaration::*; use super::Declaration::*;
use super::Signature; use super::Signature;
use super::TypeIdentifier::*; use super::TypeIdentifier::*;
@ -761,3 +761,27 @@ fn imports_4() {
} }
} }
#[test]
fn if_expr() {
parse_test_wrap_ast! {
"if x { 1 then 5, else 20 }",
exst! {
IfExpression {
discriminator: bx!(Discriminator::Simple(ex!(s "x"))),
body: bx!(IfExpressionBody::GuardList(
vec![
GuardArm {
guard: Guard::Pat(Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(1)})),
body: vec![exst!(s "5")],
},
GuardArm {
guard: Guard::None,
body: vec![exst!(s "20")],
},
]
))
}
}
}
}

View File

@ -276,6 +276,16 @@ impl<'a> Reducer<'a> {
let mut alternatives = vec![]; let mut alternatives = vec![];
for arm in guard_arms { for arm in guard_arms {
match arm.guard { match arm.guard {
Guard::None => {
let item = self.block(&arm.body);
let alt = Alternative {
item, matchable: Subpattern {
tag: None, subpatterns: vec![],
bound_vars: vec![], guard: None,
}
};
alternatives.push(alt);
},
Guard::Pat(ref p) => { Guard::Pat(ref p) => {
let item = self.block(&arm.body); let item = self.block(&arm.body);
let alt = p.to_alternative(item, symbol_table); let alt = p.to_alternative(item, symbol_table);