From fa7b6ce96b1aa0cc57d01dfeb76c53d5d5e74132 Mon Sep 17 00:00:00 2001 From: greg Date: Tue, 21 Aug 2018 19:57:45 -0700 Subject: [PATCH] Handle negatives in patterns correctly --- schala-lang/src/ast.rs | 5 +++- schala-lang/src/parsing.rs | 55 ++++++++++++++++++++++++++++++---- schala-lang/src/reduced_ast.rs | 4 +-- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/schala-lang/src/ast.rs b/schala-lang/src/ast.rs index 17fe965..8832c04 100644 --- a/schala-lang/src/ast.rs +++ b/schala-lang/src/ast.rs @@ -157,7 +157,10 @@ pub enum Pattern { #[derive(Debug, PartialEq, Clone)] pub enum PatternLiteral { - NumPattern(ExpressionType), //TODO fix + NumPattern { + neg: bool, + num: ExpressionType, + }, StringPattern(Rc), BoolPattern(bool), VarPattern(Rc) diff --git a/schala-lang/src/parsing.rs b/schala-lang/src/parsing.rs index 505e530..8e7d125 100644 --- a/schala-lang/src/parsing.rs +++ b/schala-lang/src/parsing.rs @@ -235,7 +235,8 @@ digits := (DIGIT_GROUP underscore)+ /* Pattern syntax */ pattern := '(' (pattern, ',')* ')' | simple_pattern simple_pattern := pattern_literal | record_pattern | tuple_struct_pattern -pattern_literal := 'true' | 'false' | number_literal | STR_LITERAL | IDENTIFIER +pattern_literal := 'true' | 'false' | signed_number_literal | STR_LITERAL | IDENTIFIER +signed_number_literal := '-'? number_literal record_pattern := IDENTIFIER '{' (record_pattern_entry, ',')* '}' record_pattern_entry := IDENTIFIER | IDENTIFIER ':' Pattern tuple_struct_pattern := IDENTIFIER '(' (pattern, ',')* ')' @@ -735,14 +736,12 @@ impl Parser { _ => Pattern::Literal(PatternLiteral::VarPattern(id)) } }, + //TODO I think these are buggy b/c they don't advance the parser Keyword(Kw::True) => Pattern::Literal(PatternLiteral::BoolPattern(true)), Keyword(Kw::False) => Pattern::Literal(PatternLiteral::BoolPattern(false)), StrLiteral(s) => Pattern::Literal(PatternLiteral::StringPattern(s)), - DigitGroup(_) | HexLiteral(_) | BinNumberSigil | Period => { - //TODO handle negatives - let Expression(expr_type, _) = self.number_literal()?; - Pattern::Literal(PatternLiteral::NumPattern(expr_type)) - }, + DigitGroup(_) | HexLiteral(_) | BinNumberSigil | Period => self.signed_number_literal()?, + Operator(ref op) if **op == "-" => self.signed_number_literal()?, Underscore => { self.next(); Pattern::Ignored @@ -751,6 +750,18 @@ impl Parser { }) }); + parse_method!(signed_number_literal(&mut self) -> ParseResult { + let neg = match self.peek() { + Operator(ref op) if **op == "-" => { + self.next(); + true + }, + _ => false + }; + let Expression(expr_type, _) = self.number_literal()?; + Ok(Pattern::Literal(PatternLiteral::NumPattern { neg, num: expr_type })) + }); + parse_method!(record_pattern_entry(&mut self) -> ParseResult<(Rc, Pattern)> { let name = self.identifier()?; Ok(match self.peek() { @@ -1439,5 +1450,37 @@ fn a(x) { ) ]) } + + parse_test! { + "if x is -1 then 1 else 2", AST(vec![ + exprstatement!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(Value(rc!(x))))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: NatLiteral(1) }), + vec![exprstatement!(NatLiteral(1))], + Some(vec![exprstatement!(NatLiteral(2))]), + )) + } + ) + ]) + } + + parse_test! { + "if x is 1 then 1 else 2", AST(vec![ + exprstatement!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(Value(rc!(x))))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(1) }), + vec![exprstatement!(NatLiteral(1))], + Some(vec![exprstatement!(NatLiteral(2))]), + )) + } + ) + ]) + } + + } } diff --git a/schala-lang/src/reduced_ast.rs b/schala-lang/src/reduced_ast.rs index 54999e6..346447d 100644 --- a/schala-lang/src/reduced_ast.rs +++ b/schala-lang/src/reduced_ast.rs @@ -173,7 +173,7 @@ fn reduce_if_expression(discriminator: &Discriminator, body: &IfExpressionBody, item: then_clause, } }, - _ => panic!() + e => { println!("SAW {:?}", e); panic!() } }; let alternatives = vec![ @@ -196,7 +196,7 @@ fn reduce_if_expression(discriminator: &Discriminator, body: &IfExpressionBody, Guard::Pat(ref p) => match p { Pattern::Ignored => (None, vec![]), Pattern::Literal(lit) => match lit { - PatternLiteral::NumPattern(_expr) => unimplemented!(), + PatternLiteral::NumPattern { neg, num } => unimplemented!(), PatternLiteral::StringPattern(_s) => unimplemented!(), PatternLiteral::BoolPattern(_b) => unimplemented!(), PatternLiteral::VarPattern(_var) => unimplemented!(),