diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-12-21 00:36:22 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-12-21 00:36:22 +0100 |
| commit | 2b660968aa7e1e8efb7c396e17066a1a98c8c10e (patch) | |
| tree | 40a059ccad2c82455af1d8456fabcb4502491642 /src/eval/args.rs | |
| parent | 6f111f941008f10ddc06e6f56da9e3582e90d2c4 (diff) | |
Restructure value conversions 🧱
Diffstat (limited to 'src/eval/args.rs')
| -rw-r--r-- | src/eval/args.rs | 102 |
1 files changed, 58 insertions, 44 deletions
diff --git a/src/eval/args.rs b/src/eval/args.rs index e9bf378b..765ae09c 100644 --- a/src/eval/args.rs +++ b/src/eval/args.rs @@ -1,7 +1,10 @@ //! Simplifies argument parsing. -use super::{Convert, EvalContext, RefKey, ValueDict}; -use crate::syntax::{SpanWith, Spanned}; +use std::mem; + +use super::{Conv, EvalContext, RefKey, TryFromValue, Value, ValueDict}; +use crate::diag::Diag; +use crate::syntax::{Span, SpanVec, SpanWith, Spanned}; /// A wrapper around a dictionary value that simplifies argument parsing in /// functions. @@ -16,15 +19,11 @@ impl Args { pub fn get<'a, K, T>(&mut self, ctx: &mut EvalContext, key: K) -> Option<T> where K: Into<RefKey<'a>>, - T: Convert, + T: TryFromValue, { self.0.v.remove(key).and_then(|entry| { let span = entry.value.span; - let (result, diag) = T::convert(entry.value); - if let Some(diag) = diag { - ctx.f.diags.push(diag.span_with(span)) - } - result.ok() + conv_diag(T::try_from_value(entry.value), &mut ctx.f.diags, span) }) } @@ -38,37 +37,29 @@ impl Args { ) -> Option<T> where K: Into<RefKey<'a>>, - T: Convert, + T: TryFromValue, { - match self.0.v.remove(key) { - Some(entry) => { - let span = entry.value.span; - let (result, diag) = T::convert(entry.value); - if let Some(diag) = diag { - ctx.f.diags.push(diag.span_with(span)) - } - result.ok() - } - None => { - ctx.f.diags.push(error!(self.0.span, "missing argument: {}", name)); - None - } + if let Some(entry) = self.0.v.remove(key) { + let span = entry.value.span; + conv_diag(T::try_from_value(entry.value), &mut ctx.f.diags, span) + } else { + ctx.f.diags.push(error!(self.0.span, "missing argument: {}", name)); + None } } /// Retrieve and remove the first matching positional argument. pub fn find<T>(&mut self) -> Option<T> where - T: Convert, + T: TryFromValue, { for (&key, entry) in self.0.v.nums_mut() { let span = entry.value.span; - match T::convert(std::mem::take(&mut entry.value)).0 { - Ok(t) => { - self.0.v.remove(key); - return Some(t); - } - Err(v) => entry.value = v.span_with(span), + let slot = &mut entry.value; + let conv = conv_put_back(T::try_from_value(mem::take(slot)), slot, span); + if let Some(t) = conv { + self.0.v.remove(key); + return Some(t); } } None @@ -77,18 +68,17 @@ impl Args { /// Retrieve and remove all matching positional arguments. pub fn find_all<T>(&mut self) -> impl Iterator<Item = T> + '_ where - T: Convert, + T: TryFromValue, { let mut skip = 0; std::iter::from_fn(move || { for (&key, entry) in self.0.v.nums_mut().skip(skip) { let span = entry.value.span; - match T::convert(std::mem::take(&mut entry.value)).0 { - Ok(t) => { - self.0.v.remove(key); - return Some(t); - } - Err(v) => entry.value = v.span_with(span), + let slot = &mut entry.value; + let conv = conv_put_back(T::try_from_value(mem::take(slot)), slot, span); + if let Some(t) = conv { + self.0.v.remove(key); + return Some(t); } skip += 1; } @@ -99,19 +89,18 @@ impl Args { /// Retrieve and remove all matching keyword arguments. pub fn find_all_str<T>(&mut self) -> impl Iterator<Item = (String, T)> + '_ where - T: Convert, + T: TryFromValue, { let mut skip = 0; std::iter::from_fn(move || { for (key, entry) in self.0.v.strs_mut().skip(skip) { let span = entry.value.span; - match T::convert(std::mem::take(&mut entry.value)).0 { - Ok(t) => { - let key = key.clone(); - self.0.v.remove(&key); - return Some((key, t)); - } - Err(v) => entry.value = v.span_with(span), + let slot = &mut entry.value; + let conv = conv_put_back(T::try_from_value(mem::take(slot)), slot, span); + if let Some(t) = conv { + let key = key.clone(); + self.0.v.remove(&key); + return Some((key, t)); } skip += 1; } @@ -129,6 +118,31 @@ impl Args { } } +fn conv_diag<T>(conv: Conv<T>, diags: &mut SpanVec<Diag>, span: Span) -> Option<T> { + match conv { + Conv::Ok(t) => Some(t), + Conv::Warn(t, warn) => { + diags.push(warn.span_with(span)); + Some(t) + } + Conv::Err(_, err) => { + diags.push(err.span_with(span)); + None + } + } +} + +fn conv_put_back<T>(conv: Conv<T>, slot: &mut Spanned<Value>, span: Span) -> Option<T> { + match conv { + Conv::Ok(t) => Some(t), + Conv::Warn(t, _) => Some(t), + Conv::Err(v, _) => { + *slot = v.span_with(span); + None + } + } +} + #[cfg(test)] mod tests { use super::super::{Dict, SpannedEntry, Value}; |
