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 crate::ast::Span;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use serde::{Deserialize, Serialize};
|
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>;
|
pub type Result<T> = std::result::Result<T, ConversionError>;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl From<String> for DynVal {
|
||||||
|
|
||||||
impl fmt::Display for DynVal {
|
impl fmt::Display for DynVal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "\"{}\"", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Debug for DynVal {
|
impl fmt::Debug for DynVal {
|
||||||
|
@ -70,32 +70,46 @@ impl std::str::FromStr for DynVal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_try_from {
|
pub trait FromDynVal: Sized {
|
||||||
(impl From<$typ:ty> {
|
type Err;
|
||||||
$(for $for:ty => |$arg:ident| $code:expr);*;
|
fn from_dynval(x: &DynVal) -> std::result::Result<Self, Self::Err>;
|
||||||
}) => {
|
}
|
||||||
$(impl TryFrom<$typ> for $for {
|
|
||||||
type Error = ConversionError;
|
impl<E, T: FromStr<Err = E>> FromDynVal for T {
|
||||||
fn try_from($arg: $typ) -> std::result::Result<Self, Self::Error> { $code }
|
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),*) => {
|
($($t:ty),*) => {
|
||||||
$(impl From<$t> for DynVal {
|
$(impl From<$t> for DynVal {
|
||||||
fn from(x: $t) -> Self { DynVal(x.to_string(), None) }
|
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 {
|
impl From<&serde_json::Value> for DynVal {
|
||||||
fn from(v: &serde_json::Value) -> Self {
|
fn from(v: &serde_json::Value) -> Self {
|
||||||
|
@ -118,6 +132,10 @@ impl DynVal {
|
||||||
DynVal(s, None)
|
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 {
|
pub fn into_inner(self) -> String {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
21
src/eval.rs
21
src/eval.rs
|
@ -8,6 +8,9 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum EvalError {
|
pub enum EvalError {
|
||||||
|
#[error("Tried to reference variable `{0}`, but we cannot access variables here")]
|
||||||
|
NoVariablesAllowed(String),
|
||||||
|
|
||||||
#[error("Invalid regex: {0}")]
|
#[error("Invalid regex: {0}")]
|
||||||
InvalidRegex(#[from] regex::Error),
|
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 span = self.span();
|
||||||
let value = match self {
|
let value = match self {
|
||||||
SimplExpr::Literal(_, x) => Ok(x),
|
SimplExpr::Literal(_, x) => Ok(x.clone()),
|
||||||
SimplExpr::VarRef(span, ref name) => {
|
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) => {
|
SimplExpr::BinOp(_, a, op, b) => {
|
||||||
let a = a.eval(values)?;
|
let a = a.eval(values)?;
|
||||||
|
@ -176,12 +187,12 @@ impl SimplExpr {
|
||||||
.unwrap_or(&serde_json::Value::Null);
|
.unwrap_or(&serde_json::Value::Null);
|
||||||
Ok(DynVal::from(indexed_value))
|
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) => {
|
SimplExpr::FunctionCall(span, function_name, args) => {
|
||||||
let args = args.into_iter().map(|a| a.eval(values)).collect::<Result<_, EvalError>>()?;
|
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))
|
Ok(value?.at(span))
|
||||||
|
|
Loading…
Add table
Reference in a new issue