diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-08-02 16:31:34 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-08-02 16:31:34 +0200 |
| commit | 533374db14087ac54fdc86afa5f009487ac1b850 (patch) | |
| tree | 0970eb1ca893fe45369d622b5bc1f226f0f66004 /src/syntax/expr.rs | |
| parent | 2188ef6b899cc10c84ed985e9ad9049fcc3eb662 (diff) | |
Refactor argument parsing 🔬
Diffstat (limited to 'src/syntax/expr.rs')
| -rw-r--r-- | src/syntax/expr.rs | 242 |
1 files changed, 62 insertions, 180 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index 51daf304..a551c2b6 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -1,16 +1,15 @@ //! Expressions in function headers. use std::fmt::{self, Debug, Formatter}; -use std::iter::FromIterator; use std::ops::Deref; use std::str::FromStr; use std::u8; -use crate::diagnostic::Diagnostics; +use crate::Feedback; use crate::length::Length; -use super::func::{Key, Value}; -use super::span::{Span, Spanned}; +use super::span::Spanned; use super::tokens::is_identifier; +use super::value::Value; /// An argument or return value. #[derive(Clone, PartialEq)] @@ -238,103 +237,63 @@ impl fmt::Display for ParseColorError { /// (false, 12cm, "hi") /// ``` #[derive(Default, Clone, PartialEq)] -pub struct Tuple { - /// The elements of the tuple. - pub items: Vec<Spanned<Expr>>, -} +pub struct Tuple(pub Vec<Spanned<Expr>>); impl Tuple { /// Create an empty tuple. pub fn new() -> Tuple { - Tuple { items: vec![] } + Tuple(vec![]) } /// Add an element. - pub fn add(&mut self, item: Spanned<Expr>) { - self.items.push(item); + pub fn push(&mut self, item: Spanned<Expr>) { + self.0.push(item); } - /// Extract (and remove) the first matching value and remove and generate - /// diagnostics for all previous items that did not match. - pub fn get<V: Value>(&mut self, diagnostics: &mut Diagnostics) -> Option<V> { - while !self.items.is_empty() { - let expr = self.items.remove(0); - let span = expr.span; - match V::parse(expr) { - Ok(output) => return Some(output), - Err(v) => diagnostics.push(Spanned { v, span }), + /// Expect a specific value type and generate errors for every argument + /// until an argument of the value type is found. + pub fn expect<V: Value>(&mut self, f: &mut Feedback) -> Option<V> { + while !self.0.is_empty() { + let item = self.0.remove(0); + if let Some(val) = V::parse(item, f) { + return Some(val); } } None } - /// Extract (and remove) the first matching value without removing and - /// generating diagnostics for all previous items that did not match. - pub fn get_first<V: Value>(&mut self, _: &mut Diagnostics) -> Option<V> { - let mut i = 0; - while i < self.items.len() { - let expr = self.items[i].clone(); - match V::parse(expr) { - Ok(output) => { - self.items.remove(i); - return Some(output) - } - Err(_) => {}, + /// Extract the first argument of the value type if there is any. + pub fn get<V: Value>(&mut self) -> Option<V> { + for (i, item) in self.0.iter().enumerate() { + if let Some(val) = V::parse(item.clone(), &mut Feedback::new()) { + self.0.remove(i); + return Some(val); } - i += 1; } - None } - /// Extract and return an iterator over all values that match and generate - /// diagnostics for all items that do not match. - pub fn get_all<'a, V: Value>(&'a mut self, diagnostics: &'a mut Diagnostics) - -> impl Iterator<Item=V> + 'a { - self.items.drain(..).filter_map(move |expr| { - let span = expr.span; - match V::parse(expr) { - Ok(output) => Some(output), - Err(v) => { diagnostics.push(Spanned { v, span }); None } + /// Extract all arguments of the value type. + pub fn all<'a, V: Value>(&'a mut self) -> impl Iterator<Item = V> + 'a { + let mut i = 0; + std::iter::from_fn(move || { + while i < self.0.len() { + let val = V::parse(self.0[i].clone(), &mut Feedback::new()); + if val.is_some() { + self.0.remove(i); + return val; + } else { + i += 1; + } } + None }) } - - /// Iterate over the items of this tuple. - pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, Spanned<Expr>> { - self.items.iter() - } -} - -impl IntoIterator for Tuple { - type Item = Spanned<Expr>; - type IntoIter = std::vec::IntoIter<Spanned<Expr>>; - - fn into_iter(self) -> Self::IntoIter { - self.items.into_iter() - } -} - -impl<'a> IntoIterator for &'a Tuple { - type Item = &'a Spanned<Expr>; - type IntoIter = std::slice::Iter<'a, Spanned<Expr>>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl FromIterator<Spanned<Expr>> for Tuple { - fn from_iter<I: IntoIterator<Item=Spanned<Expr>>>(iter: I) -> Self { - Tuple { items: iter.into_iter().collect() } - } } impl Debug for Tuple { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_list() - .entries(&self.items) - .finish() + f.debug_list().entries(&self.0).finish() } } @@ -374,10 +333,7 @@ impl Deref for NamedTuple { /// { fit: false, width: 12cm, items: (1, 2, 3) } /// ``` #[derive(Default, Clone, PartialEq)] -pub struct Object { - /// The key-value pairs of the object. - pub pairs: Vec<Spanned<Pair>>, -} +pub struct Object(pub Vec<Spanned<Pair>>); /// A key-value pair in an object. #[derive(Debug, Clone, PartialEq)] @@ -399,126 +355,52 @@ pub struct Pair { impl Object { /// Create an empty object. pub fn new() -> Object { - Object { pairs: vec![] } + Object(vec![]) } /// Add a pair to object. - pub fn add(&mut self, pair: Spanned<Pair>) { - self.pairs.push(pair); - } - - /// Extract (and remove) a pair with the given key string and matching - /// value. - /// - /// Inserts an error if the value does not match. If the key is not - /// contained, no error is inserted. - pub fn get<V: Value>(&mut self, diagnostics: &mut Diagnostics, key: &str) -> Option<V> { - let index = self.pairs.iter().position(|pair| pair.v.key.v.as_str() == key)?; - self.get_index::<V>(diagnostics, index) + pub fn push(&mut self, pair: Spanned<Pair>) { + self.0.push(pair); } - /// Extract (and remove) a pair with a matching key and value. + /// Extract an argument with the given key if there is any. /// - /// Inserts an error if the value does not match. If no matching key is - /// found, no error is inserted. - pub fn get_with_key<K: Key, V: Value>( - &mut self, - diagnostics: &mut Diagnostics, - ) -> Option<(K, V)> { - for (index, pair) in self.pairs.iter().enumerate() { - 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::<V>(diagnostics, index).map(|value| (key, value)); + /// Generates an error if there is a matching key, but the value is of the + /// wrong type. + pub fn get<V: Value>(&mut self, key: &str, f: &mut Feedback) -> Option<V> { + for (i, pair) in self.0.iter().enumerate() { + if pair.v.key.v.as_str() == key { + let pair = self.0.remove(i); + return V::parse(pair.v.value, f); } } None } - /// Extract (and remove) all pairs with matching keys and values. - /// - /// Inserts errors for values that do not match. - pub fn get_all<'a, K: Key, V: Value>( - &'a mut self, - diagnostics: &'a mut Diagnostics, - ) -> impl Iterator<Item=(K, V)> + 'a { - let mut index = 0; + /// Extract all key-value pairs where the value is of the given type. + pub fn all<'a, V: Value>(&'a mut self) + -> impl Iterator<Item = (Spanned<Ident>, V)> + 'a + { + let mut i = 0; std::iter::from_fn(move || { - if index < self.pairs.len() { - 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) { - self.get_index::<V>(diagnostics, index).map(|v| (key, v)) - } else { - index += 1; - None - }) - } else { - None + while i < self.0.len() { + let val = V::parse(self.0[i].v.value.clone(), &mut Feedback::new()); + if let Some(val) = val { + let pair = self.0.remove(i); + return Some((pair.v.key, val)); + } else { + i += 1; + } } - }).filter_map(|x| x) - } - - /// Extract all key value pairs with span information. - /// - /// The spans are over both key and value, like so: - /// ```typst - /// { key: value } - /// ^^^^^^^^^^ - /// ``` - pub fn get_all_spanned<'a, K: Key + 'a, V: Value + 'a>( - &'a mut self, - diagnostics: &'a mut Diagnostics, - ) -> impl Iterator<Item=Spanned<(K, V)>> + 'a { - self.get_all::<Spanned<K>, Spanned<V>>(diagnostics) - .map(|(k, v)| Spanned::new((k.v, v.v), Span::merge(k.span, v.span))) - } - - /// Extract the argument at the given index and insert an error if the value - /// does not match. - fn get_index<V: Value>(&mut self, diagnostics: &mut Diagnostics, index: usize) -> Option<V> { - let expr = self.pairs.remove(index).v.value; - let span = expr.span; - match V::parse(expr) { - Ok(output) => Some(output), - Err(v) => { diagnostics.push(Spanned { v, span }); None } - } - } - - /// Iterate over the pairs of this object. - pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, Spanned<Pair>> { - self.pairs.iter() - } -} - -impl IntoIterator for Object { - type Item = Spanned<Pair>; - type IntoIter = std::vec::IntoIter<Spanned<Pair>>; - - fn into_iter(self) -> Self::IntoIter { - self.pairs.into_iter() - } -} - -impl<'a> IntoIterator for &'a Object { - type Item = &'a Spanned<Pair>; - type IntoIter = std::slice::Iter<'a, Spanned<Pair>>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl FromIterator<Spanned<Pair>> for Object { - fn from_iter<I: IntoIterator<Item=Spanned<Pair>>>(iter: I) -> Self { - Object { pairs: iter.into_iter().collect() } + None + }) } } impl Debug for Object { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_map() - .entries(self.pairs.iter().map(|p| (&p.v.key.v, &p.v.value.v))) + .entries(self.0.iter().map(|p| (&p.v.key.v, &p.v.value.v))) .finish() } } |
