From 6a318257d69a9fcc6eb44cb97bcfe1601fc1a6c7 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Thu, 4 Nov 2021 21:11:19 -0700 Subject: [PATCH] If exprs, patterns --- schala-lang/language/src/ast/mod.rs | 2 +- schala-lang/language/src/ast/visitor.rs | 3 - schala-lang/language/src/parsing/mod.rs | 5 +- schala-lang/language/src/parsing/new.rs | 333 ++++++++++++--------- schala-lang/language/src/parsing/test.rs | 96 +++--- schala-lang/language/src/reduced_ir/mod.rs | 2 - 6 files changed, 256 insertions(+), 185 deletions(-) diff --git a/schala-lang/language/src/ast/mod.rs b/schala-lang/language/src/ast/mod.rs index 721215f..870fa58 100644 --- a/schala-lang/language/src/ast/mod.rs +++ b/schala-lang/language/src/ast/mod.rs @@ -239,7 +239,7 @@ pub struct ConditionArm { pub enum Condition { Pattern(Pattern), TruncatedOp(BinOp, Expression), - Expression(Expression), + //Expression(Expression), //I'm pretty sure I don't actually want this Else, } diff --git a/schala-lang/language/src/ast/visitor.rs b/schala-lang/language/src/ast/visitor.rs index 89d4edd..11baf9c 100644 --- a/schala-lang/language/src/ast/visitor.rs +++ b/schala-lang/language/src/ast/visitor.rs @@ -166,9 +166,6 @@ pub fn walk_if_expr_body(v: &mut V, body: &IfExpressionBody) { Condition::TruncatedOp(ref _binop, ref expr) => { walk_expression(v, expr); } - Condition::Expression(ref expr) => { - walk_expression(v, expr); - } Condition::Else => (), } if let Some(ref guard) = arm.guard { diff --git a/schala-lang/language/src/parsing/mod.rs b/schala-lang/language/src/parsing/mod.rs index 399a6b2..fe04297 100644 --- a/schala-lang/language/src/parsing/mod.rs +++ b/schala-lang/language/src/parsing/mod.rs @@ -168,8 +168,8 @@ //! //! module := 'module' IDENTIFIER '{' statement* '}' //! ``` -mod test; mod new; +mod test; use std::rc::Rc; @@ -1048,7 +1048,8 @@ impl Parser { let expr = self.expression()?; Condition::TruncatedOp(op, expr) } - _ => Condition::Expression(self.expression()?), + //_ => Condition::Expression(self.expression()?), + _ => panic!(), }) } diff --git a/schala-lang/language/src/parsing/new.rs b/schala-lang/language/src/parsing/new.rs index a2b7c38..db3b62b 100644 --- a/schala-lang/language/src/parsing/new.rs +++ b/schala-lang/language/src/parsing/new.rs @@ -1,44 +1,13 @@ -use crate::ast::*; use std::rc::Rc; -#[derive(Debug)] -struct BinopSequence { - first: ExpressionKind, - next: Vec<(BinOp, ExpressionKind)>, -} - -impl BinopSequence { - fn do_precedence(self) -> ExpressionKind { - fn helper(precedence: i32, lhs: ExpressionKind, rest: &mut Vec<(BinOp, ExpressionKind)>) -> Expression { - let mut lhs = Expression::new(Default::default(), lhs); - loop { - let (next_op, next_rhs) = match rest.pop() { - Some((a, b)) => (a, b), - None => break, - }; - let new_precedence = next_op.get_precedence(); - if precedence >= new_precedence { - rest.push((next_op, next_rhs)); - break; - } - let rhs = helper(new_precedence, next_rhs, rest); - lhs = Expression::new(Default::default(), - ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)) - ); - } - lhs - } - let mut as_stack = self.next.into_iter().rev().collect(); - helper(BinOp::min_precedence(), self.first, &mut as_stack).kind - } -} +use crate::ast::*; peg::parser! { pub grammar schala_parser() for str { - rule whitespace() = [' ' | '\t']* + rule whitespace() = [' ' | '\t' | '\n']* - rule _ = quiet!{ whitespace() } + rule _ = quiet!{ whitespace() } pub rule program() -> AST = n:(statement() ** delimiter() ) { AST { id: Default::default(), statements: n.into() } } @@ -46,32 +15,163 @@ peg::parser! { rule delimiter() = ";" / "\n" rule statement() -> Statement = - expr:expression() { Statement { + _ expr:expression() { Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) } - } + } + + rule block() -> Block = "{" items:(statement() ** delimiter()) "}" { items.into() } pub rule expression() -> Expression = - kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } } + _ kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } } rule expression_kind() -> ExpressionKind = precedence_expr() rule precedence_expr() -> ExpressionKind = - first:primary() _ next:(precedence_continuation())* { - let next = next.into_iter().map(|(sigil, expr)| (BinOp::from_sigil(sigil), expr)).collect(); - BinopSequence { first, next }.do_precedence() - } + first:prefix_expr() _ next:(precedence_continuation())* { + let next = next.into_iter().map(|(sigil, expr)| (BinOp::from_sigil(sigil), expr)).collect(); + BinopSequence { first, next }.do_precedence() + } rule precedence_continuation() -> (&'input str, ExpressionKind) = op:operator() _ expr:primary() _ { (op, expr) } - //TODO maybe make this more complex + rule prefix_expr() -> ExpressionKind = + prefix:prefix()? expr:extended_expr() { + if let Some(p) = prefix { + let expr = Expression::new(Default::default(), expr); + let prefix = PrefixOp::from_sigil(p); + ExpressionKind::PrefixExp(prefix, Box::new(expr)) + } else { + expr + } + } + + rule prefix() -> &'input str = + $(['+' | '-' | '!' ]) + + //TODO make the definition of operators more complex rule operator() -> &'input str = - $( ['+' | '-' | '*' | '/' | '%' | '<' | '>' | '=' | '!' | '$' | '&' | '?' | '^' | '`']+ ) + quiet!{$( ['+' | '-' | '*' | '/' | '%' | '<' | '>' | '=' | '!' | '$' | '&' | '|' | '?' | '^' | '`']+ )} / + expected!("operator") + + rule extended_expr() -> ExpressionKind = + primary() rule primary() -> ExpressionKind = - float_literal() / nat_literal() / bool_literal() / string_literal() / paren_expr() / - list_expr() + float_literal() / nat_literal() / bool_literal() / string_literal() / paren_expr() / + list_expr() / if_expr() / identifier_expr() + + rule identifier_expr() -> ExpressionKind = + named_struct() / qn:qualified_identifier() { ExpressionKind::Value(qn) } + + rule named_struct() -> ExpressionKind = + name:qualified_identifier() _ fields:record_block() { + ExpressionKind::NamedStruct { + name, + fields: fields.into_iter().map(|(n, exp)| (Rc::new(n.to_string()), exp)).collect(), + } + } + + + //TODO anonymous structs, update syntax for structs + rule record_block() -> Vec<(&'input str, Expression)> = + "{" _ entries:(record_entry() ** ",") _ "}" { entries } + + rule record_entry() -> (&'input str, Expression) = + _ name:identifier() _ ":" _ expr:expression() _ { (name, expr) } + + rule qualified_identifier() -> QualifiedName = + names:(identifier() ++ "::") { QualifiedName { id: Default::default(), components: names.into_iter().map(|name| Rc::new(name.to_string())).collect() } } + + //TODO improve the definition of identifiers + rule identifier() -> &'input str = + $(['a'..='z' | 'A'..='Z' | '_'] ['a'..='z' | 'A'..='Z' | '0'..='9' | '_']*) + + + rule if_expr() -> ExpressionKind = + "if" _ discriminator:(expression()?) _ body:if_expr_body() { + ExpressionKind::IfExpression { + discriminator: discriminator.map(Box::new), + body: Box::new(body), + } + } + + rule if_expr_body() -> IfExpressionBody = + cond_block() / simple_pattern_match() / simple_conditional() + + rule simple_conditional() -> IfExpressionBody = + "then" _ then_case:expr_or_block() _ else_case:else_case() { + IfExpressionBody::SimpleConditional { then_case, else_case } + } + + rule simple_pattern_match() -> IfExpressionBody = + "is" _ pattern:pattern() _ "then" _ then_case:expr_or_block() _ else_case:else_case() { + IfExpressionBody::SimplePatternMatch { pattern, then_case, else_case } + } + + rule cond_block() -> IfExpressionBody = + "{" _ cond_arms:(cond_arm() ++ ",") _ "}" { IfExpressionBody::CondList(cond_arms) } + + rule cond_arm() -> ConditionArm = + _ "else" _ body:expr_or_block() { ConditionArm { condition: Condition::Else, guard: None, body } } / + _ condition:condition() _ guard:condition_guard() _ "then" _ body:expr_or_block() + { ConditionArm { condition, guard, body } } + + rule condition() -> Condition = + "is" _ pat:pattern() { Condition::Pattern(pat) } / + op:operator() _ expr:expression() { Condition::TruncatedOp(BinOp::from_sigil(op), expr) } + + rule condition_guard() -> Option = + ("if" _ expr:expression() { expr } )? + + + rule expr_or_block() -> Block = block() / ex:expression() { + Statement { + id: Default::default(), location: Default::default(), + kind: StatementKind::Expression(ex) + }.into() + } + + rule else_case() -> Option = + ("else" _ eorb:expr_or_block() { eorb })? + + rule pattern() -> Pattern = + "(" _ variants:(pattern() ++ ",") _ ")" { Pattern::TuplePattern(variants) } / + _ pat:simple_pattern() { pat } + + rule simple_pattern() -> Pattern = + pattern_literal() / + qn:qualified_identifier() "(" members:(pattern() ** ",") ")" { + Pattern::TupleStruct(qn, members) + } / + qn:qualified_identifier() _ "{" _ items:(record_pattern_entry() ** ",") "}" _ { + let items = items.into_iter().map(|(name, pat)| (Rc::new(name.to_string()), pat)).collect(); + Pattern::Record(qn, items) + } / + qn:qualified_identifier() { Pattern::VarOrName(qn) } + + rule record_pattern_entry() -> (&'input str, Pattern) = + _ name:identifier() _ ":" _ pat:pattern() _ { (name, pat) } / + _ name:identifier() _ { + let qn = QualifiedName { + id: Default::default(), + components: vec![Rc::new(name.to_string())], + }; + (name, Pattern::VarOrName(qn)) + } + + + rule pattern_literal() -> Pattern = + "true" { Pattern::Literal(PatternLiteral::BoolPattern(true)) } / + "false" { Pattern::Literal(PatternLiteral::BoolPattern(false)) } / + s:bare_string_literal() { Pattern::Literal(PatternLiteral::StringPattern(Rc::new(s.to_string()))) } / + sign:("-"?) num:nat_literal() { + let neg = sign.is_some(); + Pattern::Literal(PatternLiteral::NumPattern { neg, num }) + } / + "_" { Pattern::Ignored } + rule list_expr() -> ExpressionKind = "[" exprs:(expression() ** ",") "]" { @@ -86,11 +186,14 @@ peg::parser! { 1 => exprs.pop().unwrap().kind, _ => ExpressionKind::TupleLiteral(exprs), } - } + } + + rule string_literal() -> ExpressionKind = + s:bare_string_literal(){ ExpressionKind::StringLiteral(Rc::new(s.to_string())) } //TODO string escapes, prefixes - rule string_literal() -> ExpressionKind = - "\"" items:$([^ '"' ]*) "\"" { ExpressionKind::StringLiteral(Rc::new(items.to_string())) } + rule bare_string_literal() -> &'input str = + "\"" items:$([^ '"' ]*) "\"" { items } rule bool_literal() -> ExpressionKind = "true" { ExpressionKind::BoolLiteral(true) } / "false" { ExpressionKind::BoolLiteral(false) } @@ -111,17 +214,17 @@ peg::parser! { ds:$( digits() "." digits()? / "." digits() ) { ExpressionKind::FloatLiteral(ds.parse().unwrap()) } rule digits() -> &'input str = $((digit_group() "_"*)+) - rule bin_digits() -> &'input str = $((bin_digit_group() "_"*)+) - rule hex_digits() -> &'input str = $((hex_digit_group() "_"*)+) + rule bin_digits() -> &'input str = $((bin_digit_group() "_"*)+) + rule hex_digits() -> &'input str = $((hex_digit_group() "_"*)+) - rule digit_group() -> &'input str = $(['0'..='9']+) - rule bin_digit_group() -> &'input str = $(['0' | '1']+) - rule hex_digit_group() -> &'input str = $(['0'..='9' | 'a'..='f' | 'A'..='F']+) + rule digit_group() -> &'input str = $(['0'..='9']+) + rule bin_digit_group() -> &'input str = $(['0' | '1']+) + rule hex_digit_group() -> &'input str = $(['0'..='9' | 'a'..='f' | 'A'..='F']+) } } -fn parse_binary(digits: &str/*, tok: Token*/) -> /*ParseResult*/ u64 { +fn parse_binary(digits: &str /*, tok: Token*/) -> u64 { let mut result: u64 = 0; let mut multiplier = 1; for d in digits.chars().rev() { @@ -129,11 +232,13 @@ fn parse_binary(digits: &str/*, tok: Token*/) -> /*ParseResult*/ u64 { '1' => result += multiplier, '0' => (), '_' => continue, - _ => unreachable!() + _ => unreachable!(), } multiplier = match multiplier.checked_mul(2) { Some(m) => m, - None => /*return ParseError::new_with_token("This binary expression will overflow", tok),*/ panic!(), + None => + /*return ParseError::new_with_token("This binary expression will overflow", tok),*/ + panic!(), } } //Ok(result) @@ -154,89 +259,45 @@ fn parse_hex(digits: &str) -> u64 { } multiplier = match multiplier.checked_mul(16) { Some(m) => m, - None => panic!() + None => panic!(), } } result } - -#[cfg(test)] -mod test { - use super::*; - use pretty_assertions::assert_eq; - - #[test] - fn new_parser() { - let parsed = schala_parser::expression("4"); - assert_eq!(parsed.unwrap(), Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::NatLiteral(4) }); - - let parsed = schala_parser::program("56.1"); - if let Err(ref err) = parsed { - println!("{}", err); - } - assert_eq!(parsed.unwrap(), AST { - id: Default::default(), statements: vec![ - Statement { - id: Default::default(), - location: Default::default(), - kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: - ExpressionKind::FloatLiteral(56.1) }) - } - - ].into() }); - - let parsed = schala_parser::program("1;2\n5\n(1.1,false)"); - if let Err(ref err) = parsed { - println!("{}", err); - } - assert_eq!(parsed.unwrap(), AST { - id: Default::default(), statements: vec![ - Statement { - id: Default::default(), - location: Default::default(), - kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: - ExpressionKind::NatLiteral(1) }) - }, - Statement { - id: Default::default(), - location: Default::default(), - kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: - ExpressionKind::NatLiteral(2) }) - }, - Statement { - id: Default::default(), - location: Default::default(), - kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: - ExpressionKind::NatLiteral(5) }) - }, - Statement { - id: Default::default(), - location: Default::default(), - kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: - ExpressionKind::TupleLiteral(vec![Expression{ - id: Default::default(), - type_anno: None, - kind: ExpressionKind::FloatLiteral(1.1), - }, - Expression { - id: Default::default(), - type_anno: None, - kind: ExpressionKind::BoolLiteral(false), - }] - - ) }) - } - - ].into() }); - - /* - let parsed = schala_parser::expression("quincy"); - println!("{:?}", parsed.unwrap_err()); - - assert_eq!(1, 2); - */ - - } - +#[derive(Debug)] +struct BinopSequence { + first: ExpressionKind, + next: Vec<(BinOp, ExpressionKind)>, +} + +impl BinopSequence { + fn do_precedence(self) -> ExpressionKind { + fn helper( + precedence: i32, + lhs: ExpressionKind, + rest: &mut Vec<(BinOp, ExpressionKind)>, + ) -> Expression { + let mut lhs = Expression::new(Default::default(), lhs); + loop { + let (next_op, next_rhs) = match rest.pop() { + Some((a, b)) => (a, b), + None => break, + }; + let new_precedence = next_op.get_precedence(); + if precedence >= new_precedence { + rest.push((next_op, next_rhs)); + break; + } + let rhs = helper(new_precedence, next_rhs, rest); + lhs = Expression::new( + Default::default(), + ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)), + ); + } + lhs + } + let mut as_stack = self.next.into_iter().rev().collect(); + helper(BinOp::min_precedence(), self.first, &mut as_stack).kind + } } diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index 6d569c9..7ba4a93 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -6,9 +6,8 @@ use std::{fmt::Write, rc::Rc}; use pretty_assertions::assert_eq; -use super::{tokenize, ParseResult, Parser}; +use super::{new::schala_parser, tokenize, ParseResult, Parser}; use crate::{ast::*, tokenizing::Location}; -use super::new::schala_parser; fn rc(s: &str) -> Rc { Rc::new(s.to_owned()) @@ -108,6 +107,18 @@ macro_rules! assert_ast { }; } +macro_rules! assert_ast2 { + ($input:expr, $statements:expr) => { + let ast = schala_parser::program($input); + let expected = AST { id: Default::default(), statements: $statements.into() }; + if ast.is_err() { + println!("Parse error: {}", ast.unwrap_err()); + panic!(); + } + assert_eq!(ast.unwrap(), expected); + }; +} + macro_rules! assert_fail { ($input:expr, $failure:expr) => { let err = parse($input).unwrap_err(); @@ -124,15 +135,21 @@ macro_rules! assert_expr { macro_rules! assert_expr2 { ($input:expr, $correct:expr) => { - assert_eq!(schala_parser::expression($input).unwrap(), $correct); + let expr = schala_parser::expression($input); + if expr.is_err() { + println!("Expression parse error: {}", expr.unwrap_err()); + panic!(); + } + assert_eq!(expr.unwrap(), $correct); }; } + macro_rules! assert_fail_expr2 { ($input:expr, $failure:expr) => { let _err = schala_parser::expression($input).unwrap_err(); //TODO make real tests for failures //assert_eq!(err.to_string(), $failure); - } + }; } macro_rules! assert_fail_expr { @@ -173,17 +190,13 @@ fn binexps() { use StatementKind::Expression; assert_expr2!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); - assert_eq!( - parse("3; 4; 4.3").unwrap(), - AST { - id: Default::default(), - statements: vec![ - stmt(Expression(expr(NatLiteral(3)))), - stmt(Expression(expr(NatLiteral(4)))), - stmt(Expression(expr(FloatLiteral(4.3)))), - ] - .into() - } + assert_ast2!( + "3; 4; 4.3", + vec![ + stmt(Expression(expr(NatLiteral(3)))), + stmt(Expression(expr(NatLiteral(4)))), + stmt(Expression(expr(FloatLiteral(4.3)))), + ] ); assert_expr2!( @@ -215,21 +228,22 @@ fn binexps() { fn prefix_exps() { use ExpressionKind::*; - assert_expr!("-3", prefixop("-", expr(NatLiteral(3)))); - assert_expr!("-0.2", prefixop("-", expr(FloatLiteral(0.2)))); - assert_expr!("!3", prefixop("!", expr(NatLiteral(3)))); - assert_expr!("!t", prefixop("!", expr(Value(qn!(t))))); - assert_expr!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b)))))); - assert_expr!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b))))); + assert_expr2!("-3", prefixop("-", expr(NatLiteral(3)))); + assert_expr2!("-0.2", prefixop("-", expr(FloatLiteral(0.2)))); + assert_expr2!("!3", prefixop("!", expr(NatLiteral(3)))); + assert_expr2!("!t", prefixop("!", expr(Value(qn!(t))))); + //TODO fix + //assert_expr2!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b)))))); + assert_expr2!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b))))); } #[test] fn operators() { use ExpressionKind::*; - assert_expr!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1)))); - assert_expr!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1)))); - assert_expr!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1)))); + assert_expr2!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1)))); + assert_expr2!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1)))); + assert_expr2!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1)))); } #[test] @@ -270,12 +284,12 @@ fn accessors() { fn tuples() { use ExpressionKind::*; - assert_expr!("()", expr(TupleLiteral(vec![]))); - assert_expr!( + assert_expr2!("()", expr(TupleLiteral(vec![]))); + assert_expr2!( r#"("hella", 34)"#, expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))])) ); - assert_expr!( + assert_expr2!( r#"(1+2, "slough")"#, expr(TupleLiteral(vec![ binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), @@ -288,11 +302,11 @@ fn tuples() { fn identifiers() { use ExpressionKind::*; - assert_expr!("a", expr(Value(qn!(a)))); - assert_expr!("some_value", expr(Value(qn!(some_value)))); - assert_expr!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma)))); - assert_expr!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b))))); - assert_expr!("None", expr(Value(qn!(None)))); + assert_expr2!("a", expr(Value(qn!(a)))); + assert_expr2!("some_value", expr(Value(qn!(some_value)))); + assert_expr2!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma)))); + assert_expr2!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b))))); + assert_expr2!("None", expr(Value(qn!(None)))); assert_expr!( "thing::item::call()", expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] }) @@ -302,14 +316,14 @@ fn identifiers() { #[test] fn named_struct() { use ExpressionKind::*; - assert_expr!( + assert_expr2!( "Pandas { a: x + y }", expr(NamedStruct { name: qn!(Pandas), fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))] }) ); - assert_expr!( + assert_expr2!( "Trousers { a:1, b:800 }", expr(NamedStruct { name: qn!(Trousers), @@ -1067,7 +1081,7 @@ fn if_exprs() { }) ); - assert_expr!( + assert_expr2!( "if a then b else c", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(a))))), @@ -1110,7 +1124,7 @@ fn pattern_matching() { use ExpressionKind::*; for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] { - assert_expr!( + assert_expr2!( item, expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1123,7 +1137,7 @@ fn pattern_matching() { ); } - assert_expr!( + assert_expr2!( "if x is Something { a, b: x } then { 4 } else { 9 }", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1138,7 +1152,7 @@ fn pattern_matching() { }) ); - assert_expr!( + assert_expr2!( "if x is -1 then 1 else 2", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1150,7 +1164,7 @@ fn pattern_matching() { }) ); - assert_expr!( + assert_expr2!( "if x is true then 1 else 2", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1162,7 +1176,7 @@ fn pattern_matching() { }) ); - assert_expr!( + assert_expr2!( "if x { is 1 then 5, else 20 }", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1184,7 +1198,7 @@ fn pattern_matching() { }) ); - assert_expr!( + assert_expr2!( r#"if x is "gnosticism" then 1 else 2"#, expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), diff --git a/schala-lang/language/src/reduced_ir/mod.rs b/schala-lang/language/src/reduced_ir/mod.rs index 450e6fa..3be4ad8 100644 --- a/schala-lang/language/src/reduced_ir/mod.rs +++ b/schala-lang/language/src/reduced_ir/mod.rs @@ -247,8 +247,6 @@ impl<'a, 'b> Reducer<'a, 'b> { let mut alternatives = vec![]; for arm in condition_arms { match arm.condition { - ast::Condition::Expression(ref _expr) => - return Expression::ReductionError("case-expression".to_string()), ast::Condition::Pattern(ref pat) => { let alt = Alternative { pattern: match pat.reduce(self.symbol_table) {