From 5748185fb7a9b13266a69e8f15420cf839cd70ca Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Tue, 20 Jul 2021 18:51:29 +0200 Subject: [PATCH] FromDynVal-trait --- src/dynval.rs | 54 ++++++++++++++++++++++++++++++++++----------------- src/eval.rs | 21 +++++++++++++++----- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/dynval.rs b/src/dynval.rs index b3b5b2b..463eae7 100644 --- a/src/dynval.rs +++ b/src/dynval.rs @@ -1,7 +1,7 @@ use crate::ast::Span; use itertools::Itertools; use serde::{Deserialize, Serialize}; -use std::{convert::TryFrom, fmt, iter::FromIterator}; +use std::{fmt, iter::FromIterator, str::FromStr}; pub type Result = std::result::Result; @@ -34,7 +34,7 @@ impl From for DynVal { impl fmt::Display for DynVal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "\"{}\"", self.0) + write!(f, "{}", self.0) } } impl fmt::Debug for DynVal { @@ -70,32 +70,46 @@ impl std::str::FromStr for DynVal { } } -macro_rules! impl_try_from { - (impl From<$typ:ty> { - $(for $for:ty => |$arg:ident| $code:expr);*; - }) => { - $(impl TryFrom<$typ> for $for { - type Error = ConversionError; - fn try_from($arg: $typ) -> std::result::Result { $code } +pub trait FromDynVal: Sized { + type Err; + fn from_dynval(x: &DynVal) -> std::result::Result; +} + +impl> FromDynVal for T { + type Err = E; + + fn from_dynval(x: &DynVal) -> std::result::Result { + x.0.parse() + } +} + +macro_rules! impl_from_dynval { + ( + $(for $for:ty => |$name:ident| $code:expr);*; + ) => { + $(impl FromDynVal for $for { + type Err = ConversionError; + fn from_dynval($name: DynVal) -> std::result::Result { $code } })* }; } -macro_rules! impl_primval_from { +macro_rules! impl_dynval_from { ($($t:ty),*) => { $(impl From<$t> for DynVal { fn from(x: $t) -> Self { DynVal(x.to_string(), None) } })* }; } -impl_try_from!(impl From { - for String => |x| x.as_string(); - for f64 => |x| x.as_f64(); - for i32 => |x| x.as_i32(); - for bool => |x| x.as_bool(); - //for Vec => |x| x.as_vec(); -}); -impl_primval_from!(bool, i32, u32, f32, u8, f64, &str); +// impl_from_dynval! { +// for String => |x| x.as_string(); +// for f64 => |x| x.as_f64(); +// for i32 => |x| x.as_i32(); +// for bool => |x| x.as_bool(); +////for Vec => |x| x.as_vec(); +//} + +impl_dynval_from!(bool, i32, u32, f32, u8, f64, &str); impl From<&serde_json::Value> for DynVal { fn from(v: &serde_json::Value) -> Self { @@ -118,6 +132,10 @@ impl DynVal { DynVal(s, None) } + pub fn read_as>(&self) -> std::result::Result { + T::from_dynval(self) + } + pub fn into_inner(self) -> String { self.0 } diff --git a/src/eval.rs b/src/eval.rs index 01d58bd..3c70583 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,6 +8,9 @@ use std::collections::HashMap; #[derive(Debug, thiserror::Error)] pub enum EvalError { + #[error("Tried to reference variable `{0}`, but we cannot access variables here")] + NoVariablesAllowed(String), + #[error("Invalid regex: {0}")] InvalidRegex(#[from] regex::Error), @@ -114,12 +117,20 @@ impl SimplExpr { } } - pub fn eval(self, values: &HashMap) -> Result { + pub fn eval_no_vars(&self) -> Result { + match self.eval(&HashMap::new()) { + Ok(x) => Ok(x), + Err(EvalError::UnknownVariable(name)) => Err(EvalError::NoVariablesAllowed(name)), + Err(x) => Err(x), + } + } + + pub fn eval(&self, values: &HashMap) -> Result { let span = self.span(); let value = match self { - SimplExpr::Literal(_, x) => Ok(x), + SimplExpr::Literal(_, x) => Ok(x.clone()), SimplExpr::VarRef(span, ref name) => { - Ok(values.get(name).cloned().ok_or_else(|| EvalError::UnresolvedVariable(name.to_string()).at(span))?.at(span)) + Ok(values.get(name).cloned().ok_or_else(|| EvalError::UnresolvedVariable(name.to_string()).at(*span))?.at(*span)) } SimplExpr::BinOp(_, a, op, b) => { let a = a.eval(values)?; @@ -176,12 +187,12 @@ impl SimplExpr { .unwrap_or(&serde_json::Value::Null); Ok(DynVal::from(indexed_value)) } - _ => Err(EvalError::CannotIndex(format!("{}", val)).at(span)), + _ => Err(EvalError::CannotIndex(format!("{}", val)).at(*span)), } } SimplExpr::FunctionCall(span, function_name, args) => { let args = args.into_iter().map(|a| a.eval(values)).collect::>()?; - call_expr_function(&function_name, args).map_err(|e| e.at(span)) + call_expr_function(&function_name, args).map_err(|e| e.at(*span)) } }; Ok(value?.at(span))