summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-02-10 10:29:17 +0100
committerLaurenz <laurmaedje@gmail.com>2022-02-10 10:29:17 +0100
commit624471db619240f0eed849b92dff6a525ce7e547 (patch)
treeb6218c031019a78a99c7bb99fcbbe40918e6f2d7 /src/eval
parent6e198bf7606847b0847487a4847d6a3ee3621d2d (diff)
Proper error messages for shorthands
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/func.rs44
-rw-r--r--src/eval/value.rs6
2 files changed, 24 insertions, 26 deletions
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>,
{