diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index c340d9b0b..1dc47d03a 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -364,7 +364,7 @@ impl Deref for NamedTuple { #[derive(Default, Clone, PartialEq)] pub struct Object { /// The key-value pairs of the object. - pub pairs: Vec, + pub pairs: Vec>, } /// A key-value pair in an object. @@ -391,7 +391,7 @@ impl Object { } /// Add a pair to object. - pub fn add(&mut self, pair: Pair) { + pub fn add(&mut self, pair: Spanned) { self.pairs.push(pair); } @@ -401,7 +401,7 @@ impl Object { /// Inserts an error if the value does not match. If the key is not /// contained, no error is inserted. pub fn get(&mut self, errors: &mut Errors, key: &str) -> Option { - let index = self.pairs.iter().position(|pair| pair.key.v.as_str() == key)?; + let index = self.pairs.iter().position(|pair| pair.v.key.v.as_str() == key)?; self.get_index::(errors, index) } @@ -414,7 +414,7 @@ impl Object { errors: &mut Errors, ) -> Option<(K, V)> { for (index, pair) in self.pairs.iter().enumerate() { - let key = Spanned { v: pair.key.v.as_str(), span: pair.key.span }; + let key = Spanned { v: pair.v.key.v.as_str(), span: pair.v.key.span }; if let Some(key) = K::parse(key) { return self.get_index::(errors, index).map(|value| (key, value)); } @@ -432,7 +432,7 @@ impl Object { let mut index = 0; std::iter::from_fn(move || { if index < self.pairs.len() { - let key = &self.pairs[index].key; + let key = &self.pairs[index].v.key; let key = Spanned { v: key.v.as_str(), span: key.span }; Some(if let Some(key) = K::parse(key) { @@ -465,7 +465,7 @@ impl Object { /// Extract the argument at the given index and insert an error if the value /// does not match. fn get_index(&mut self, errors: &mut Errors, index: usize) -> Option { - let expr = self.pairs.remove(index).value; + let expr = self.pairs.remove(index).v.value; let span = expr.span; match V::parse(expr) { Ok(output) => Some(output), @@ -474,14 +474,14 @@ impl Object { } /// Iterate over the pairs of this object. - pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, Pair> { + pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, Spanned> { self.pairs.iter() } } impl IntoIterator for Object { - type Item = Pair; - type IntoIter = std::vec::IntoIter; + type Item = Spanned; + type IntoIter = std::vec::IntoIter>; fn into_iter(self) -> Self::IntoIter { self.pairs.into_iter() @@ -489,16 +489,16 @@ impl IntoIterator for Object { } impl<'a> IntoIterator for &'a Object { - type Item = &'a Pair; - type IntoIter = std::slice::Iter<'a, Pair>; + type Item = &'a Spanned; + type IntoIter = std::slice::Iter<'a, Spanned>; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl FromIterator for Object { - fn from_iter>(iter: I) -> Self { +impl FromIterator> for Object { + fn from_iter>>(iter: I) -> Self { Object { pairs: iter.into_iter().collect() } } } @@ -506,7 +506,7 @@ impl FromIterator for Object { impl Debug for Object { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_map() - .entries(self.pairs.iter().map(|p| (&p.key.v, &p.value.v))) + .entries(self.pairs.iter().map(|p| (&p.v.key.v, &p.v.value.v))) .finish() } } diff --git a/src/syntax/func/mod.rs b/src/syntax/func/mod.rs index 53bbc14ef..54d34531c 100644 --- a/src/syntax/func/mod.rs +++ b/src/syntax/func/mod.rs @@ -56,11 +56,11 @@ impl FuncArgs { } } -impl FromIterator for FuncArgs { - fn from_iter>(iter: I) -> Self { +impl FromIterator> for FuncArgs { + fn from_iter>>(iter: I) -> Self { let mut args = FuncArgs::new(); for item in iter.into_iter() { - args.add(item); + args.add(item.v); } args } @@ -72,7 +72,7 @@ pub enum FuncArg { /// A positional argument. Pos(Spanned), /// A keyword argument. - Key(Pair), + Key(Spanned), } impl FuncArg { @@ -83,7 +83,7 @@ impl FuncArg { pub fn span(&self) -> Span { match self { FuncArg::Pos(item) => item.span, - FuncArg::Key(Pair { key, value }) => Span::merge(key.span, value.span), + FuncArg::Key(item) => item.span, } } } diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index 1cb32263c..8ebb3a29e 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -190,10 +190,10 @@ impl<'s> FuncParser<'s> { if let Some(ident) = p.parse_ident() { // This could still be a named tuple if let Some(Token::LeftParen) = p.peekv() { - return Ok(FuncArg::Pos( - p.parse_named_tuple(ident) - .map(|t| Expr::NamedTuple(t)) - )); + let n_tuple = p.parse_named_tuple(ident) + .map(|t| Expr::NamedTuple(t)); + let span = n_tuple.span; + return Ok(Spanned::new(FuncArg::Pos(n_tuple), span)); } p.skip_whitespace(); @@ -209,16 +209,22 @@ impl<'s> FuncParser<'s> { let value = p.parse_expr().ok_or(("value", None))?; // Add a keyword argument. - Ok(FuncArg::Key(Pair { key: ident, value })) + let span = Span::merge(ident.span, value.span); + 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. - Ok(FuncArg::Pos(ident.map(|id| Expr::Ident(id)))) + let ident = ident.map(|id| Expr::Ident(id)); + let span = ident.span; + Ok(Spanned::new(FuncArg::Pos(ident), span)) } } else { // Add a positional argument because we haven't got an // identifier that could be an argument key. - p.parse_expr().map(|expr| FuncArg::Pos(expr)) + p.parse_expr().map(|expr| Spanned { span: expr.span, v: FuncArg::Pos(expr) }) .ok_or(("argument", None)) } }).v @@ -231,78 +237,58 @@ impl<'s> FuncParser<'s> { /// we look for multiplication and division and here finally, for addition /// and subtraction. fn parse_expr(&mut self) -> Option> { - let term = self.parse_term()?; - self.skip_whitespace(); - - if let Some(next) = self.peek() { - match next.v { - Token::Plus | Token::Hyphen => { - self.eat(); - self.skip_whitespace(); - let o2 = self.parse_expr(); - if o2.is_none() { - self.feedback.errors.push(err!( - Span::merge(next.span, term.span); - "Missing right summand" - )); - return Some(term) - } - - let o2 = o2.expect("Checked for None before"); - let span = Span::merge(term.span, o2.span); - match next.v { - Token::Plus => Some(Spanned::new( - Expr::Add(Box::new(term), Box::new(o2)), span - )), - Token::Hyphen => Some(Spanned::new( - Expr::Sub(Box::new(term), Box::new(o2)), span - )), - _ => unreachable!(), - } - }, - _ => Some(term) - } - } else { - Some(term) - } + let o1 = self.parse_term()?; + self.parse_binop(o1, "summand", Self::parse_expr, |token| match token { + Token::Plus => Some(Expr::Add), + Token::Hyphen => Some(Expr::Sub), + _ => None, + }) } fn parse_term(&mut self) -> Option> { - // TODO: Deduplicate code here - let factor = self.parse_factor()?; + let o1 = self.parse_factor()?; + self.parse_binop(o1, "factor", Self::parse_term, |token| match token { + Token::Star => Some(Expr::Mul), + Token::Slash => Some(Expr::Div), + _ => None, + }) + } + + fn parse_binop( + &mut self, + o1: Spanned, + operand_name: &str, + mut parse_operand: F, + parse_op: G, + ) -> Option> + where + F: FnMut(&mut Self) -> Option>, + G: FnOnce(Token) -> Option>, Box>) -> Expr>, + { self.skip_whitespace(); if let Some(next) = self.peek() { - match next.v { - Token::Star | Token::Slash => { - self.eat(); - self.skip_whitespace(); - let o2 = self.parse_term(); - if o2.is_none() { - self.feedback.errors.push(err!( - Span::merge(next.span, factor.span); - "Missing right factor" - )); - return Some(factor) - } + let binop = match parse_op(next.v) { + Some(op) => op, + None => return Some(o1), + }; - let o2 = o2.expect("Checked for None before"); - let span = Span::merge(factor.span, o2.span); - match next.v { - Token::Star => Some(Spanned::new( - Expr::Mul(Box::new(factor), Box::new(o2)), span - )), - Token::Slash => Some(Spanned::new( - Expr::Div(Box::new(factor), Box::new(o2)), span - )), - _ => unreachable!(), - } - }, - _ => Some(factor) + 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, + )); } - } else { - Some(factor) } + + Some(o1) } /// Parse expressions that are of the form value or -value @@ -310,16 +296,15 @@ impl<'s> FuncParser<'s> { let first = self.peek()?; if first.v == Token::Hyphen { self.eat(); - let o2 = self.parse_value(); self.skip_whitespace(); - if o2.is_none() { - self.feedback.errors.push(err!(first.span; "Dangling minus")); - return None + + if let Some(factor) = self.parse_value() { + let span = Span::merge(first.span, factor.span); + Some(Spanned::new(Expr::Neg(Box::new(factor)), span)) + } else { + self.feedback.errors.push(err!(first.span; "dangling minus")); + None } - - let o2 = o2.expect("Checked for None before"); - let span = Span::merge(first.span, o2.span); - Some(Spanned::new(Expr::Neg(Box::new(o2)), span)) } else { self.parse_value() } @@ -423,7 +408,8 @@ impl<'s> FuncParser<'s> { let value = p.parse_expr().ok_or(("value", None))?; - Ok(Pair { key, value }) + let span = Span::merge(key.span, value.span); + Ok(Spanned::new(Pair { key, value }, span)) }) } @@ -438,8 +424,8 @@ impl<'s> FuncParser<'s> { mut parse_item: F ) -> (Spanned, bool) where - C: FromIterator, - F: FnMut(&mut Self) -> Result)>, + C: FromIterator>, + F: FnMut(&mut Self) -> Result, (&'static str, Option)>, { let start = self.pos(); let mut can_be_coerced = true; @@ -469,7 +455,6 @@ impl<'s> FuncParser<'s> { Ok(item) => { // Expect a comma behind the item (only separated by // whitespace). - let behind_item = self.pos(); self.skip_whitespace(); match self.peekv() { Some(Token::Comma) => { @@ -478,7 +463,7 @@ impl<'s> FuncParser<'s> { } t @ Some(_) if t != end => { can_be_coerced = false; - self.expected_at("comma", behind_item); + self.expected_at("comma", item.span.end); }, _ => {} } @@ -513,8 +498,8 @@ impl<'s> FuncParser<'s> { parse_item: F ) -> Spanned where - C: FromIterator, - F: FnMut(&mut Self) -> Result)>, + C: FromIterator>, + F: FnMut(&mut Self) -> Result, (&'static str, Option)>, { self.parse_collection_bracket_aware(end, parse_item).0 } @@ -735,10 +720,10 @@ mod tests { macro_rules! object { ($($key:expr => $value:expr),* $(,)?) => { Expr::Object(Object { - pairs: vec![$(Pair { + pairs: vec![$(zspan(Pair { key: zspan(Ident($key.to_string())), value: zspan($value), - }),*] + })),*] }) }; } @@ -995,9 +980,20 @@ mod tests { Sub(Div(Num(5.0), Num(2.0)), Num(1.0)) ) ), {})]); - p!("[val: (6.3E+2+4*-3.2pt)/2]" => [func!("val": ( + p!("[val: (6.3E+2+4* - 3.2pt)/2]" => [func!("val": ( Div(Add(Num(6.3e2),Mul(Num(4.0), Neg(Pt(3.2)))), Num(2.0)) ), {})]); + p!("[val: 4pt--]" => + [func!("val": (Pt(4.0)), {})], + [ + (0:10, 0:11, "dangling minus"), + (0:6, 0:10, "missing right summand") + ], + ); + p!("[val: 3mm+4pt*]" => + [func!("val": (Add(Sz(Size::mm(3.0)), Pt(4.0))), {})], + [(0:10, 0:14, "missing right factor")], + ); } #[test] diff --git a/src/syntax/test.rs b/src/syntax/test.rs index 109b5ef6d..47680487b 100644 --- a/src/syntax/test.rs +++ b/src/syntax/test.rs @@ -152,7 +152,7 @@ impl SpanlessEq for Object { fn spanless_eq(&self, other: &Object) -> bool { self.pairs.len() == other.pairs.len() && self.pairs.iter().zip(&other.pairs) - .all(|(x, y)| x.key.v == y.key.v && x.value.v.spanless_eq(&y.value.v)) + .all(|(x, y)| x.v.key.v == y.v.key.v && x.v.value.v.spanless_eq(&y.v.value.v)) } }