From 332f83ed2dd5a050d1af145fc285003a75f39617 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sat, 18 Jul 2020 17:52:12 +0200 Subject: [PATCH] =?UTF-8?q?Some=20code=20and=20styling=20improvements=20?= =?UTF-8?q?=F0=9F=8E=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/syntax/parsing.rs | 107 ++++++++++++++++++++---------------------- src/syntax/tokens.rs | 8 ++-- 2 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index 8ebb3a29e..07dfec7cb 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -213,7 +213,7 @@ impl<'s> FuncParser<'s> { Ok(Spanned::new( FuncArg::Key(Spanned::new(Pair { key: ident, value }, span)), span, - )) + )) } else { // Add a positional argument because there was no equals // sign after the identifier that could have been a key. @@ -229,13 +229,12 @@ impl<'s> FuncParser<'s> { } }).v } - - /// Parse an expression which may contain math operands. - /// For this, this method looks for operators in - /// descending order of associativity, i.e. we first drill down to find all - /// negations, brackets and tuples, the next level, - /// we look for multiplication and division and here finally, for addition - /// and subtraction. + + /// Parse an expression which may contain math operands. For this, this + /// method looks for operators in descending order of associativity, i.e. we + /// first drill down to find all negations, brackets and tuples, the next + /// level, we look for multiplication and division and here finally, for + /// addition and subtraction. fn parse_expr(&mut self) -> Option> { let o1 = self.parse_term()?; self.parse_binop(o1, "summand", Self::parse_expr, |token| match token { @@ -258,46 +257,43 @@ impl<'s> FuncParser<'s> { &mut self, o1: Spanned, operand_name: &str, - mut parse_operand: F, + parse_operand: F, parse_op: G, ) -> Option> where - F: FnMut(&mut Self) -> Option>, + F: FnOnce(&mut Self) -> Option>, G: FnOnce(Token) -> Option>, Box>) -> Expr>, { self.skip_whitespace(); if let Some(next) = self.peek() { - let binop = match parse_op(next.v) { - Some(op) => op, - None => return Some(o1), - }; + if let Some(binop) = parse_op(next.v) { + self.eat(); + self.skip_whitespace(); - self.eat(); - self.skip_whitespace(); - - if let Some(o2) = parse_operand(self) { - let span = Span::merge(o1.span, o2.span); - let expr = binop(Box::new(o1), Box::new(o2)); - return Some(Spanned::new(expr, span)); - } else { - self.feedback.errors.push(err!( - Span::merge(next.span, o1.span); - "missing right {}", operand_name, - )); + if let Some(o2) = parse_operand(self) { + let span = Span::merge(o1.span, o2.span); + let expr = binop(Box::new(o1), Box::new(o2)); + return Some(Spanned::new(expr, span)); + } else { + self.feedback.errors.push(err!( + Span::merge(next.span, o1.span); + "missing right {}", operand_name, + )); + } } } Some(o1) } - /// Parse expressions that are of the form value or -value + /// Parse expressions that are of the form value or -value. fn parse_factor(&mut self) -> Option> { let first = self.peek()?; if first.v == Token::Hyphen { self.eat(); self.skip_whitespace(); - + if let Some(factor) = self.parse_value() { let span = Span::merge(first.span, factor.span); Some(Spanned::new(Expr::Neg(Box::new(factor)), span)) @@ -349,12 +345,12 @@ impl<'s> FuncParser<'s> { }, Token::LeftParen => { - let mut tuple = self.parse_tuple(); + let (mut tuple, can_be_coerced) = self.parse_tuple(); // Coerce 1-tuple into value - if tuple.1 && tuple.0.v.items.len() > 0 { - tuple.0.v.items.pop().expect("Length is one") + if can_be_coerced && tuple.v.items.len() > 0 { + tuple.v.items.pop().expect("length is at least one") } else { - tuple.0.map(|t| Expr::Tuple(t)) + tuple.map(|t| Expr::Tuple(t)) } }, Token::LeftBrace => self.parse_object().map(|o| Expr::Object(o)), @@ -363,15 +359,15 @@ impl<'s> FuncParser<'s> { }) } - /// Parse a tuple expression: `(, ...)`. The boolean in the return - /// values showes whether the tuple can be coerced into a single value + /// Parse a tuple expression: `(, ...)`. The boolean in the return + /// values showes whether the tuple can be coerced into a single value. fn parse_tuple(&mut self) -> (Spanned, bool) { let token = self.eat(); debug_assert_eq!(token.map(Spanned::value), Some(Token::LeftParen)); // Parse a collection until a right paren appears and complain about // missing a `value` when an invalid token is encoutered. - self.parse_collection_bracket_aware(Some(Token::RightParen), + self.parse_collection_comma_aware(Some(Token::RightParen), |p| p.parse_expr().ok_or(("value", None))) } @@ -413,12 +409,25 @@ impl<'s> FuncParser<'s> { }) } + /// Parse a comma-separated collection where each item is parsed through + /// `parse_item` until the `end` token is met. + fn parse_collection( + &mut self, + end: Option, + parse_item: F + ) -> Spanned + where + C: FromIterator>, + F: FnMut(&mut Self) -> Result, (&'static str, Option)>, + { + self.parse_collection_comma_aware(end, parse_item).0 + } + /// Parse a comma-separated collection where each item is parsed through /// `parse_item` until the `end` token is met. The first item in the return /// tuple is the collection, the second item indicates whether the - /// collection can be coerced into a single item - /// (i.e. at least one comma appeared). - fn parse_collection_bracket_aware( + /// collection can be coerced into a single item (i.e. no comma appeared). + fn parse_collection_comma_aware( &mut self, end: Option, mut parse_item: F @@ -490,20 +499,6 @@ impl<'s> FuncParser<'s> { (Spanned::new(collection, Span { start, end }), can_be_coerced) } - /// Parse a comma-separated collection where each item is parsed through - /// `parse_item` until the `end` token is met. - fn parse_collection( - &mut self, - end: Option, - parse_item: F - ) -> Spanned - where - C: FromIterator>, - F: FnMut(&mut Self) -> Result, (&'static str, Option)>, - { - self.parse_collection_bracket_aware(end, parse_item).0 - } - /// Try to parse an identifier and do nothing if the peekable token is no /// identifier. fn parse_ident(&mut self) -> Option> { @@ -665,16 +660,16 @@ mod tests { fn Str(text: &str) -> Expr { Expr::Str(text.to_string()) } fn Pt(points: f32) -> Expr { Expr::Size(Size::pt(points)) } fn Neg(e1: Expr) -> Expr { Expr::Neg(Box::new(zspan(e1))) } - fn Add(e1: Expr, e2: Expr) -> Expr { + fn Add(e1: Expr, e2: Expr) -> Expr { Expr::Add(Box::new(zspan(e1)), Box::new(zspan(e2))) } - fn Sub(e1: Expr, e2: Expr) -> Expr { + fn Sub(e1: Expr, e2: Expr) -> Expr { Expr::Sub(Box::new(zspan(e1)), Box::new(zspan(e2))) } - fn Mul(e1: Expr, e2: Expr) -> Expr { + fn Mul(e1: Expr, e2: Expr) -> Expr { Expr::Mul(Box::new(zspan(e1)), Box::new(zspan(e2))) } - fn Div(e1: Expr, e2: Expr) -> Expr { + fn Div(e1: Expr, e2: Expr) -> Expr { Expr::Div(Box::new(zspan(e1)), Box::new(zspan(e2))) } diff --git a/src/syntax/tokens.rs b/src/syntax/tokens.rs index 6642a9bfa..3b34019d9 100644 --- a/src/syntax/tokens.rs +++ b/src/syntax/tokens.rs @@ -133,9 +133,9 @@ impl<'s> Token<'s> { ExprSize(_) => "size", ExprBool(_) => "bool", ExprHex(_) => "hex value", - Plus => "plus", - Hyphen => "minus", - Slash => "slash", + Plus => "plus", + Hyphen => "minus", + Slash => "slash", Star => "star", Underscore => "underscore", Backslash => "backslash", @@ -223,7 +223,7 @@ impl<'s> Iterator for Tokens<'s> { ':' if self.mode == Header => Colon, ',' if self.mode == Header => Comma, '=' if self.mode == Header => Equals, - + // Expression operators. '+' if self.mode == Header => Plus, '-' if self.mode == Header => Hyphen,