FromDynVal-trait
This commit is contained in:
parent
7539dda162
commit
5748185fb7
2 changed files with 52 additions and 23 deletions
|
@ -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<T> = std::result::Result<T, ConversionError>;
|
||||
|
||||
|
@ -34,7 +34,7 @@ impl From<String> 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<Self, Self::Error> { $code }
|
||||
pub trait FromDynVal: Sized {
|
||||
type Err;
|
||||
fn from_dynval(x: &DynVal) -> std::result::Result<Self, Self::Err>;
|
||||
}
|
||||
|
||||
impl<E, T: FromStr<Err = E>> FromDynVal for T {
|
||||
type Err = E;
|
||||
|
||||
fn from_dynval(x: &DynVal) -> std::result::Result<Self, Self::Err> {
|
||||
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<Self, Self::Err> { $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<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<String> => |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<String> => |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<E, T: FromDynVal<Err = E>>(&self) -> std::result::Result<T, E> {
|
||||
T::from_dynval(self)
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> String {
|
||||
self.0
|
||||
}
|
||||
|
|
21
src/eval.rs
21
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<VarName, DynVal>) -> Result<DynVal, EvalError> {
|
||||
pub fn eval_no_vars(&self) -> Result<DynVal, EvalError> {
|
||||
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<VarName, DynVal>) -> Result<DynVal, EvalError> {
|
||||
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::<Result<_, EvalError>>()?;
|
||||
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))
|
||||
|
|
Loading…
Add table
Reference in a new issue