evaluate expressions

main
Ziyang Hu 2 years ago
parent 4707d13bfb
commit ea72a01f5a

@ -4,21 +4,48 @@ use anyhow::Result;
use itertools::Itertools; use itertools::Itertools;
use crate::data::expr::ExprError::UnexpectedArgs; use crate::data::expr::ExprError::UnexpectedArgs;
use crate::data::keyword::Keyword;
use crate::data::tuple::Tuple;
use crate::data::value::DataValue; use crate::data::value::DataValue;
use crate::query::compile::Term;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum ExprError { pub enum ExprError {
#[error("unexpected args for {0}: {1:?}")] #[error("unexpected args for {0}: {1:?}")]
UnexpectedArgs(&'static str, Vec<DataValue>), UnexpectedArgs(&'static str, Vec<DataValue>),
#[error("unexpected return type: expected {0}, got {1:?}")]
UnexpectedReturnType(String, DataValue),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
Const(Term<DataValue>), Binding(Keyword),
BoundIdx(usize),
Const(DataValue),
Apply(&'static Op, Box<[Expr]>), Apply(&'static Op, Box<[Expr]>),
} }
impl Expr {
pub(crate) fn eval(&self, bindings: &Tuple) -> Result<DataValue> {
match self {
Expr::Binding(_) => {
unreachable!()
}
Expr::BoundIdx(i) => Ok(bindings.0[*i].clone()),
Expr::Const(d) => Ok(d.clone()),
Expr::Apply(op, args) => {
let args: Box<[DataValue]> = args.iter().map(|v| v.eval(bindings)).try_collect()?;
(op.inner)(&args)
}
}
}
pub(crate) fn eval_pred(&self, bindings: &Tuple) -> Result<bool> {
match self.eval(bindings)? {
DataValue::Bool(b) => Ok(b),
v => Err(ExprError::UnexpectedReturnType("bool".to_string(), v).into()),
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct Op { pub struct Op {
pub(crate) name: &'static str, pub(crate) name: &'static str,
@ -171,4 +198,4 @@ fn op_not(args: &[DataValue]) -> Result<DataValue> {
} else { } else {
Err(UnexpectedArgs("not", args.to_vec()).into()) Err(UnexpectedArgs("not", args.to_vec()).into())
} }
} }

@ -7,7 +7,8 @@ use serde_json::Map;
use crate::data::attr::Attribute; use crate::data::attr::Attribute;
use crate::data::expr::{ use crate::data::expr::{
Expr, OP_ADD, OP_DIV, OP_EQ, OP_GE, OP_GT, OP_LE, OP_LT, OP_MUL, OP_NEQ, OP_SUB, Expr, OP_ADD, OP_AND, OP_DIV, OP_EQ, OP_GE, OP_GT, OP_LE, OP_LT, OP_MUL, OP_NEQ, OP_NOT, OP_OR,
OP_SUB,
}; };
use crate::data::json::JsonValue; use crate::data::json::JsonValue;
use crate::data::keyword::{Keyword, PROG_ENTRY}; use crate::data::keyword::{Keyword, PROG_ENTRY};
@ -112,6 +113,9 @@ impl SessionTx {
"Ge" => &OP_GE, "Ge" => &OP_GE,
"Lt" => &OP_LT, "Lt" => &OP_LT,
"Le" => &OP_LE, "Le" => &OP_LE,
"Or" => &OP_OR,
"And" => &OP_AND,
"Not" => &OP_NOT,
s => return Err(QueryCompilationError::UnknownOperator(s.to_string()).into()), s => return Err(QueryCompilationError::UnknownOperator(s.to_string()).into()),
}; };
@ -159,14 +163,14 @@ impl SessionTx {
JsonValue::String(s) => { JsonValue::String(s) => {
let kw = Keyword::from(s as &str); let kw = Keyword::from(s as &str);
if kw.is_reserved() { if kw.is_reserved() {
Ok(Expr::Const(Term::Var(kw))) Ok(Expr::Binding(kw))
} else { } else {
Ok(Expr::Const(Term::Const(DataValue::String(s.into())))) Ok(Expr::Const(DataValue::String(s.into())))
} }
} }
JsonValue::Object(map) => { JsonValue::Object(map) => {
if let Some(v) = map.get("const") { if let Some(v) = map.get("const") {
Ok(Expr::Const(Term::Const(v.into()))) Ok(Expr::Const(v.into()))
} else if map.contains_key("pred") { } else if map.contains_key("pred") {
Self::parse_expr(map) Self::parse_expr(map)
} else { } else {
@ -177,7 +181,7 @@ impl SessionTx {
.into()) .into())
} }
} }
v => Ok(Expr::Const(Term::Const(v.into()))), v => Ok(Expr::Const(v.into())),
} }
} }
fn parse_rule_atom(&mut self, payload: &Map<String, JsonValue>, vld: Validity) -> Result<Atom> { fn parse_rule_atom(&mut self, payload: &Map<String, JsonValue>, vld: Validity) -> Result<Atom> {

Loading…
Cancel
Save