diff options
Diffstat (limited to 'src/syntax/expr.rs')
| -rw-r--r-- | src/syntax/expr.rs | 230 |
1 files changed, 125 insertions, 105 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index 34a1c6bf..fe24c655 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -1,4 +1,3 @@ -use crate::size::ScaleSize; use super::*; @@ -22,30 +21,13 @@ impl Expr { Str(_) => "string", Number(_) => "number", Size(_) => "size", - Bool(_) => "boolean", + Bool(_) => "bool", Tuple(_) => "tuple", Object(_) => "object", } } } -impl Display for Expr { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use Expr::*; - match self { - Ident(i) => write!(f, "{}", i), - Str(s) => write!(f, "{:?}", s), - Number(n) => write!(f, "{}", n), - Size(s) => write!(f, "{}", s), - Bool(b) => write!(f, "{}", b), - Tuple(t) => write!(f, "{}", t), - Object(o) => write!(f, "{}", o), - } - } -} - -debug_display!(Expr); - /// An identifier. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Ident(pub String); @@ -64,17 +46,6 @@ impl Ident { } } -impl Display for Ident { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -debug_display!(Ident); - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct StringLike(pub String); - /// A sequence of expressions. #[derive(Clone, PartialEq)] pub struct Tuple { @@ -89,27 +60,31 @@ impl Tuple { pub fn add(&mut self, item: Spanned<Expr>) { self.items.push(item); } -} - -impl Display for Tuple { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "(")?; - let mut first = true; - for item in &self.items { - if !first { - write!(f, ", ")?; + pub fn get<V: Value>(&mut self, errors: &mut Errors) -> Option<V::Output> { + 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(err) => errors.push(Spanned { v: err, span }), } - write!(f, "{}", item.v)?; - first = false; } + None + } - write!(f, ")") + pub fn get_all<'a, V: Value>(&'a mut self, errors: &'a mut Errors) + -> impl Iterator<Item=V::Output> + 'a { + self.items.drain(..).filter_map(move |expr| { + let span = expr.span; + match V::parse(expr) { + Ok(output) => Some(output), + Err(err) => { errors.push(Spanned { v: err, span }); None } + } + }) } } -debug_display!(Tuple); - /// A key-value collection of identifiers and associated expressions. #[derive(Clone, PartialEq)] pub struct Object { @@ -128,6 +103,108 @@ impl Object { pub fn add_pair(&mut self, pair: Pair) { self.pairs.push(pair); } + + pub fn get<V: Value>(&mut self, errors: &mut Errors, key: &str) -> Option<V::Output> { + let index = self.pairs.iter().position(|pair| pair.key.v.as_str() == key)?; + self.get_index::<V>(errors, index) + } + + pub fn get_with_key<K: Key, V: Value>( + &mut self, + errors: &mut Errors, + ) -> Option<(K::Output, V::Output)> { + for (index, pair) in self.pairs.iter().enumerate() { + let key = Spanned { v: pair.key.v.as_str(), span: pair.key.span }; + if let Some(key) = K::parse(key) { + return self.get_index::<V>(errors, index).map(|value| (key, value)); + } + } + None + } + + pub fn get_all<'a, K: Key, V: Value>( + &'a mut self, + errors: &'a mut Errors, + ) -> impl Iterator<Item=(K::Output, V::Output)> + 'a { + let mut index = 0; + std::iter::from_fn(move || { + if index < self.pairs.len() { + let key = &self.pairs[index].key; + let key = Spanned { v: key.v.as_str(), span: key.span }; + + Some(if let Some(key) = K::parse(key) { + self.get_index::<V>(errors, index).map(|v| (key, v)) + } else { + index += 1; + None + }) + } else { + None + } + }).filter_map(|x| x) + } + + pub fn get_all_spanned<'a, K: Key + 'a, V: Value + 'a>( + &'a mut self, + errors: &'a mut Errors, + ) -> impl Iterator<Item=Spanned<(K::Output, V::Output)>> + 'a { + self.get_all::<Spanned<K>, Spanned<V>>(errors) + .map(|(k, v)| Spanned::new((k.v, v.v), Span::merge(k.span, v.span))) + } + + fn get_index<V: Value>(&mut self, errors: &mut Errors, index: usize) -> Option<V::Output> { + let expr = self.pairs.remove(index).value; + let span = expr.span; + match V::parse(expr) { + Ok(output) => Some(output), + Err(err) => { errors.push(Spanned { v: err, span }); None } + } + } +} + +/// A key-value pair in an object. +#[derive(Clone, PartialEq)] +pub struct Pair { + pub key: Spanned<Ident>, + pub value: Spanned<Expr>, +} + +impl Display for Expr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + use Expr::*; + match self { + Ident(i) => write!(f, "{}", i), + Str(s) => write!(f, "{:?}", s), + Number(n) => write!(f, "{}", n), + Size(s) => write!(f, "{}", s), + Bool(b) => write!(f, "{}", b), + Tuple(t) => write!(f, "{}", t), + Object(o) => write!(f, "{}", o), + } + } +} + +impl Display for Ident { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Display for Tuple { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "(")?; + + let mut first = true; + for item in &self.items { + if !first { + write!(f, ", ")?; + } + write!(f, "{}", item.v)?; + first = false; + } + + write!(f, ")") + } } impl Display for Object { @@ -151,71 +228,14 @@ impl Display for Object { } } -debug_display!(Object); - -/// A key-value pair in an object. -#[derive(Clone, PartialEq)] -pub struct Pair { - pub key: Spanned<Ident>, - pub value: Spanned<Expr>, -} - impl Display for Pair { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}: {}", self.key.v, self.value.v) } } +debug_display!(Expr); +debug_display!(Ident); +debug_display!(Tuple); +debug_display!(Object); debug_display!(Pair); - -pub trait ExprKind: Sized { - /// The name of the expression in an `expected <name>` error. - const NAME: &'static str; - - /// Create from expression. - fn from_expr(expr: Spanned<Expr>) -> Result<Self, Error>; -} - -impl<T> ExprKind for Spanned<T> where T: ExprKind { - const NAME: &'static str = T::NAME; - - fn from_expr(expr: Spanned<Expr>) -> Result<Self, Error> { - let span = expr.span; - T::from_expr(expr).map(|v| Spanned { v, span }) - } -} -/// Implements the expression kind trait for a type. -macro_rules! kind { - ($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => { - impl ExprKind for $type { - const NAME: &'static str = $name; - - fn from_expr(expr: Spanned<Expr>) -> Result<Self, Error> { - #[allow(unreachable_patterns)] - Ok(match expr.v { - $($p => $r),*, - _ => return Err( - err!("expected {}, found {}", Self::NAME, expr.v.name()) - ), - }) - } - } - }; -} - -kind!(Expr, "expression", e => e); -kind!(Ident, "identifier", Expr::Ident(i) => i); -kind!(String, "string", Expr::Str(s) => s); -kind!(f64, "number", Expr::Number(n) => n); -kind!(bool, "boolean", Expr::Bool(b) => b); -kind!(Size, "size", Expr::Size(s) => s); -kind!(Tuple, "tuple", Expr::Tuple(t) => t); -kind!(Object, "object", Expr::Object(o) => o); -kind!(ScaleSize, "number or size", - Expr::Size(size) => ScaleSize::Absolute(size), - Expr::Number(scale) => ScaleSize::Scaled(scale as f32), -); -kind!(StringLike, "identifier or string", - Expr::Ident(Ident(s)) => StringLike(s), - Expr::Str(s) => StringLike(s), -); |
