diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-02-10 10:29:17 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-02-10 10:29:17 +0100 |
| commit | 624471db619240f0eed849b92dff6a525ce7e547 (patch) | |
| tree | b6218c031019a78a99c7bb99fcbbe40918e6f2d7 | |
| parent | 6e198bf7606847b0847487a4847d6a3ee3621d2d (diff) | |
Proper error messages for shorthands
| -rw-r--r-- | macros/src/lib.rs | 19 | ||||
| -rw-r--r-- | src/eval/func.rs | 44 | ||||
| -rw-r--r-- | src/eval/value.rs | 6 | ||||
| -rw-r--r-- | src/library/align.rs | 2 | ||||
| -rw-r--r-- | src/library/container.rs | 4 | ||||
| -rw-r--r-- | src/library/grid.rs | 2 | ||||
| -rw-r--r-- | src/library/link.rs | 2 | ||||
| -rw-r--r-- | src/library/list.rs | 3 | ||||
| -rw-r--r-- | src/library/pad.rs | 2 | ||||
| -rw-r--r-- | src/library/page.rs | 2 | ||||
| -rw-r--r-- | src/library/place.rs | 2 | ||||
| -rw-r--r-- | src/library/shape.rs | 2 | ||||
| -rw-r--r-- | src/library/stack.rs | 2 | ||||
| -rw-r--r-- | src/library/table.rs | 2 | ||||
| -rw-r--r-- | src/library/transform.rs | 6 | ||||
| -rw-r--r-- | src/library/utility.rs | 6 |
16 files changed, 53 insertions, 53 deletions
diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 0757a201..ab9fbf1b 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -56,20 +56,23 @@ fn expand(mut impl_block: syn::ItemImpl) -> Result<TokenStream2> { let name = property.name; let string = name.to_string().replace("_", "-").to_lowercase(); - let alternative = if property.variadic { + let value = if property.variadic { quote! { - .or_else(|| { - let list: Vec<_> = args.all().collect(); - (!list.is_empty()).then(|| list) - }) + match args.named(#string)? { + Some(value) => value, + None => { + let list: Vec<_> = args.all()?; + (!list.is_empty()).then(|| list) + } + } } } else if property.shorthand { - quote! { .or_else(|| args.find()) } + quote! { args.named_or_find(#string)? } } else { - quote! {} + quote! { args.named(#string)? } }; - quote! { styles.set_opt(Self::#name, args.named(#string)? #alternative); } + quote! { styles.set_opt(Self::#name, #value); } }); parse_quote! { diff --git a/src/eval/func.rs b/src/eval/func.rs index 6d405ca4..887f7989 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -162,10 +162,7 @@ impl Args { /// /// Returns a `missing argument: {what}` error if no positional argument is /// left. - pub fn expect<T>(&mut self, what: &str) -> TypResult<T> - where - T: Cast<Spanned<Value>>, - { + pub fn expect<T: Cast>(&mut self, what: &str) -> TypResult<T> { match self.eat()? { Some(v) => Ok(v), None => bail!(self.span, "missing argument: {}", what), @@ -173,10 +170,7 @@ impl Args { } /// Consume and cast the first positional argument if there is one. - pub fn eat<T>(&mut self) -> TypResult<Option<T>> - where - T: Cast<Spanned<Value>>, - { + pub fn eat<T: Cast>(&mut self) -> TypResult<Option<T>> { for (i, slot) in self.items.iter().enumerate() { if slot.name.is_none() { let value = self.items.remove(i).value; @@ -188,33 +182,29 @@ impl Args { } /// Find and consume the first castable positional argument. - pub fn find<T>(&mut self) -> Option<T> - where - T: Cast<Spanned<Value>>, - { + pub fn find<T: Cast>(&mut self) -> TypResult<Option<T>> { for (i, slot) in self.items.iter().enumerate() { if slot.name.is_none() && T::is(&slot.value) { let value = self.items.remove(i).value; - return T::cast(value).ok(); + let span = value.span; + return T::cast(value).at(span).map(Some); } } - None + Ok(None) } /// Find and consume all castable positional arguments. - pub fn all<T>(&mut self) -> impl Iterator<Item = T> + '_ - where - T: Cast<Spanned<Value>>, - { - std::iter::from_fn(move || self.find()) + pub fn all<T: Cast>(&mut self) -> TypResult<Vec<T>> { + let mut list = vec![]; + while let Some(value) = self.find()? { + list.push(value); + } + Ok(list) } /// Cast and remove the value for the given named argument, returning an /// error if the conversion fails. - pub fn named<T>(&mut self, name: &str) -> TypResult<Option<T>> - where - T: Cast<Spanned<Value>>, - { + pub fn named<T: Cast>(&mut self, name: &str) -> TypResult<Option<T>> { // We don't quit once we have a match because when multiple matches // exist, we want to remove all of them and use the last one. let mut i = 0; @@ -231,6 +221,14 @@ impl Args { Ok(found) } + /// Same as named, but with fallback to find. + pub fn named_or_find<T: Cast>(&mut self, name: &str) -> TypResult<Option<T>> { + match self.named(name)? { + Some(value) => Ok(Some(value)), + None => self.find(), + } + } + /// Take out all arguments into a new instance. pub fn take(&mut self) -> Self { Self { diff --git a/src/eval/value.rs b/src/eval/value.rs index 2d37b34f..d1f0be76 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -284,7 +284,7 @@ pub trait Type { } /// Cast from a value to a specific type. -pub trait Cast<V>: Sized { +pub trait Cast<V = Spanned<Value>>: Sized { /// Check whether the value is castable to `Self`. fn is(value: &V) -> bool; @@ -415,7 +415,7 @@ impl Cast<Value> for Value { } } -impl<T> Cast<Spanned<Value>> for T +impl<T> Cast for T where T: Cast<Value>, { @@ -428,7 +428,7 @@ where } } -impl<T> Cast<Spanned<Value>> for Spanned<T> +impl<T> Cast for Spanned<T> where T: Cast<Value>, { diff --git a/src/library/align.rs b/src/library/align.rs index 5dc12938..1fb91138 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -15,7 +15,7 @@ pub struct AlignNode { #[class] impl AlignNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { - let aligns: Spec<_> = args.find().unwrap_or_default(); + let aligns: Spec<_> = args.find()?.unwrap_or_default(); let body: LayoutNode = args.expect("body")?; Ok(Template::block(body.aligned(aligns))) } diff --git a/src/library/container.rs b/src/library/container.rs index 143bddfc..382be262 100644 --- a/src/library/container.rs +++ b/src/library/container.rs @@ -10,7 +10,7 @@ impl BoxNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { let width = args.named("width")?; let height = args.named("height")?; - let body: LayoutNode = args.find().unwrap_or_default(); + let body: LayoutNode = args.find()?.unwrap_or_default(); Ok(Template::inline(body.sized(Spec::new(width, height)))) } } @@ -21,6 +21,6 @@ pub struct BlockNode; #[class] impl BlockNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { - Ok(Template::Block(args.find().unwrap_or_default())) + Ok(Template::Block(args.find()?.unwrap_or_default())) } } diff --git a/src/library/grid.rs b/src/library/grid.rs index f85e5d56..c9904a5f 100644 --- a/src/library/grid.rs +++ b/src/library/grid.rs @@ -27,7 +27,7 @@ impl GridNode { column_gutter.unwrap_or_else(|| base_gutter.clone()), row_gutter.unwrap_or(base_gutter), ), - children: args.all().collect(), + children: args.all()?, })) } } diff --git a/src/library/link.rs b/src/library/link.rs index a43c5290..42c630f6 100644 --- a/src/library/link.rs +++ b/src/library/link.rs @@ -23,7 +23,7 @@ impl LinkNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { let url = args.expect::<EcoString>("url")?; - let body = args.find().unwrap_or_else(|| { + let body = args.find()?.unwrap_or_else(|| { let mut text = url.as_str(); for prefix in ["mailto:", "tel:"] { text = text.trim_start_matches(prefix); diff --git a/src/library/list.rs b/src/library/list.rs index 0c0e61ad..3b7cef68 100644 --- a/src/library/list.rs +++ b/src/library/list.rs @@ -21,7 +21,8 @@ impl<L: ListLabel> ListNode<L> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { Ok(args - .all() + .all()? + .into_iter() .enumerate() .map(|(i, child)| Template::show(Self { label: L::new(1 + i), child })) .sum()) diff --git a/src/library/pad.rs b/src/library/pad.rs index b65057dc..684e1172 100644 --- a/src/library/pad.rs +++ b/src/library/pad.rs @@ -14,7 +14,7 @@ pub struct PadNode { #[class] impl PadNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { - let all = args.find(); + let all = args.find()?; let left = args.named("left")?; let top = args.named("top")?; let right = args.named("right")?; diff --git a/src/library/page.rs b/src/library/page.rs index d54fefb0..7f0f7332 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -36,7 +36,7 @@ impl PageNode { } fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> { - if let Some(paper) = args.named::<Paper>("paper")?.or_else(|| args.find()) { + if let Some(paper) = args.named_or_find::<Paper>("paper")? { styles.set(Self::WIDTH, Smart::Custom(paper.width())); styles.set(Self::HEIGHT, Smart::Custom(paper.height())); } diff --git a/src/library/place.rs b/src/library/place.rs index ee5ee2c9..52bbeb21 100644 --- a/src/library/place.rs +++ b/src/library/place.rs @@ -10,7 +10,7 @@ pub struct PlaceNode(pub LayoutNode); #[class] impl PlaceNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> { - let aligns = args.find().unwrap_or(Spec::with_x(Some(Align::Left))); + let aligns = args.find()?.unwrap_or(Spec::with_x(Some(Align::Left))); let tx = args.named("dx")?.unwrap_or_default(); let ty = args.named("dy")?.unwrap_or_default(); let body: LayoutNode = args.expect("body")?; diff --git a/src/library/shape.rs b/src/library/shape.rs index 95e3e288..1eaad11a 100644 --- a/src/library/shape.rs +++ b/src/library/shape.rs @@ -45,7 +45,7 @@ impl<S: ShapeKind> ShapeNode<S> { }; Ok(Template::inline( - ShapeNode { kind: S::default(), child: args.find() } + ShapeNode { kind: S::default(), child: args.find()? } .pack() .sized(Spec::new(width, height)), )) diff --git a/src/library/stack.rs b/src/library/stack.rs index bccd552f..88605a30 100644 --- a/src/library/stack.rs +++ b/src/library/stack.rs @@ -20,7 +20,7 @@ impl StackNode { Ok(Template::block(Self { dir: args.named("dir")?.unwrap_or(Dir::TTB), spacing: args.named("spacing")?, - children: args.all().collect(), + children: args.all()?, })) } } diff --git a/src/library/table.rs b/src/library/table.rs index c40a117b..3f30dd9e 100644 --- a/src/library/table.rs +++ b/src/library/table.rs @@ -39,7 +39,7 @@ impl TableNode { column_gutter.unwrap_or_else(|| base_gutter.clone()), row_gutter.unwrap_or(base_gutter), ), - children: args.all().collect(), + children: args.all()?, })) } diff --git a/src/library/transform.rs b/src/library/transform.rs index de053a9d..6c16d02a 100644 --- a/src/library/transform.rs +++ b/src/library/transform.rs @@ -78,9 +78,7 @@ pub struct Rotate(pub Angle); impl TransformKind for Rotate { fn construct(args: &mut Args) -> TypResult<Self> { - Ok(Self( - args.named("angle")?.or_else(|| args.find()).unwrap_or_default(), - )) + Ok(Self(args.named_or_find("angle")?.unwrap_or_default())) } fn matrix(&self) -> Transform { @@ -94,7 +92,7 @@ pub struct Scale(pub Relative, pub Relative); impl TransformKind for Scale { fn construct(args: &mut Args) -> TypResult<Self> { - let all = args.find(); + let all = args.find()?; let sx = args.named("x")?.or(all).unwrap_or(Relative::one()); let sy = args.named("y")?.or(all).unwrap_or(Relative::one()); Ok(Self(sx, sy)) diff --git a/src/library/utility.rs b/src/library/utility.rs index 4fb254de..3b9b8b04 100644 --- a/src/library/utility.rs +++ b/src/library/utility.rs @@ -31,7 +31,7 @@ pub fn join(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let sep = args.named::<Value>("sep")?.unwrap_or(Value::None); let mut result = Value::None; - let mut iter = args.all::<Value>(); + let mut iter = args.all::<Value>()?.into_iter(); if let Some(first) = iter.next() { result = first; @@ -88,7 +88,7 @@ pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// Create an RGB(A) color. pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { Ok(Value::from( - if let Some(string) = args.find::<Spanned<EcoString>>() { + if let Some(string) = args.find::<Spanned<EcoString>>()? { match RgbaColor::from_str(&string.v) { Ok(color) => color, Err(_) => bail!(string.span, "invalid hex string"), @@ -208,7 +208,7 @@ pub fn modulo(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// Find the minimum or maximum of a sequence of values. fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> { let mut extremum = args.expect::<Value>("value")?; - for Spanned { v, span } in args.all::<Spanned<Value>>() { + for Spanned { v, span } in args.all::<Spanned<Value>>()? { match v.partial_cmp(&extremum) { Some(ordering) => { if ordering == goal { |
