From 55304c621eb04844677769fcab8ce6dc343c83b6 Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Tue, 17 May 2022 23:13:22 +0800 Subject: [PATCH] ops in their own modules --- src/data/eval.rs | 127 +++++++- src/data/expr.rs | 2 +- src/data/expr_parser.rs | 3 +- src/data/op.rs | 598 ++++---------------------------------- src/data/op/arithmetic.rs | 178 ++++++++++++ src/data/op/boolean.rs | 158 ++++++++++ src/data/op/combine.rs | 63 ++++ src/data/op/comparison.rs | 142 +++++++++ src/data/op/text.rs | 31 ++ src/data/tuple.rs | 2 - src/data/tuple_set.rs | 3 +- src/runtime/instance.rs | 7 +- 12 files changed, 753 insertions(+), 561 deletions(-) create mode 100644 src/data/op/arithmetic.rs create mode 100644 src/data/op/boolean.rs create mode 100644 src/data/op/combine.rs create mode 100644 src/data/op/comparison.rs create mode 100644 src/data/op/text.rs diff --git a/src/data/eval.rs b/src/data/eval.rs index d1dc447d..a3ac2763 100644 --- a/src/data/eval.rs +++ b/src/data/eval.rs @@ -29,6 +29,12 @@ pub(crate) enum EvalError { #[error("Cannot apply `{0}` to `{1:?}`")] OpTypeMismatch(String, Vec), + + #[error("Optimized before partial eval")] + OptimizedBeforePartialEval, + + #[error("Arity mismatch for {0}, {1} arguments given ")] + ArityMismatch(String, usize), } type Result = result::Result; @@ -43,7 +49,10 @@ impl RowEvalContext for () { } } -pub(crate) trait ExprEvalContext {} +pub(crate) trait ExprEvalContext { + fn resolve<'a>(&'a self, key: &str) -> Option>; + fn resolve_table_col<'a>(&'a self, binding: &str, col: &str) -> Option<(TableId, ColId)>; +} fn extract_optimized_bin_args(args: Vec) -> (Expr, Expr) { let mut args = args.into_iter(); @@ -55,8 +64,120 @@ fn extract_optimized_u_args(args: Vec) -> Expr { } impl<'a> Expr<'a> { - pub(crate) fn partial_eval(&'a self, ctx: &'a C) -> Result { - todo!() + pub(crate) fn partial_eval(self, ctx: &'a C) -> Result { + let res = match self { + v @ (Expr::Const(_) | + Expr::TableCol(_, _) | + Expr::TupleSetIdx(_)) => v, + Expr::List(l) => Expr::List(l.into_iter().map(|v| v.partial_eval(ctx)).collect::>>()?), + Expr::Dict(d) => Expr::Dict(d.into_iter().map(|(k, v)| -> Result<(String, Expr)> { + Ok((k, v.partial_eval(ctx)?)) + }).collect::>>()?), + Expr::Variable(var) => ctx.resolve(&var).ok_or(EvalError::UnresolvedVariable(var))?, + Expr::FieldAcc(f, arg) => { + let expr = match *arg { + Expr::Variable(var) => { + if let Some((tid, cid)) = ctx.resolve_table_col(&var, &f) { + return Ok(Expr::TableCol(tid, cid)); + } else { + ctx.resolve(&var) + .ok_or(EvalError::UnresolvedVariable(var))? + .partial_eval(ctx)? + } + } + expr => expr.partial_eval(ctx)? + }; + match expr { + Expr::Const(Value::Null) => Expr::Const(Value::Null), + Expr::Const(Value::Dict(mut d)) => { + Expr::Const(d.remove(&f as &str).unwrap_or(Value::Null)) + } + v @ (Expr::IdxAcc(_, _) | + Expr::FieldAcc(_, _) | + Expr::TableCol(_, _) | + Expr::Apply(_, _) | + Expr::ApplyAgg(_, _, _)) => { + Expr::FieldAcc(f, v.into()) + } + Expr::Dict(mut d) => { + d.remove(&f as &str).unwrap_or(Expr::Const(Value::Null)) + } + v => return Err(EvalError::FieldAccess(f, Value::from(v).to_static())) + } + } + Expr::IdxAcc(i, arg) => { + let arg = arg.partial_eval(ctx)?; + match arg { + Expr::Const(Value::Null) => Expr::Const(Value::Null), + Expr::Const(Value::List(mut l)) => { + if i >= l.len() { + Expr::Const(Value::Null) + } else { + Expr::Const(l.swap_remove(i)) + } + } + Expr::List(mut l) => { + if i >= l.len() { + Expr::Const(Value::Null) + } else { + l.swap_remove(i) + } + } + v @ (Expr::IdxAcc(_, _) | + Expr::FieldAcc(_, _) | + Expr::TableCol(_, _) | + Expr::Apply(_, _) | + Expr::ApplyAgg(_, _, _)) => { + Expr::IdxAcc(i, v.into()) + } + v => return Err(EvalError::IndexAccess(i, Value::from(v).to_static())) + } + } + Expr::Apply(op, args) => { + let args = args.into_iter().map(|v| v.partial_eval(ctx)).collect::>>()?; + if op.has_side_effect() { + Expr::Apply(op, args) + } else { + match op.partial_eval(args.clone())? { + Some(v) => v, + None => Expr::Apply(op, args) + } + } + } + Expr::ApplyAgg(op, a_args, args) => { + let a_args = a_args.into_iter().map(|v| v.partial_eval(ctx)).collect::>>()?; + let args = args.into_iter().map(|v| v.partial_eval(ctx)).collect::>>()?; + if op.has_side_effect() { + Expr::ApplyAgg(op, a_args, args) + } else { + match op.partial_eval(a_args.clone(), args.clone())? { + Some(v) => v, + None => Expr::ApplyAgg(op, a_args, args) + } + } + } + Expr::Add(_) | + Expr::Sub(_) | + Expr::Mul(_) | + Expr::Div(_) | + Expr::Pow(_) | + Expr::Mod(_) | + Expr::StrCat(_) | + Expr::Eq(_) | + Expr::Ne(_) | + Expr::Gt(_) | + Expr::Ge(_) | + Expr::Lt(_) | + Expr::Le(_) | + Expr::Negate(_) | + Expr::Minus(_) | + Expr::IsNull(_) | + Expr::NotNull(_) | + Expr::Coalesce(_) | + Expr::Or(_) | + Expr::And(_) => return Err(EvalError::OptimizedBeforePartialEval) + }; + Ok(res) } pub(crate) fn optimize_ops(self) -> Self { match self { diff --git a/src/data/expr.rs b/src/data/expr.rs index ca7cd28d..86165520 100644 --- a/src/data/expr.rs +++ b/src/data/expr.rs @@ -2,7 +2,7 @@ use crate::data::op::{AggOp, Op, OpAdd, OpAnd, OpCoalesce, OpDiv, OpEq, OpGe, Op use crate::data::tuple_set::{ColId, TableId, TupleSetIdx}; use crate::data::value::{StaticValue, Value}; use std::collections::BTreeMap; -use std::fmt::{format, write, Debug, Formatter}; +use std::fmt::{Debug, Formatter}; use std::result; use std::sync::Arc; diff --git a/src/data/expr_parser.rs b/src/data/expr_parser.rs index 40eff71b..567b8925 100644 --- a/src/data/expr_parser.rs +++ b/src/data/expr_parser.rs @@ -1,4 +1,4 @@ -use crate::data::expr::{Expr, ExprError}; +use crate::data::expr::{Expr}; use crate::data::op::{ Op, OpAdd, OpAnd, OpCoalesce, OpConcat, OpDiv, OpEq, OpGe, OpGt, OpLe, OpLt, OpMerge, OpMinus, OpMod, OpMul, OpNe, OpNegate, OpOr, OpPow, OpStrCat, OpSub, UnresolvedOp, @@ -249,7 +249,6 @@ fn build_expr_infix<'a>( #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::data::expr::StaticExpr; use crate::parser::CozoParser; use pest::Parser; diff --git a/src/data/op.rs b/src/data/op.rs index 83745b79..9338eee1 100644 --- a/src/data/op.rs +++ b/src/data/op.rs @@ -1,12 +1,21 @@ -use std::cmp::max; -use std::collections::BTreeMap; -use crate::data::eval::{EvalError, ExprEvalContext, RowEvalContext}; +mod arithmetic; +mod text; +mod comparison; +mod boolean; +mod combine; + +use crate::data::eval::{EvalError}; use crate::data::expr::Expr; use crate::data::typing::Typing; use crate::data::value::{StaticValue, Value}; -use std::fmt::{Debug, Formatter}; use std::result; +pub(crate) use arithmetic::*; +pub(crate) use text::*; +pub(crate) use comparison::*; +pub(crate) use boolean::*; +pub(crate) use combine::*; + type Result = result::Result; pub(crate) trait Op: Send + Sync { @@ -16,6 +25,9 @@ pub(crate) trait Op: Send + Sync { fn arity(&self) -> Option { Some(1) } + fn has_side_effect(&self) -> bool { + false + } fn name(&self) -> &str; fn non_null_args(&self) -> bool { true @@ -85,7 +97,36 @@ pub(crate) trait Op: Send + Sync { self.name() ) } - fn expr_eval(&self, ctx: &dyn ExprEvalContext, args: ()) -> () {} + fn partial_eval<'a>(&self, args: Vec>) -> Result>> { + if let Some(arity) = self.arity() { + if arity != args.len() { + return Err(EvalError::ArityMismatch(self.name().to_string(), arity)) + } + } + let mut has_null = false; + match args.iter().map(|v| { + match v { + Expr::Const(v) => { + if *v == Value::Null { + has_null = true; + } + Some(v.clone()) + } + _ => None + } + }).collect::>().into_iter().collect::>>() { + Some(args) => { + Ok(Some(Expr::Const(self.eval(has_null, args)?))) + } + None => { + if self.non_null_args() && has_null { + Ok(Some(Expr::Const(Value::Null))) + } else { + Ok(None) + } + } + } + } } pub(crate) trait AggOp: Send + Sync { @@ -95,12 +136,12 @@ pub(crate) trait AggOp: Send + Sync { fn arity(&self) -> Option { Some(1) } - fn name(&self) -> &str; - fn row_eval(&self, ctx: (), args: ()) -> () { - unimplemented!() + fn has_side_effect(&self) -> bool { + false } - fn expr_eval(&self, ctx: (), args: ()) -> () { - self.row_eval(ctx, args) + fn name(&self) -> &str; + fn partial_eval<'a>(&self, a_args: Vec>, args: Vec>) -> Result>> { + todo!() } } @@ -122,318 +163,7 @@ impl AggOp for UnresolvedOp { } } -pub(crate) struct OpAdd; - -impl Op for OpAdd { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "+" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l + r).into(), - (Value::Float(l), Value::Int(r)) => (l + (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) + r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() + r.into_inner()).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpSub; - -impl Op for OpSub { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "-" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l - r).into(), - (Value::Float(l), Value::Int(r)) => (l - (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) - r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() - r.into_inner()).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpMul; - -impl Op for OpMul { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "*" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l * r).into(), - (Value::Float(l), Value::Int(r)) => (l * (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) * r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() * r.into_inner()).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpDiv; - -impl Op for OpDiv { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "/" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l as f64 / r as f64).into(), - (Value::Float(l), Value::Int(r)) => (l / (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) / r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() / r.into_inner()).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpMod; - -impl Op for OpMod { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "%" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l % r).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpPow; -impl Op for OpPow { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "**" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => ((l as f64).powf(r as f64)).into(), - (Value::Float(l), Value::Int(r)) => ((l.into_inner()).powf(r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64).powf(r.into_inner())).into(), - (Value::Float(l), Value::Float(r)) => ((l.into_inner()).powf(r.into_inner())).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpStrCat; - -impl Op for OpStrCat { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "++" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - match (left, right) { - (Value::Text(l), Value::Text(r)) => { - let mut l = l.into_owned(); - l += r.as_ref(); - Ok(l.into()) - } - (l, r) => Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )), - } - } -} - -pub(crate) struct OpEq; - -impl Op for OpEq { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "==" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - Ok((left == right).into()) - } -} - -pub(crate) struct OpNe; - -impl Op for OpNe { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "!=" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - Ok((left != right).into()) - } -} - -pub(crate) struct OpGt; - -impl Op for OpGt { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - ">" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l > r).into(), - (Value::Float(l), Value::Int(r)) => (l > (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) > r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l > r).into(), - (Value::Text(l), Value::Text(r)) => (l > r).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpGe; - -impl Op for OpGe { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - ">=" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l >= r).into(), - (Value::Float(l), Value::Int(r)) => (l >= (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) >= r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l >= r).into(), - (Value::Text(l), Value::Text(r)) => (l >= r).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpLt; - -impl Op for OpLt { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "<" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l < r).into(), - (Value::Float(l), Value::Int(r)) => (l < (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) < r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l < r).into(), - (Value::Text(l), Value::Text(r)) => (l < r).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} - -pub(crate) struct OpLe; - -impl Op for OpLe { - fn arity(&self) -> Option { - Some(2) - } - fn name(&self) -> &str { - "<=" - } - fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - let res: Value = match (left, right) { - (Value::Int(l), Value::Int(r)) => (l <= r).into(), - (Value::Float(l), Value::Int(r)) => (l <= (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) <= r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l <= r).into(), - (Value::Text(l), Value::Text(r)) => (l <= r).into(), - (l, r) => { - return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )); - } - }; - Ok(res) - } -} pub(crate) struct OpNegate; @@ -451,229 +181,3 @@ impl Op for OpNegate { } } } - -pub(crate) struct OpMinus; - -impl Op for OpMinus { - fn name(&self) -> &str { - "--" - } - fn eval_one_non_null<'a>(&self, arg: Value<'a>) -> Result> { - match arg { - Value::Int(i) => Ok((-i).into()), - Value::Float(i) => Ok((-i).into()), - v => Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![v.to_static()], - )), - } - } -} - -pub(crate) struct OpIsNull; - -impl Op for OpIsNull { - fn name(&self) -> &str { - "is_null" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, has_null: bool, _args: Vec>) -> Result> { - Ok(has_null.into()) - } - fn eval_one<'a>(&self, arg: Value<'a>) -> Result> { - Ok((arg == Value::Null).into()) - } -} - -pub(crate) struct OpNotNull; - -impl Op for OpNotNull { - fn name(&self) -> &str { - "not_null" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, has_null: bool, _args: Vec>) -> Result> { - Ok((!has_null).into()) - } - fn eval_one<'a>(&self, arg: Value<'a>) -> Result> { - Ok((arg != Value::Null).into()) - } -} - -pub(crate) struct OpCoalesce; - -impl Op for OpCoalesce { - fn arity(&self) -> Option { - None - } - fn name(&self) -> &str { - "~~" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, _has_null: bool, args: Vec>) -> Result> { - for arg in args { - if arg != Value::Null { - return Ok(arg); - } - } - Ok(Value::Null) - } - fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - match (left, right) { - (Value::Null, v) => Ok(v), - (l, _r) => Ok(l) - } - } -} - -pub(crate) struct OpOr; - -impl Op for OpOr { - fn arity(&self) -> Option { - None - } - fn name(&self) -> &str { - "||" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, has_null: bool, args: Vec>) -> Result> { - for arg in args { - match arg { - Value::Null => {} - Value::Bool(true) => return Ok(Value::Bool(true)), - Value::Bool(false) => {} - v => return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![v.to_static()], - )), - } - } - if has_null { - Ok(Value::Null) - } else { - Ok(Value::Bool(false)) - } - } - fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - match (left, right) { - (Value::Null, Value::Bool(true)) => Ok(true.into()), - (Value::Null, Value::Bool(false)) => Ok(Value::Null), - (Value::Bool(true), Value::Null) => Ok(true.into()), - (Value::Bool(false), Value::Null) => Ok(Value::Null), - (Value::Bool(l), Value::Bool(r)) => Ok((l || r).into()), - (l, r) => Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )) - } - } -} - -pub(crate) struct OpAnd; - -impl Op for OpAnd { - fn arity(&self) -> Option { - None - } - fn name(&self) -> &str { - "&&" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, has_null: bool, args: Vec>) -> Result> { - for arg in args { - match arg { - Value::Null => {} - Value::Bool(false) => return Ok(Value::Bool(false)), - Value::Bool(true) => {} - v => return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![v.to_static()], - )), - } - } - if has_null { - Ok(Value::Null) - } else { - Ok(Value::Bool(true)) - } - } - fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { - match (left, right) { - (Value::Null, Value::Bool(false)) => Ok(false.into()), - (Value::Null, Value::Bool(true)) => Ok(Value::Null), - (Value::Bool(false), Value::Null) => Ok(false.into()), - (Value::Bool(true), Value::Null) => Ok(Value::Null), - (Value::Bool(l), Value::Bool(r)) => Ok((l && r).into()), - (l, r) => Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![l.to_static(), r.to_static()], - )) - } - } -} - -pub(crate) struct OpConcat; - -impl Op for OpConcat { - fn arity(&self) -> Option { - None - } - fn name(&self) -> &str { - "concat" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, _has_null: bool, args: Vec>) -> Result> { - let mut coll = vec![]; - for v in args.into_iter() { - match v { - Value::Null => {} - Value::List(l) => coll.extend(l), - v => return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![v.to_static()], - )), - } - } - Ok(coll.into()) - } -} - -pub(crate) struct OpMerge; - -impl Op for OpMerge { - fn arity(&self) -> Option { - None - } - fn name(&self) -> &str { - "merge" - } - fn non_null_args(&self) -> bool { - false - } - fn eval<'a>(&self, has_null: bool, args: Vec>) -> Result> { - let mut coll = BTreeMap::new(); - for v in args.into_iter() { - match v { - Value::Null => {} - Value::Dict(d) => coll.extend(d), - v => return Err(EvalError::OpTypeMismatch( - self.name().to_string(), - vec![v.to_static()], - )), - } - } - Ok(coll.into()) - } -} diff --git a/src/data/op/arithmetic.rs b/src/data/op/arithmetic.rs new file mode 100644 index 00000000..f7d8c496 --- /dev/null +++ b/src/data/op/arithmetic.rs @@ -0,0 +1,178 @@ +use std::result; +use crate::data::eval::EvalError; +use crate::data::op::Op; +use crate::data::value::Value; + +type Result = result::Result; + +pub(crate) struct OpAdd; + +impl Op for OpAdd { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "+" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l + r).into(), + (Value::Float(l), Value::Int(r)) => (l + (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) + r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() + r.into_inner()).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpSub; + +impl Op for OpSub { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "-" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l - r).into(), + (Value::Float(l), Value::Int(r)) => (l - (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) - r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() - r.into_inner()).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpMul; + +impl Op for OpMul { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "*" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l * r).into(), + (Value::Float(l), Value::Int(r)) => (l * (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) * r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() * r.into_inner()).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpDiv; + +impl Op for OpDiv { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "/" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l as f64 / r as f64).into(), + (Value::Float(l), Value::Int(r)) => (l / (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) / r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() / r.into_inner()).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpMod; + +impl Op for OpMod { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "%" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l % r).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpPow; + +impl Op for OpPow { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "**" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => ((l as f64).powf(r as f64)).into(), + (Value::Float(l), Value::Int(r)) => ((l.into_inner()).powf(r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64).powf(r.into_inner())).into(), + (Value::Float(l), Value::Float(r)) => ((l.into_inner()).powf(r.into_inner())).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + + +pub(crate) struct OpMinus; + +impl Op for OpMinus { + fn name(&self) -> &str { + "--" + } + fn eval_one_non_null<'a>(&self, arg: Value<'a>) -> Result> { + match arg { + Value::Int(i) => Ok((-i).into()), + Value::Float(i) => Ok((-i).into()), + v => Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![v.to_static()], + )), + } + } +} diff --git a/src/data/op/boolean.rs b/src/data/op/boolean.rs new file mode 100644 index 00000000..fb521a45 --- /dev/null +++ b/src/data/op/boolean.rs @@ -0,0 +1,158 @@ +use std::result; +use crate::data::eval::EvalError; +use crate::data::op::Op; +use crate::data::value::Value; + +type Result = result::Result; + +pub(crate) struct OpIsNull; + +impl Op for OpIsNull { + fn name(&self) -> &str { + "is_null" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, has_null: bool, _args: Vec>) -> Result> { + Ok(has_null.into()) + } + fn eval_one<'a>(&self, arg: Value<'a>) -> Result> { + Ok((arg == Value::Null).into()) + } +} + +pub(crate) struct OpNotNull; + +impl Op for OpNotNull { + fn name(&self) -> &str { + "not_null" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, has_null: bool, _args: Vec>) -> Result> { + Ok((!has_null).into()) + } + fn eval_one<'a>(&self, arg: Value<'a>) -> Result> { + Ok((arg != Value::Null).into()) + } +} + +pub(crate) struct OpCoalesce; + +impl Op for OpCoalesce { + fn arity(&self) -> Option { + None + } + fn name(&self) -> &str { + "~~" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, _has_null: bool, args: Vec>) -> Result> { + for arg in args { + if arg != Value::Null { + return Ok(arg); + } + } + Ok(Value::Null) + } + fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + match (left, right) { + (Value::Null, v) => Ok(v), + (l, _r) => Ok(l) + } + } +} + +pub(crate) struct OpOr; + +impl Op for OpOr { + fn arity(&self) -> Option { + None + } + fn name(&self) -> &str { + "||" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, has_null: bool, args: Vec>) -> Result> { + for arg in args { + match arg { + Value::Null => {} + Value::Bool(true) => return Ok(Value::Bool(true)), + Value::Bool(false) => {} + v => return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![v.to_static()], + )), + } + } + if has_null { + Ok(Value::Null) + } else { + Ok(Value::Bool(false)) + } + } + fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + match (left, right) { + (Value::Null, Value::Bool(true)) => Ok(true.into()), + (Value::Null, Value::Bool(false)) => Ok(Value::Null), + (Value::Bool(true), Value::Null) => Ok(true.into()), + (Value::Bool(false), Value::Null) => Ok(Value::Null), + (Value::Bool(l), Value::Bool(r)) => Ok((l || r).into()), + (l, r) => Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )) + } + } +} + +pub(crate) struct OpAnd; + +impl Op for OpAnd { + fn arity(&self) -> Option { + None + } + fn name(&self) -> &str { + "&&" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, has_null: bool, args: Vec>) -> Result> { + for arg in args { + match arg { + Value::Null => {} + Value::Bool(false) => return Ok(Value::Bool(false)), + Value::Bool(true) => {} + v => return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![v.to_static()], + )), + } + } + if has_null { + Ok(Value::Null) + } else { + Ok(Value::Bool(true)) + } + } + fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + match (left, right) { + (Value::Null, Value::Bool(false)) => Ok(false.into()), + (Value::Null, Value::Bool(true)) => Ok(Value::Null), + (Value::Bool(false), Value::Null) => Ok(false.into()), + (Value::Bool(true), Value::Null) => Ok(Value::Null), + (Value::Bool(l), Value::Bool(r)) => Ok((l && r).into()), + (l, r) => Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )) + } + } +} diff --git a/src/data/op/combine.rs b/src/data/op/combine.rs new file mode 100644 index 00000000..d1a709eb --- /dev/null +++ b/src/data/op/combine.rs @@ -0,0 +1,63 @@ +use std::collections::BTreeMap; +use std::result; +use crate::data::eval::EvalError; +use crate::data::op::Op; +use crate::data::value::Value; + +type Result = result::Result; + +pub(crate) struct OpConcat; + +impl Op for OpConcat { + fn arity(&self) -> Option { + None + } + fn name(&self) -> &str { + "concat" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, _has_null: bool, args: Vec>) -> Result> { + let mut coll = vec![]; + for v in args.into_iter() { + match v { + Value::Null => {} + Value::List(l) => coll.extend(l), + v => return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![v.to_static()], + )), + } + } + Ok(coll.into()) + } +} + +pub(crate) struct OpMerge; + +impl Op for OpMerge { + fn arity(&self) -> Option { + None + } + fn name(&self) -> &str { + "merge" + } + fn non_null_args(&self) -> bool { + false + } + fn eval<'a>(&self, has_null: bool, args: Vec>) -> Result> { + let mut coll = BTreeMap::new(); + for v in args.into_iter() { + match v { + Value::Null => {} + Value::Dict(d) => coll.extend(d), + v => return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![v.to_static()], + )), + } + } + Ok(coll.into()) + } +} diff --git a/src/data/op/comparison.rs b/src/data/op/comparison.rs new file mode 100644 index 00000000..91d20b94 --- /dev/null +++ b/src/data/op/comparison.rs @@ -0,0 +1,142 @@ +use std::result; +use crate::data::eval::EvalError; +use crate::data::op::Op; +use crate::data::value::Value; + +type Result = result::Result; + +pub(crate) struct OpEq; + +impl Op for OpEq { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "==" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + Ok((left == right).into()) + } +} + +pub(crate) struct OpNe; + +impl Op for OpNe { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "!=" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + Ok((left != right).into()) + } +} + +pub(crate) struct OpGt; + +impl Op for OpGt { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + ">" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l > r).into(), + (Value::Float(l), Value::Int(r)) => (l > (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) > r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l > r).into(), + (Value::Text(l), Value::Text(r)) => (l > r).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpGe; + +impl Op for OpGe { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + ">=" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l >= r).into(), + (Value::Float(l), Value::Int(r)) => (l >= (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) >= r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l >= r).into(), + (Value::Text(l), Value::Text(r)) => (l >= r).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpLt; + +impl Op for OpLt { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "<" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l < r).into(), + (Value::Float(l), Value::Int(r)) => (l < (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) < r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l < r).into(), + (Value::Text(l), Value::Text(r)) => (l < r).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} + +pub(crate) struct OpLe; + +impl Op for OpLe { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "<=" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + let res: Value = match (left, right) { + (Value::Int(l), Value::Int(r)) => (l <= r).into(), + (Value::Float(l), Value::Int(r)) => (l <= (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) <= r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l <= r).into(), + (Value::Text(l), Value::Text(r)) => (l <= r).into(), + (l, r) => { + return Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )); + } + }; + Ok(res) + } +} \ No newline at end of file diff --git a/src/data/op/text.rs b/src/data/op/text.rs new file mode 100644 index 00000000..dc262efb --- /dev/null +++ b/src/data/op/text.rs @@ -0,0 +1,31 @@ +use std::result; +use crate::data::eval::EvalError; +use crate::data::op::Op; +use crate::data::value::Value; + +type Result = result::Result; + + +pub(crate) struct OpStrCat; + +impl Op for OpStrCat { + fn arity(&self) -> Option { + Some(2) + } + fn name(&self) -> &str { + "++" + } + fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result> { + match (left, right) { + (Value::Text(l), Value::Text(r)) => { + let mut l = l.into_owned(); + l += r.as_ref(); + Ok(l.into()) + } + (l, r) => Err(EvalError::OpTypeMismatch( + self.name().to_string(), + vec![l.to_static(), r.to_static()], + )), + } + } +} \ No newline at end of file diff --git a/src/data/tuple.rs b/src/data/tuple.rs index 7490bce5..863386d6 100644 --- a/src/data/tuple.rs +++ b/src/data/tuple.rs @@ -1,6 +1,4 @@ -use crate::data::tuple::TupleError::UndefinedDataTag; use crate::data::value::Value; -use chrono::format::Item; use cozorocks::{PinnableSlicePtr, PinnableSlicePtrShared, SlicePtr, SlicePtrShared}; use std::borrow::Cow; use std::cell::RefCell; diff --git a/src/data/tuple_set.rs b/src/data/tuple_set.rs index 03ae4095..ea472ee4 100644 --- a/src/data/tuple_set.rs +++ b/src/data/tuple_set.rs @@ -1,6 +1,5 @@ -use crate::data::tuple::{OwnTuple, ReifiedTuple, Tuple, TupleError}; +use crate::data::tuple::{OwnTuple, ReifiedTuple, TupleError}; use crate::data::value::Value; -use cozorocks::{PinnableSlicePtr, PinnableSlicePtrShared, SlicePtr, SlicePtrShared}; use std::cmp::Ordering; use std::fmt::{Debug, Formatter}; use std::result; diff --git a/src/runtime/instance.rs b/src/runtime/instance.rs index e61beb4d..b1f9bb1a 100644 --- a/src/runtime/instance.rs +++ b/src/runtime/instance.rs @@ -3,20 +3,19 @@ use crate::data::tuple::{DataKind, OwnTuple, Tuple, TupleError}; use crate::data::tuple_set::MIN_TABLE_ID_BOUND; use crate::data::typing::Typing; use crate::data::value::{StaticValue, Value}; -use crate::runtime::instance::DbInstanceError::TableDoesNotExist; use crate::runtime::options::{ default_options, default_read_options, default_txn_db_options, default_txn_options, default_write_options, }; use cozorocks::{ - destroy_db, BridgeError, DbPtr, OptionsPtrShared, PinnableSlicePtr, ReadOptionsPtr, TDbOptions, - TransactOptions, TransactionPtr, WriteOptionsPtr, + destroy_db, BridgeError, DbPtr, OptionsPtrShared, ReadOptionsPtr, TDbOptions, + TransactionPtr, WriteOptionsPtr, }; use lazy_static::lazy_static; use log::error; use std::collections::{BTreeMap, BTreeSet}; use std::sync::atomic::{AtomicU32, Ordering}; -use std::sync::{Arc, LockResult, Mutex, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::{mem, result}; #[derive(thiserror::Error, Debug)]