refactor expr

main
Ziyang Hu 2 years ago
parent 3e5ca6c790
commit 64c1ba3263

@ -4,7 +4,7 @@ Operations
* [x] `from(...rels)`, can use chain notation
* [x] `left_join(left, right, ...conds)`, similarly for `right_join`, `outer_join`)
* [ ] `concat(...rels)`
* [x] `concat(...rels)`
* [ ] `intersect(...rels)`, similarly for `union`
* [ ] `diff(left, right)`, similarly for `sym_diff`
* [x] `select(rel, binding: {..})`
@ -12,7 +12,7 @@ Operations
* [x] `take(rel, n)`
* [x] `skip(rel, n)`
* [x] `sort(rel, expr1, expr2: sort_dir)`
* [ ] `group(rel, binding: {*key1: expr1, val1: expr2})`
* [ ] `group(rel, binding: {*key1: expr1, val1: expr2}, *ordering)` may order elements within groups
* [ ] `walk(pattern, ...conds, ...bindings)`
* [ ] `walk_repeat(pattern, ...conds, ...bindings)` every element contains additional `_iter` and `_visited` fields
* [x] `values(data, ?Table)`

@ -1,7 +1,7 @@
use crate::algebra::op::{InterpretContext, RelationalAlgebra};
use crate::algebra::parser::RaBox;
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::tuple::{OwnTuple, Tuple};
use crate::data::tuple_set::{BindingMap, TupleSet, TupleSetIdx};
use crate::data::value::Value;
@ -16,7 +16,7 @@ pub(crate) struct AssocOp<'a> {
pub(crate) ctx: &'a TempDbContext<'a>,
pub(crate) source: RaBox<'a>,
pub(crate) assoc_infos: Vec<AssocInfo>,
pub(crate) key_extractors: Vec<StaticExpr>,
pub(crate) key_extractors: Vec<Expr>,
pub(crate) binding: String,
}

@ -1,7 +1,7 @@
use crate::algebra::op::RelationalAlgebra;
use crate::algebra::parser::{build_relational_expr, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::tuple::{DataKind, OwnTuple};
use crate::data::tuple_set::{BindingMap, TupleSet, TupleSetIdx};
use crate::data::value::Value;
@ -40,7 +40,7 @@ impl<'a> ConcatOp<'a> {
}
Ok(Self { sources })
}
fn value_entries(&self, binding_map: &BindingMap) -> Result<Vec<StaticExpr>> {
fn value_entries(&self, binding_map: &BindingMap) -> Result<Vec<Expr>> {
let dft = BTreeMap::new();
let own_binding_map = self.binding_map()?;
let mut ret = vec![];
@ -109,7 +109,6 @@ impl<'b> RelationalAlgebra for ConcatOp<'b> {
for source in &self.sources {
let source_map = source.binding_map()?;
let val_extractors = self.value_entries(&source_map)?;
let own_map = self.binding_map()?;
let iter = source.iter()?.map(move |tset| -> Result<TupleSet> {
let tset = tset?;

@ -1,8 +1,7 @@
use crate::algebra::op::RelationalAlgebra;
use crate::algebra::parser::{assert_rule, build_relational_expr, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::op::OpAnd;
use crate::data::expr::{Expr};
use crate::data::tuple_set::{BindingMap, BindingMapEvalContext, TupleSet, TupleSetEvalContext};
use crate::data::value::{StaticValue, Value};
use crate::ddl::reify::TableInfo;
@ -10,14 +9,13 @@ use crate::parser::{Pairs, Rule};
use crate::runtime::options::default_write_options;
use anyhow::Result;
use std::collections::BTreeSet;
use std::sync::Arc;
pub(crate) const NAME_WHERE: &str = "Where";
pub(crate) struct WhereFilter<'a> {
pub(crate) ctx: &'a TempDbContext<'a>,
pub(crate) source: RaBox<'a>,
pub(crate) condition: StaticExpr,
pub(crate) condition: Expr,
}
#[derive(thiserror::Error, Debug)]
@ -42,9 +40,9 @@ impl<'a> WhereFilter<'a> {
let arg = arg.into_inner().next().unwrap();
assert_rule(&arg, Rule::expr, NAME_WHERE, 1)?;
let cond = Expr::try_from(arg)?;
conds.push(cond.into_static());
conds.push(cond);
}
let condition = Expr::Apply(Arc::new(OpAnd), conds);
let condition = Expr::OpAnd(conds);
Ok(Self {
ctx,
source,
@ -75,8 +73,7 @@ impl<'b> RelationalAlgebra for WhereFilter<'b> {
let condition = self
.condition
.clone()
.partial_eval(&binding_ctx)?
.into_static();
.partial_eval(&binding_ctx)?;
let txn = self.ctx.txn.clone();
let temp_db = self.ctx.sess.temp.clone();
let w_opts = default_write_options();

@ -3,7 +3,7 @@ use crate::algebra::op::{
};
use crate::algebra::parser::{assert_rule, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::uuid::random_uuid_v1;
use crate::parser::text_identifier::build_name_in_def;
use crate::parser::{Pair, Pairs, Rule};
@ -89,7 +89,7 @@ pub(crate) fn build_chain<'a>(ctx: &'a TempDbContext<'a>, arg: Pair) -> Result<R
ChainPartEdgeDir::Fwd => "_dst_",
ChainPartEdgeDir::Bwd => "_src_",
};
let left_join_keys: Vec<StaticExpr> = table_info
let left_join_keys: Vec<Expr> = table_info
.as_node()?
.keys
.iter()
@ -121,7 +121,7 @@ pub(crate) fn build_chain<'a>(ctx: &'a TempDbContext<'a>, arg: Pair) -> Result<R
.resolve_table(&cur_el.target)
.ok_or_else(|| AlgebraParseError::TableNotFound(cur_el.target.clone()))?;
let table_info = ctx.get_table_info(edge_id)?;
let mut left_join_keys: Vec<StaticExpr> = vec![Expr::Const(match dir {
let mut left_join_keys: Vec<Expr> = vec![Expr::Const(match dir {
ChainPartEdgeDir::Fwd => true.into(),
ChainPartEdgeDir::Bwd => false.into(),
})];

@ -3,7 +3,7 @@ use crate::algebra::op::{
};
use crate::algebra::parser::{assert_rule, build_relational_expr, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::parser::parse_scoped_dict;
use crate::data::tuple::{DataKind, OwnTuple};
use crate::data::tuple_set::{BindingMap, BindingMapEvalContext, TupleSet, TupleSetEvalContext};
@ -26,7 +26,7 @@ pub(crate) struct Insertion<'a> {
binding: String,
target_info: TableInfo,
assoc_infos: Vec<AssocInfo>,
extract_map: StaticExpr,
extract_map: Expr,
upsert: bool,
}
@ -62,7 +62,6 @@ impl<'a> Insertion<'a> {
AlgebraParseError::Parse("Cannot have keyed map in Insert".to_string()).into(),
);
}
let extract_map = extract_map.into_static();
let target_id = ctx
.resolve_table(&table_name)

@ -1,8 +1,8 @@
use crate::algebra::op::{drop_temp_table, RelationalAlgebra};
use crate::algebra::parser::{assert_rule, build_relational_expr, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::op::NAME_OP_EQ;
use crate::data::expr::{Expr};
use crate::data::op::{OP_EQ};
use crate::data::tuple::{DataKind, OwnTuple, Tuple};
use crate::data::tuple_set::{merge_binding_maps, BindingMap, BindingMapEvalContext, TupleSet};
use crate::ddl::reify::{DdlContext, TableInfo};
@ -23,7 +23,7 @@ pub(crate) struct MergeJoin<'a> {
ctx: &'a TempDbContext<'a>,
pub(crate) left: RaBox<'a>,
pub(crate) right: RaBox<'a>,
pub(crate) join_keys: Vec<(StaticExpr, StaticExpr)>,
pub(crate) join_keys: Vec<(Expr, Expr)>,
pub(crate) left_outer: bool,
pub(crate) right_outer: bool,
left_temp_id: AtomicU32,
@ -33,11 +33,11 @@ pub(crate) struct MergeJoin<'a> {
#[derive(thiserror::Error, Debug)]
pub(crate) enum JoinError {
#[error("Invalid join condition {0:?}")]
JoinCondition(StaticExpr),
JoinCondition(Expr),
#[error("Join condition {0:?} must contain variables {1:?}")]
NoBoundVariable(StaticExpr, BTreeSet<String>),
NoBoundVariable(Expr, BTreeSet<String>),
#[error("Join condition {0:?} must not contain variables {1:?}")]
WrongBoundVariable(StaticExpr, BTreeSet<String>),
WrongBoundVariable(Expr, BTreeSet<String>),
}
impl<'a> MergeJoin<'a> {
@ -66,16 +66,16 @@ impl<'a> MergeJoin<'a> {
)
.into());
}
let mut join_keys: Vec<(StaticExpr, StaticExpr)> = vec![];
let mut join_keys: Vec<(Expr, Expr)> = vec![];
for (i, arg) in args.enumerate() {
let pair = arg.into_inner().next().unwrap();
assert_rule(&pair, Rule::expr, kind, i + 2)?;
let expr = Expr::try_from(pair)?;
match expr {
Expr::Apply(op, args) if op.name() == NAME_OP_EQ => {
Expr::BuiltinFn(op, args) if op == OP_EQ => {
let mut args = args.into_iter();
let left_condition = args.next().unwrap().into_static();
let right_condition = args.next().unwrap().into_static();
let left_condition = args.next().unwrap();
let right_condition = args.next().unwrap();
let left_variables = left_condition.all_variables();
let right_variables = right_condition.all_variables();
if left_variables.is_disjoint(&left_bindings) {
@ -100,7 +100,7 @@ impl<'a> MergeJoin<'a> {
}
join_keys.push((left_condition, right_condition))
}
ex => return Err(JoinError::JoinCondition(ex.into_static()).into()),
ex => return Err(JoinError::JoinCondition(ex).into()),
}
}
@ -115,12 +115,7 @@ impl<'a> MergeJoin<'a> {
right_temp_id: Default::default(),
})
}
fn materialize(
&self,
temp_table_id: u32,
keys: Vec<StaticExpr>,
source: &RaBox<'a>,
) -> Result<()> {
fn materialize(&self, temp_table_id: u32, keys: Vec<Expr>, source: &RaBox<'a>) -> Result<()> {
let source_map = source.binding_map()?;
let binding_ctx = BindingMapEvalContext {
map: &source_map,

@ -1,7 +1,6 @@
use crate::algebra::op::{build_binding_map_from_info, QueryError, RelationalAlgebra};
use crate::algebra::parser::RaBox;
use crate::context::TempDbContext;
use crate::data::expr::StaticExpr;
use crate::data::tuple::{DataKind, OwnTuple, ReifiedTuple, Tuple};
use crate::data::tuple_set::{
shift_merge_binding_map, BindingMap, BindingMapEvalContext, TableId, TupleSet,
@ -12,6 +11,7 @@ use crate::runtime::options::{default_read_options, default_write_options};
use anyhow::Result;
use cozorocks::{DbPtr, PrefixIterator, ReadOptionsPtr, TransactionPtr, WriteOptionsPtr};
use std::collections::{BTreeMap, BTreeSet};
use crate::data::expr::Expr;
pub(crate) const NAME_NESTED_LOOP_LEFT: &str = "NestedLoop";
@ -21,7 +21,7 @@ pub(crate) struct NestedLoopLeft<'a> {
pub(crate) right: TableInfo,
pub(crate) right_binding: String,
pub(crate) left_outer_join: bool,
pub(crate) join_key_extractor: Vec<StaticExpr>,
pub(crate) join_key_extractor: Vec<Expr>,
pub(crate) key_is_prefix: bool,
}
@ -73,7 +73,7 @@ impl<'b> RelationalAlgebra for NestedLoopLeft<'b> {
.map(|ex| {
ex.clone()
.partial_eval(&binding_ctx)
.map(|ex| ex.into_static())
.map(|ex| ex)
})
.collect::<Result<Vec<_>>>()?;
let table_id = self.right.table_id();
@ -164,7 +164,7 @@ pub(crate) struct NestLoopLeftPrefixIter<'a> {
left_iter: Box<dyn Iterator<Item = Result<TupleSet>> + 'a>,
right_iter: PrefixIterator<OwnTuple>,
right_table_id: TableId,
key_extractors: Vec<StaticExpr>,
key_extractors: Vec<Expr>,
left_cache: Option<TupleSet>,
left_cache_used: bool,
txn: TransactionPtr,

@ -1,7 +1,7 @@
use crate::algebra::op::RelationalAlgebra;
use crate::algebra::parser::{assert_rule, build_relational_expr, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::parser::{parse_keyed_dict, parse_scoped_dict};
use crate::data::tuple::{DataKind, OwnTuple};
use crate::data::tuple_set::{
@ -20,7 +20,7 @@ pub(crate) struct SelectOp<'a> {
ctx: &'a TempDbContext<'a>,
pub(crate) source: RaBox<'a>,
binding: String,
extract_map: StaticExpr,
extract_map: Expr,
}
impl<'a> SelectOp<'a> {
@ -56,7 +56,7 @@ impl<'a> SelectOp<'a> {
AlgebraParseError::Parse("Cannot have keyed map in Select".to_string()).into(),
);
}
let extract_map = extract_map.into_static();
Ok(Self {
ctx,
source,
@ -69,7 +69,7 @@ impl<'a> SelectOp<'a> {
#[derive(thiserror::Error, Debug)]
pub(crate) enum SelectOpError {
#[error("Selection needs a dict, got {0:?}")]
NeedsDict(StaticExpr),
NeedsDict(Expr),
}
impl<'b> RelationalAlgebra for SelectOp<'b> {
@ -116,7 +116,7 @@ impl<'b> RelationalAlgebra for SelectOp<'b> {
)
})
.collect::<BTreeMap<_, _>>(),
ex => return Err(SelectOpError::NeedsDict(ex.into_static()).into()),
ex => return Err(SelectOpError::NeedsDict(ex).into()),
};
Ok(BindingMap {
inner_map: BTreeMap::from([(self.binding.clone(), extract_map)]),
@ -135,14 +135,13 @@ impl<'b> RelationalAlgebra for SelectOp<'b> {
.extract_map
.clone()
.partial_eval(&binding_ctx)?
.into_static()
{
Expr::Dict(d) => d.values().cloned().collect::<Vec<_>>(),
Expr::Const(Value::Dict(d)) => d
.values()
.map(|v| Expr::Const(v.clone()))
.collect::<Vec<_>>(),
ex => return Err(SelectOpError::NeedsDict(ex.into_static()).into()),
ex => return Err(SelectOpError::NeedsDict(ex).into()),
};
let txn = self.ctx.txn.clone();

@ -1,7 +1,7 @@
use crate::algebra::op::RelationalAlgebra;
use crate::algebra::parser::{build_relational_expr, AlgebraParseError, RaBox};
use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::tuple::{DataKind, OwnTuple, Tuple};
use crate::data::tuple_set::{BindingMap, BindingMapEvalContext, TupleSet, MIN_TABLE_ID_BOUND};
use crate::data::value::Value;
@ -25,7 +25,7 @@ pub(crate) enum SortDirection {
pub(crate) struct SortOp<'a> {
pub(crate) source: RaBox<'a>,
ctx: &'a TempDbContext<'a>,
sort_exprs: Vec<(StaticExpr, SortDirection)>,
sort_exprs: Vec<(Expr, SortDirection)>,
temp_table_id: AtomicU32,
}
@ -42,7 +42,7 @@ impl<'a> SortOp<'a> {
};
let sort_exprs = args
.map(|arg| -> Result<(StaticExpr, SortDirection)> {
.map(|arg| -> Result<(Expr, SortDirection)> {
let mut arg = arg.into_inner().next().unwrap();
let mut dir = SortDirection::Asc;
if arg.as_rule() == Rule::sort_arg {
@ -52,7 +52,7 @@ impl<'a> SortOp<'a> {
dir = SortDirection::Dsc
}
}
let expr = Expr::try_from(arg)?.into_static();
let expr = Expr::try_from(arg)?;
Ok((expr, dir))
})
.collect::<Result<Vec<_>>>()?;
@ -74,8 +74,8 @@ impl<'a> SortOp<'a> {
let sort_exprs = self
.sort_exprs
.iter()
.map(|(ex, dir)| -> Result<(StaticExpr, SortDirection)> {
let ex = ex.clone().partial_eval(&binding_ctx)?.into_static();
.map(|(ex, dir)| -> Result<(Expr, SortDirection)> {
let ex = ex.clone().partial_eval(&binding_ctx)?;
Ok((ex, *dir))
})
.collect::<Result<Vec<_>>>()?;

@ -1,4 +1,4 @@
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::Expr;
use crate::data::op::*;
use crate::data::tuple_set::TupleSetIdx;
use crate::data::value::{StaticValue, Value};
@ -13,17 +13,14 @@ pub enum EvalError {
UnresolvedVariable(String),
#[error("Cannot access field {0} for {1:?}")]
FieldAccess(String, StaticExpr),
FieldAccess(String, Expr),
#[error("Cannot access index {0} for {1:?}")]
IndexAccess(usize, StaticExpr),
IndexAccess(usize, Expr),
#[error("Cannot apply `{0}` to `{1:?}`")]
OpTypeMismatch(String, Vec<StaticValue>),
#[error("Optimized before partial eval")]
OptimizedBeforePartialEval,
#[error("Arity mismatch for {0}, {1} arguments given ")]
ArityMismatch(String, usize),
@ -77,27 +74,27 @@ impl PartialEvalContext for () {
}
}
fn extract_optimized_bin_args(args: Vec<Expr>) -> (Expr, Expr) {
let mut args = args.into_iter();
(
args.next().unwrap().optimize_ops(),
args.next().unwrap().optimize_ops(),
)
}
// fn extract_optimized_bin_args(args: Vec<Expr>) -> (Expr, Expr) {
// let mut args = args.into_iter();
// (
// args.next().unwrap().optimize_ops(),
// args.next().unwrap().optimize_ops(),
// )
// }
fn extract_optimized_u_args(args: Vec<Expr>) -> Expr {
args.into_iter().next().unwrap().optimize_ops()
}
// fn extract_optimized_u_args(args: Vec<Expr>) -> Expr {
// args.into_iter().next().unwrap().optimize_ops()
// }
impl<'a> Expr<'a> {
pub(crate) fn interpret_eval<C: PartialEvalContext>(self, ctx: &'a C) -> Result<Value> {
impl Expr {
pub(crate) fn interpret_eval<C: PartialEvalContext>(self, ctx: &C) -> Result<Value> {
match self.partial_eval(ctx)? {
Expr::Const(v) => Ok(v),
v => Err(EvalError::IncompleteEvaluation(format!("{:?}", v)).into()),
}
}
pub(crate) fn partial_eval<C: PartialEvalContext>(self, ctx: &'a C) -> Result<Self> {
pub(crate) fn partial_eval<C: PartialEvalContext>(self, ctx: &C) -> Result<Self> {
let res = match self {
v @ (Expr::Const(_) | Expr::TupleSetIdx(_)) => v,
Expr::List(l) => {
@ -145,30 +142,29 @@ impl<'a> Expr<'a> {
Expr::Variable(var) => ctx
.resolve(&var)
.ok_or(EvalError::UnresolvedVariable(var))?,
Expr::FieldAcc(f, arg) => {
match *arg {
Expr::Dict(mut d) => {
// This skips evaluation of other keys
d.remove(&f as &str)
.unwrap_or(Expr::Const(Value::Null))
.partial_eval(ctx)?
}
arg => match arg.partial_eval(ctx)? {
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::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, v.into_static()).into()),
},
Expr::FieldAcc(f, arg) => match *arg {
Expr::Dict(mut d) => {
// This skips evaluation of other keys
d.remove(&f as &str)
.unwrap_or(Expr::Const(Value::Null))
.partial_eval(ctx)?
}
}
arg => match arg.partial_eval(ctx)? {
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::BuiltinFn(_, _)
| Expr::ApplyAgg(_, _, _)
| Expr::OpConcat(_)
| Expr::OpMerge(_)
| Expr::OpCoalesce(_)) => 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, v).into()),
},
},
Expr::IdxAcc(i, arg) => {
match *arg {
// This skips evaluation of other keys
@ -197,57 +193,51 @@ impl<'a> Expr<'a> {
}
v @ (Expr::IdxAcc(_, _)
| Expr::FieldAcc(_, _)
| Expr::Apply(_, _)
| Expr::BuiltinFn(_, _)
| Expr::ApplyAgg(_, _, _)) => Expr::IdxAcc(i, v.into()),
v => return Err(EvalError::IndexAccess(i, v.into_static()).into()),
v => return Err(EvalError::IndexAccess(i, v).into()),
},
}
}
Expr::Apply(op, args) => {
if let Some(n) = op.arity() {
if n != args.len() {
Expr::BuiltinFn(op, args) => {
if let Some(n) = op.arity {
if n as usize != args.len() {
return Err(
EvalError::ArityMismatch(op.name().to_string(), args.len()).into()
EvalError::ArityMismatch(op.name.to_string(), args.len()).into()
);
}
}
match op.name() {
// special cases
NAME_OP_AND => partial_eval_and(ctx, args)?,
NAME_OP_OR => partial_eval_or(ctx, args)?,
NAME_OP_COALESCE => partial_eval_coalesce(ctx, args)?,
NAME_OP_MERGE => partial_eval_merge_expr(ctx, args)?,
NAME_OP_CONCAT => partial_eval_concat_expr(ctx, args)?,
_ => {
let mut has_unevaluated = false;
let non_null_args_fn = op.non_null_args();
let mut eval_args = Vec::with_capacity(args.len());
for v in args {
let v = v.partial_eval(ctx)?;
if !matches!(v, Expr::Const(_)) {
has_unevaluated = true;
eval_args.push(v);
} else if non_null_args_fn && matches!(v, Expr::Const(Value::Null)) {
return Ok(Expr::Const(Value::Null));
} else {
eval_args.push(v);
}
}
if has_unevaluated {
Expr::Apply(op, eval_args)
} else {
let args = eval_args
.into_iter()
.map(|v| match v {
Expr::Const(v) => v,
_ => unreachable!(),
})
.collect();
op.eval(args).map(Expr::Const)?
}
let mut has_unevaluated = false;
let mut eval_args = Vec::with_capacity(args.len());
for v in args {
let v = v.partial_eval(ctx)?;
if !matches!(v, Expr::Const(_)) {
has_unevaluated = true;
eval_args.push(v);
} else if op.non_null_args && matches!(v, Expr::Const(Value::Null)) {
return Ok(Expr::Const(Value::Null));
} else {
eval_args.push(v);
}
}
if has_unevaluated {
Expr::BuiltinFn(op, eval_args)
} else {
let args = eval_args
.into_iter()
.map(|v| match v {
Expr::Const(v) => v,
_ => unreachable!(),
})
.collect::<Vec<_>>();
(op.func)(&args).map(Expr::Const)?
}
}
Expr::OpMerge(args) => partial_eval_merge_expr(ctx, args)?,
Expr::OpConcat(args) => partial_eval_concat_expr(ctx, args)?,
Expr::OpOr(args) => partial_eval_or(ctx, args)?,
Expr::OpAnd(args) => partial_eval_and(ctx, args)?,
Expr::OpCoalesce(args) => partial_eval_coalesce(ctx, args)?,
Expr::ApplyAgg(op, a_args, args) => {
let a_args = a_args
.into_iter()
@ -264,129 +254,10 @@ impl<'a> Expr<'a> {
partial_eval_if_expr(ctx, cond, if_part, else_part)?
}
Expr::SwitchExpr(args) => partial_eval_switch_expr(ctx, 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::Not(_)
| Expr::Minus(_)
| Expr::IsNull(_)
| Expr::NotNull(_)
| Expr::Coalesce(_)
| Expr::Or(_)
| Expr::And(_) => return Err(EvalError::OptimizedBeforePartialEval.into()),
};
Ok(res)
}
pub(crate) fn optimize_ops(self) -> Self {
// Note: `and`, `or` and `coalesce` do not short-circuit if not optimized
match self {
Expr::List(l) => Expr::List(l.into_iter().map(|v| v.optimize_ops()).collect()),
Expr::Dict(d) => {
Expr::Dict(d.into_iter().map(|(k, v)| (k, v.optimize_ops())).collect())
}
Expr::Apply(op, args) => match op.name() {
NAME_OP_ADD => Expr::Add(extract_optimized_bin_args(args).into()),
NAME_OP_SUB => Expr::Sub(extract_optimized_bin_args(args).into()),
NAME_OP_MUL => Expr::Mul(extract_optimized_bin_args(args).into()),
NAME_OP_DIV => Expr::Div(extract_optimized_bin_args(args).into()),
NAME_OP_POW => Expr::Pow(extract_optimized_bin_args(args).into()),
NAME_OP_MOD => Expr::Mod(extract_optimized_bin_args(args).into()),
NAME_OP_STR_CAT => Expr::StrCat(extract_optimized_bin_args(args).into()),
NAME_OP_EQ => Expr::Eq(extract_optimized_bin_args(args).into()),
NAME_OP_NE => Expr::Ne(extract_optimized_bin_args(args).into()),
NAME_OP_GT => Expr::Gt(extract_optimized_bin_args(args).into()),
NAME_OP_GE => Expr::Ge(extract_optimized_bin_args(args).into()),
NAME_OP_LT => Expr::Lt(extract_optimized_bin_args(args).into()),
NAME_OP_LE => Expr::Le(extract_optimized_bin_args(args).into()),
NAME_OP_NOT => Expr::Not(extract_optimized_u_args(args).into()),
NAME_OP_MINUS => Expr::Minus(extract_optimized_u_args(args).into()),
NAME_OP_IS_NULL => Expr::IsNull(extract_optimized_u_args(args).into()),
NAME_OP_NOT_NULL => Expr::NotNull(extract_optimized_u_args(args).into()),
NAME_OP_COALESCE => {
let mut args = args.into_iter();
let mut arg = args.next().unwrap().optimize_ops();
for nxt in args {
arg = Expr::Coalesce((arg, nxt.optimize_ops()).into());
}
arg
}
NAME_OP_OR => {
let mut args = args.into_iter();
let mut arg = args.next().unwrap().optimize_ops();
for nxt in args {
arg = Expr::Or((arg, nxt.optimize_ops()).into());
}
arg
}
NAME_OP_AND => {
let mut args = args.into_iter();
let mut arg = args.next().unwrap().optimize_ops();
for nxt in args {
arg = Expr::And((arg, nxt.optimize_ops()).into());
}
arg
}
_ => Expr::Apply(op, args.into_iter().map(|v| v.optimize_ops()).collect()),
},
Expr::ApplyAgg(op, a_args, args) => Expr::ApplyAgg(
op,
a_args.into_iter().map(|v| v.optimize_ops()).collect(),
args.into_iter().map(|v| v.optimize_ops()).collect(),
),
Expr::FieldAcc(f, arg) => Expr::FieldAcc(f, arg.optimize_ops().into()),
Expr::IdxAcc(i, arg) => Expr::IdxAcc(i, arg.optimize_ops().into()),
Expr::IfExpr(args) => {
let (cond, if_part, else_part) = *args;
Expr::IfExpr(
(
cond.optimize_ops(),
if_part.optimize_ops(),
else_part.optimize_ops(),
)
.into(),
)
}
Expr::SwitchExpr(args) => Expr::SwitchExpr(
args.into_iter()
.map(|(e1, e2)| (e1.optimize_ops(), e2.optimize_ops()))
.collect(),
),
v @ (Expr::Const(_)
| Expr::Variable(_)
| Expr::TupleSetIdx(_)
| 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::Not(_)
| Expr::Minus(_)
| Expr::IsNull(_)
| Expr::NotNull(_)
| Expr::Coalesce(_)
| Expr::Or(_)
| Expr::And(_)) => v,
}
}
pub(crate) fn row_eval<C: RowEvalContext + 'a>(&'a self, ctx: &'a C) -> Result<Value<'a>> {
pub(crate) fn row_eval<'a, C: RowEvalContext + 'a>(&'a self, ctx: &'a C) -> Result<Value<'a>> {
let res: Value = match self {
Expr::Const(v) => v.clone(),
Expr::List(l) => l
@ -404,18 +275,17 @@ impl<'a> Expr<'a> {
.into(),
Expr::Variable(v) => return Err(EvalError::UnresolvedVariable(v.clone()).into()),
Expr::TupleSetIdx(idx) => ctx.resolve(idx)?.clone(),
Expr::Apply(op, args) => {
Expr::BuiltinFn(op, args) => {
let mut eval_args = Vec::with_capacity(args.len());
let op_non_null_args = op.non_null_args();
for v in args {
let v = v.row_eval(ctx)?;
if op_non_null_args && v == Value::Null {
if op.non_null_args && v == Value::Null {
return Ok(Value::Null);
} else {
eval_args.push(v);
}
}
op.eval(eval_args)?
(op.func)(&eval_args)?
}
Expr::ApplyAgg(_, _, _) => {
todo!()
@ -445,151 +315,11 @@ impl<'a> Expr<'a> {
row_eval_if_expr(ctx, cond, if_part, else_part)?
}
Expr::SwitchExpr(args) => row_eval_switch_expr(ctx, args)?,
// optimized implementations, not really necessary
Expr::Add(args) => OpAdd.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Sub(args) => OpSub.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Mul(args) => OpMul.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Div(args) => OpDiv.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Pow(args) => OpPow.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Mod(args) => OpMod.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::StrCat(args) => OpStrCat.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Eq(args) => OpEq.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Ne(args) => OpNe.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Gt(args) => OpGt.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Ge(args) => OpGe.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Lt(args) => OpLt.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Le(args) => OpLe.eval_two_non_null(
match args.as_ref().0.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
match args.as_ref().1.row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
},
)?,
Expr::Not(arg) => OpNot.eval_one_non_null(match arg.as_ref().row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
})?,
Expr::Minus(arg) => OpMinus.eval_one_non_null(match arg.as_ref().row_eval(ctx)? {
v @ Value::Null => return Ok(v),
v => v,
})?,
Expr::IsNull(arg) => OpIsNull.eval_one(arg.as_ref().row_eval(ctx)?)?,
Expr::NotNull(arg) => OpNotNull.eval_one(arg.as_ref().row_eval(ctx)?)?,
// These implementations are special in that they short-circuit
Expr::Coalesce(args) => row_eval_coalesce(ctx, &args.as_ref().0, &args.as_ref().1)?,
Expr::Or(args) => row_eval_or(ctx, &args.as_ref().0, &args.as_ref().1)?,
Expr::And(args) => row_eval_and(ctx, &args.as_ref().0, &args.as_ref().1)?,
Expr::OpAnd(args) => row_eval_and(ctx, args)?,
Expr::OpOr(args) => row_eval_or(ctx, args)?,
Expr::OpCoalesce(args) => row_eval_coalesce(ctx, args)?,
Expr::OpMerge(args) => row_eval_merge(ctx, args)?,
Expr::OpConcat(args) => row_eval_concat(ctx, args)?
};
Ok(res)
}

@ -1,7 +1,4 @@
use crate::data::op::{
AggOp, Op, OpAdd, OpAnd, OpCoalesce, OpDiv, OpEq, OpGe, OpGt, OpIsNull, OpLe, OpLt, OpMinus,
OpMod, OpMul, OpNe, OpNot, OpNotNull, OpOr, OpPow, OpStrCat, OpSub, UnresolvedOp,
};
use crate::data::op::*;
use crate::data::tuple_set::TupleSetIdx;
use crate::data::value::{StaticValue, Value};
use crate::parser::{CozoParser, Rule};
@ -10,7 +7,6 @@ use pest::Parser;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use std::result;
use std::sync::Arc;
#[derive(thiserror::Error, Debug)]
pub enum ExprError {
@ -28,46 +24,47 @@ pub enum ExprError {
}
#[derive(Clone)]
pub enum Expr<'a> {
Const(Value<'a>),
List(Vec<Expr<'a>>),
Dict(BTreeMap<String, Expr<'a>>),
pub struct BuiltinFn {
pub(crate) name: &'static str,
pub(crate) arity: Option<u8>,
pub(crate) non_null_args: bool,
pub(crate) func: for<'a> fn(&[Value<'a>]) -> Result<Value<'a>>,
}
impl PartialEq for BuiltinFn {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for BuiltinFn {}
#[derive(Clone, PartialEq, Eq)]
pub enum Expr {
Const(StaticValue),
List(Vec<Expr>),
Dict(BTreeMap<String, Expr>),
Variable(String),
TupleSetIdx(TupleSetIdx),
Apply(Arc<dyn Op + Send + Sync>, Vec<Expr<'a>>),
ApplyAgg(Arc<dyn AggOp + Send + Sync>, Vec<Expr<'a>>, Vec<Expr<'a>>),
FieldAcc(String, Box<Expr<'a>>),
IdxAcc(usize, Box<Expr<'a>>),
IfExpr(Box<(Expr<'a>, Expr<'a>, Expr<'a>)>),
SwitchExpr(Vec<(Expr<'a>, Expr<'a>)>),
// optimized
Add(Box<(Expr<'a>, Expr<'a>)>),
Sub(Box<(Expr<'a>, Expr<'a>)>),
Mul(Box<(Expr<'a>, Expr<'a>)>),
Div(Box<(Expr<'a>, Expr<'a>)>),
Pow(Box<(Expr<'a>, Expr<'a>)>),
Mod(Box<(Expr<'a>, Expr<'a>)>),
StrCat(Box<(Expr<'a>, Expr<'a>)>),
Eq(Box<(Expr<'a>, Expr<'a>)>),
Ne(Box<(Expr<'a>, Expr<'a>)>),
Gt(Box<(Expr<'a>, Expr<'a>)>),
Ge(Box<(Expr<'a>, Expr<'a>)>),
Lt(Box<(Expr<'a>, Expr<'a>)>),
Le(Box<(Expr<'a>, Expr<'a>)>),
Not(Box<Expr<'a>>),
Minus(Box<Expr<'a>>),
IsNull(Box<Expr<'a>>),
NotNull(Box<Expr<'a>>),
Coalesce(Box<(Expr<'a>, Expr<'a>)>),
Or(Box<(Expr<'a>, Expr<'a>)>),
And(Box<(Expr<'a>, Expr<'a>)>),
// Apply(Arc<dyn Op + Send + Sync>, Vec<Expr>),
ApplyAgg((), Vec<Expr>, Vec<Expr>),
FieldAcc(String, Box<Expr>),
IdxAcc(usize, Box<Expr>),
IfExpr(Box<(Expr, Expr, Expr)>),
SwitchExpr(Vec<(Expr, Expr)>),
OpAnd(Vec<Expr>),
OpOr(Vec<Expr>),
OpCoalesce(Vec<Expr>),
OpMerge(Vec<Expr>),
OpConcat(Vec<Expr>),
BuiltinFn(BuiltinFn, Vec<Expr>),
}
impl<'a> Expr<'a> {
impl Expr {
pub(crate) fn is_const(&self) -> bool {
matches!(self, Expr::Const(_))
}
pub(crate) fn extract_const(self) -> Option<Value<'a>> {
pub(crate) fn extract_const(self) -> Option<StaticValue> {
match self {
Expr::Const(v) => Some(v),
_ => None,
@ -92,7 +89,7 @@ impl<'a> Expr<'a> {
accum.insert(v.clone());
}
Expr::TupleSetIdx(_) => {}
Expr::Apply(_, args) => {
Expr::BuiltinFn(_, args) => {
for el in args {
collect(el, accum);
}
@ -129,126 +126,33 @@ impl<'a> Expr<'a> {
collect(self, &mut ret);
ret
}
pub(crate) fn into_static(self) -> StaticExpr {
match self {
Expr::Const(v) => Expr::Const(v.into_static()),
Expr::List(l) => Expr::List(l.into_iter().map(|v| v.into_static()).collect()),
Expr::Dict(d) => Expr::Dict(d.into_iter().map(|(k, v)| (k, v.into_static())).collect()),
Expr::Variable(v) => Expr::Variable(v),
Expr::TupleSetIdx(idx) => Expr::TupleSetIdx(idx),
Expr::Apply(op, args) => {
Expr::Apply(op, args.into_iter().map(|v| v.into_static()).collect())
}
Expr::ApplyAgg(op, a_args, args) => Expr::ApplyAgg(
op,
a_args.into_iter().map(|v| v.into_static()).collect(),
args.into_iter().map(|v| v.into_static()).collect(),
),
Expr::FieldAcc(f, arg) => Expr::FieldAcc(f, arg.into_static().into()),
Expr::IdxAcc(i, arg) => Expr::IdxAcc(i, arg.into_static().into()),
Expr::IfExpr(args) => {
let (a, b, c) = *args;
Expr::IfExpr((a.into_static(), b.into_static(), c.into_static()).into())
}
Expr::SwitchExpr(args) => Expr::SwitchExpr(
args.into_iter()
.map(|(a, b)| (a.into_static(), b.into_static()))
.collect(),
),
Expr::Add(args) => {
let (a, b) = *args;
Expr::Add((a.into_static(), b.into_static()).into())
}
Expr::Sub(args) => {
let (a, b) = *args;
Expr::Sub((a.into_static(), b.into_static()).into())
}
Expr::Mul(args) => {
let (a, b) = *args;
Expr::Mul((a.into_static(), b.into_static()).into())
}
Expr::Div(args) => {
let (a, b) = *args;
Expr::Div((a.into_static(), b.into_static()).into())
}
Expr::Pow(args) => {
let (a, b) = *args;
Expr::Pow((a.into_static(), b.into_static()).into())
}
Expr::Mod(args) => {
let (a, b) = *args;
Expr::Mod((a.into_static(), b.into_static()).into())
}
Expr::StrCat(args) => {
let (a, b) = *args;
Expr::StrCat((a.into_static(), b.into_static()).into())
}
Expr::Eq(args) => {
let (a, b) = *args;
Expr::Eq((a.into_static(), b.into_static()).into())
}
Expr::Ne(args) => {
let (a, b) = *args;
Expr::Ne((a.into_static(), b.into_static()).into())
}
Expr::Gt(args) => {
let (a, b) = *args;
Expr::Gt((a.into_static(), b.into_static()).into())
}
Expr::Ge(args) => {
let (a, b) = *args;
Expr::Ge((a.into_static(), b.into_static()).into())
}
Expr::Lt(args) => {
let (a, b) = *args;
Expr::Lt((a.into_static(), b.into_static()).into())
}
Expr::Le(args) => {
let (a, b) = *args;
Expr::Le((a.into_static(), b.into_static()).into())
}
Expr::Not(arg) => Expr::Not(arg.into_static().into()),
Expr::Minus(arg) => Expr::Minus(arg.into_static().into()),
Expr::IsNull(arg) => Expr::IsNull(arg.into_static().into()),
Expr::NotNull(arg) => Expr::NotNull(arg.into_static().into()),
Expr::Coalesce(args) => {
let (a, b) = *args;
Expr::Coalesce((a.into_static(), b.into_static()).into())
}
Expr::Or(args) => {
let (a, b) = *args;
Expr::Or((a.into_static(), b.into_static()).into())
}
Expr::And(args) => {
let (a, b) = *args;
Expr::And((a.into_static(), b.into_static()).into())
}
}
}
}
impl<'a> PartialEq for Expr<'a> {
fn eq(&self, other: &Self) -> bool {
use Expr::*;
match (self, other) {
(Const(l), Const(r)) => l == r,
(List(l), List(r)) => l == r,
(Dict(l), Dict(r)) => l == r,
(Variable(l), Variable(r)) => l == r,
(TupleSetIdx(l), TupleSetIdx(r)) => l == r,
(Apply(lo, la), Apply(ro, ra)) => (lo.name() == ro.name()) && (la == ra),
(ApplyAgg(lo, laa, la), ApplyAgg(ro, raa, ra)) => {
(lo.name() == ro.name()) && (laa == raa) && (la == ra)
}
(FieldAcc(lf, la), FieldAcc(rf, ra)) => (lf == rf) && (la == ra),
(IdxAcc(li, la), IdxAcc(ri, ra)) => (li == ri) && (la == ra),
_ => false,
fn write_fn_call<'a, T: IntoIterator<Item = &'a [Expr]>>(
f: &mut Formatter,
name: &str,
args_iter: T,
) -> std::fmt::Result {
write!(f, "({}", name)?;
for (i, args) in args_iter.into_iter().enumerate() {
if i == 0 {
write!(f, " ")?;
} else {
write!(f, "; ")?;
}
write!(
f,
"{}",
args.iter()
.map(|v| format!("{:?}", v))
.collect::<Vec<_>>()
.join(" ")
)?
}
Ok(())
}
impl<'a> Debug for Expr<'a> {
impl<'a> Debug for Expr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Const(c) => write!(f, "{}", c),
@ -256,39 +160,10 @@ impl<'a> Debug for Expr<'a> {
Expr::Dict(d) => write!(f, "{:?}", d),
Expr::Variable(v) => write!(f, "`{}`", v),
Expr::TupleSetIdx(sid) => write!(f, "{:?}", sid),
Expr::Apply(op, args) => write!(
f,
"({} {})",
op.name(),
args.iter()
.map(|v| format!("{:?}", v))
.collect::<Vec<_>>()
.join(" ")
),
Expr::Add(args) => write!(f, "(`+ {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Sub(args) => write!(f, "(`- {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Mul(args) => write!(f, "(`* {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Div(args) => write!(f, "(`/ {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Pow(args) => write!(f, "(`** {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Mod(args) => write!(f, "(`% {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::StrCat(args) => write!(f, "(`++ {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Eq(args) => write!(f, "(`== {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Ne(args) => write!(f, "(`!= {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Gt(args) => write!(f, "(`> {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Ge(args) => write!(f, "(`>= {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Lt(args) => write!(f, "(`< {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Le(args) => write!(f, "(`<= {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Not(arg) => write!(f, "(`! {:?})", arg.as_ref()),
Expr::Minus(arg) => write!(f, "(`-- {:?})", arg.as_ref()),
Expr::IsNull(arg) => write!(f, "(`is_null {:?})", arg.as_ref()),
Expr::NotNull(arg) => write!(f, "(`not_null {:?})", arg.as_ref()),
Expr::Coalesce(args) => write!(f, "(`~ {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::Or(args) => write!(f, "(`|| {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::And(args) => write!(f, "(`&& {:?} {:?})", args.as_ref().0, args.as_ref().1),
Expr::ApplyAgg(op, a_args, args) => write!(
f,
"[|{} {} | {}|]",
op.name(),
todo!(),
a_args
.iter()
.map(|v| format!("{:?}", v))
@ -314,12 +189,16 @@ impl<'a> Debug for Expr<'a> {
}
Expr::FieldAcc(field, arg) => write!(f, "(.{} {:?})", field, arg),
Expr::IdxAcc(i, arg) => write!(f, "(.{} {:?})", i, arg),
Expr::OpAnd(args) => write_fn_call(f, "&&", [args.as_ref()]),
Expr::OpOr(args) => write_fn_call(f, "||", [args.as_ref()]),
Expr::OpCoalesce(args) => write_fn_call(f, "~", [args.as_ref()]),
Expr::OpMerge(args) => write_fn_call(f, "merge", [args.as_ref()]),
Expr::OpConcat(args) => write_fn_call(f, "concat", [args.as_ref()]),
Expr::BuiltinFn(op, args) => write_fn_call(f, op.name, [args.as_ref()]),
}
}
}
pub type StaticExpr = Expr<'static>;
fn extract_list_from_value(value: Value, n: usize) -> Result<Vec<Value>> {
if let Value::List(l) = value {
if n > 0 && l.len() != n {
@ -331,18 +210,18 @@ fn extract_list_from_value(value: Value, n: usize) -> Result<Vec<Value>> {
}
}
impl<'a> TryFrom<Value<'a>> for Expr<'a> {
impl TryFrom<StaticValue> for Expr {
type Error = anyhow::Error;
fn try_from(value: Value<'a>) -> Result<Self> {
fn try_from(value: StaticValue) -> Result<Self> {
if let Value::Dict(d) = value {
if d.len() != 1 {
return Err(ExprError::ConversionFailure(Value::Dict(d).into_static()).into());
}
let (k, v) = d.into_iter().next().unwrap();
match k.as_ref() {
"Const" => Ok(Expr::Const(v)),
"List" => {
EXPR_TAG_CONST => Ok(Expr::Const(v)),
EXPR_TAG_LIST => {
let l = extract_list_from_value(v, 0)?;
Ok(Expr::List(
l.into_iter()
@ -350,7 +229,7 @@ impl<'a> TryFrom<Value<'a>> for Expr<'a> {
.collect::<Result<Vec<_>>>()?,
))
}
"Dict" => match v {
EXPR_TAG_DICT => match v {
Value::Dict(d) => Ok(Expr::Dict(
d.into_iter()
.map(|(k, v)| -> Result<(String, Expr)> {
@ -365,7 +244,7 @@ impl<'a> TryFrom<Value<'a>> for Expr<'a> {
.into());
}
},
"Variable" => {
EXPR_TAG_VARIABLE => {
if let Value::Text(t) = v {
Ok(Expr::Variable(t.to_string()))
} else {
@ -375,7 +254,7 @@ impl<'a> TryFrom<Value<'a>> for Expr<'a> {
.into());
}
}
"TupleSetIdx" => {
EXPR_TAG_TUPLE_SET_IDX => {
let mut l = extract_list_from_value(v, 3)?.into_iter();
let is_key = match l.next().unwrap() {
Value::Bool(b) => b,
@ -395,40 +274,38 @@ impl<'a> TryFrom<Value<'a>> for Expr<'a> {
col_idx: cid as usize,
}))
}
"Apply" => {
EXPR_TAG_APPLY => {
let mut ll = extract_list_from_value(v, 2)?.into_iter();
let name = match ll.next().unwrap() {
Value::Text(t) => t,
v => return Err(ExprError::ConversionFailure(v.into_static()).into()),
};
let op = Arc::new(UnresolvedOp(name.to_string()));
let l = extract_list_from_value(ll.next().unwrap(), 0)?;
let args = l
let _args = l
.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?;
Ok(Expr::Apply(op, args))
todo!()
}
"ApplyAgg" => {
EXPR_TAG_APPLY_AGG => {
let mut ll = extract_list_from_value(v, 3)?.into_iter();
let name = match ll.next().unwrap() {
Value::Text(t) => t,
v => return Err(ExprError::ConversionFailure(v.into_static()).into()),
};
let op = Arc::new(UnresolvedOp(name.to_string()));
let l = extract_list_from_value(ll.next().unwrap(), 0)?;
let a_args = l
.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?;
let l = extract_list_from_value(ll.next().unwrap(), 0)?;
let args = l
let _args = l
.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?;
Ok(Expr::ApplyAgg(op, a_args, args))
todo!()
}
"FieldAcc" => {
EXPR_TAG_FIELD_ACC => {
let mut ll = extract_list_from_value(v, 2)?.into_iter();
let field = match ll.next().unwrap() {
Value::Text(t) => t,
@ -437,7 +314,7 @@ impl<'a> TryFrom<Value<'a>> for Expr<'a> {
let arg = Expr::try_from(ll.next().unwrap())?;
Ok(Expr::FieldAcc(field.to_string(), arg.into()))
}
"IdxAcc" => {
EXPR_TAG_IDX_ACC => {
let mut ll = extract_list_from_value(v, 2)?.into_iter();
let idx = match ll.next().unwrap() {
Value::Int(i) => i as usize,
@ -454,9 +331,9 @@ impl<'a> TryFrom<Value<'a>> for Expr<'a> {
}
}
fn build_value_from_binop<'a>(name: &str, (left, right): (Expr<'a>, Expr<'a>)) -> Value<'a> {
fn build_value_from_binop<'a>(name: &str, (left, right): (Expr, Expr)) -> Value<'a> {
build_tagged_value(
"Apply",
EXPR_TAG_APPLY,
vec![
Value::from(name.to_string()),
Value::from(vec![Value::from(left), Value::from(right)]),
@ -465,9 +342,9 @@ fn build_value_from_binop<'a>(name: &str, (left, right): (Expr<'a>, Expr<'a>)) -
)
}
fn build_value_from_uop<'a>(name: &str, arg: Expr<'a>) -> Value<'a> {
fn build_value_from_uop<'a>(name: &str, arg: Expr) -> Value<'a> {
build_tagged_value(
"Apply",
EXPR_TAG_APPLY,
vec![
Value::from(name.to_string()),
Value::from(vec![Value::from(arg)]),
@ -476,24 +353,34 @@ fn build_value_from_uop<'a>(name: &str, arg: Expr<'a>) -> Value<'a> {
)
}
impl<'a> From<Expr<'a>> for Value<'a> {
fn from(expr: Expr<'a>) -> Self {
pub(crate) const EXPR_TAG_CONST: &str = "Const";
pub(crate) const EXPR_TAG_LIST: &str = "List";
pub(crate) const EXPR_TAG_DICT: &str = "Dict";
pub(crate) const EXPR_TAG_VARIABLE: &str = "Variable";
pub(crate) const EXPR_TAG_TUPLE_SET_IDX: &str = "TupleSetIdx";
pub(crate) const EXPR_TAG_APPLY: &str = "Apply";
pub(crate) const EXPR_TAG_APPLY_AGG: &str = "ApplyAgg";
pub(crate) const EXPR_TAG_FIELD_ACC: &str = "FieldAcc";
pub(crate) const EXPR_TAG_IDX_ACC: &str = "IndexAcc";
impl<'a> From<Expr> for Value<'a> {
fn from(expr: Expr) -> Self {
match expr {
Expr::Const(c) => build_tagged_value("Const", c),
Expr::Const(c) => build_tagged_value(EXPR_TAG_CONST, c),
Expr::List(l) => build_tagged_value(
"List",
EXPR_TAG_LIST,
l.into_iter().map(Value::from).collect::<Vec<_>>().into(),
),
Expr::Dict(d) => build_tagged_value(
"Dict",
EXPR_TAG_DICT,
d.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect::<BTreeMap<_, _>>()
.into(),
),
Expr::Variable(v) => build_tagged_value("Variable", v.into()),
Expr::Variable(v) => build_tagged_value(EXPR_TAG_VARIABLE, v.into()),
Expr::TupleSetIdx(sid) => build_tagged_value(
"TupleSetIdx",
EXPR_TAG_TUPLE_SET_IDX,
vec![
sid.is_key.into(),
Value::from(sid.t_set as i64),
@ -501,30 +388,50 @@ impl<'a> From<Expr<'a>> for Value<'a> {
]
.into(),
),
Expr::Add(arg) => build_value_from_binop(OpAdd.name(), *arg),
Expr::Sub(arg) => build_value_from_binop(OpSub.name(), *arg),
Expr::Mul(arg) => build_value_from_binop(OpMul.name(), *arg),
Expr::Div(arg) => build_value_from_binop(OpDiv.name(), *arg),
Expr::Pow(arg) => build_value_from_binop(OpPow.name(), *arg),
Expr::Mod(arg) => build_value_from_binop(OpMod.name(), *arg),
Expr::StrCat(arg) => build_value_from_binop(OpStrCat.name(), *arg),
Expr::Eq(arg) => build_value_from_binop(OpEq.name(), *arg),
Expr::Ne(arg) => build_value_from_binop(OpNe.name(), *arg),
Expr::Gt(arg) => build_value_from_binop(OpGt.name(), *arg),
Expr::Ge(arg) => build_value_from_binop(OpGe.name(), *arg),
Expr::Lt(arg) => build_value_from_binop(OpLt.name(), *arg),
Expr::Le(arg) => build_value_from_binop(OpLe.name(), *arg),
Expr::Not(arg) => build_value_from_uop(OpNot.name(), *arg),
Expr::Minus(arg) => build_value_from_uop(OpMinus.name(), *arg),
Expr::IsNull(arg) => build_value_from_uop(OpIsNull.name(), *arg),
Expr::NotNull(arg) => build_value_from_uop(OpNotNull.name(), *arg),
Expr::Coalesce(arg) => build_value_from_binop(OpCoalesce.name(), *arg),
Expr::Or(arg) => build_value_from_binop(OpOr.name(), *arg),
Expr::And(arg) => build_value_from_binop(OpAnd.name(), *arg),
Expr::Apply(op, args) => build_tagged_value(
"Apply",
Expr::BuiltinFn(op, args) => build_tagged_value(
EXPR_TAG_APPLY,
vec![
Value::from(op.name.to_string()),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
),
Expr::OpAnd(args) => build_tagged_value(
EXPR_TAG_APPLY,
vec![
Value::from(NAME_OP_ADD),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
),
Expr::OpOr(args) => build_tagged_value(
EXPR_TAG_APPLY,
vec![
Value::from(op.name().to_string()),
Value::from(NAME_OP_OR),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
),
Expr::OpCoalesce(args) => build_tagged_value(
EXPR_TAG_APPLY,
vec![
Value::from(NAME_OP_COALESCE),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
),
Expr::OpMerge(args) => build_tagged_value(
EXPR_TAG_APPLY,
vec![
Value::from(NAME_OP_MERGE),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
),
Expr::OpConcat(args) => build_tagged_value(
EXPR_TAG_APPLY,
vec![
Value::from(NAME_OP_CONCAT),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
@ -536,9 +443,9 @@ impl<'a> From<Expr<'a>> for Value<'a> {
todo!()
}
Expr::ApplyAgg(op, a_args, args) => build_tagged_value(
"ApplyAgg",
EXPR_TAG_APPLY_AGG,
vec![
Value::from(op.name().to_string()),
Value::from(todo!()),
a_args
.into_iter()
.map(Value::from)
@ -549,11 +456,12 @@ impl<'a> From<Expr<'a>> for Value<'a> {
.into(),
),
Expr::FieldAcc(f, v) => {
build_tagged_value("FieldAcc", vec![f.into(), Value::from(*v)].into())
}
Expr::IdxAcc(idx, v) => {
build_tagged_value("IdxAcc", vec![(idx as i64).into(), Value::from(*v)].into())
build_tagged_value(EXPR_TAG_FIELD_ACC, vec![f.into(), Value::from(*v)].into())
}
Expr::IdxAcc(idx, v) => build_tagged_value(
EXPR_TAG_IDX_ACC,
vec![(idx as i64).into(), Value::from(*v)].into(),
),
}
}
}
@ -562,7 +470,7 @@ fn build_tagged_value<'a>(tag: &'static str, val: Value<'a>) -> Value<'a> {
Value::Dict(BTreeMap::from([(tag.into(), val)]))
}
impl<'a> TryFrom<&'a str> for Expr<'a> {
impl<'a> TryFrom<&'a str> for Expr {
type Error = anyhow::Error;
fn try_from(value: &'a str) -> result::Result<Self, Self::Error> {

@ -3,80 +3,11 @@ mod boolean;
mod combine;
mod comparison;
mod control;
mod sequence;
mod text;
mod uuid;
use crate::data::value::Value;
use anyhow::Result;
use crate::data::expr::Expr;
pub(crate) use arithmetic::*;
pub(crate) use boolean::*;
pub(crate) use combine::*;
pub(crate) use comparison::*;
pub(crate) use control::*;
pub(crate) use text::*;
pub trait Op: Send + Sync {
fn arity(&self) -> Option<usize>;
fn has_side_effect(&self) -> bool;
fn name(&self) -> &str;
fn non_null_args(&self) -> bool;
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>>;
}
pub trait AggOp: Send + Sync {
fn arity(&self) -> Option<usize>;
fn has_side_effect(&self) -> bool;
fn name(&self) -> &str;
fn prep(&self, args: &[Expr]) -> Result<()>;
fn get(&self, args: &[Expr]) -> Result<Value>;
}
pub(crate) struct UnresolvedOp(pub String);
impl Op for UnresolvedOp {
fn non_null_args(&self) -> bool {
false
}
fn has_side_effect(&self) -> bool {
true
}
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
&self.0
}
fn eval<'a>(&self, _args: Vec<Value<'a>>) -> Result<Value<'a>> {
unimplemented!()
}
}
impl AggOp for UnresolvedOp {
fn arity(&self) -> Option<usize> {
None
}
fn has_side_effect(&self) -> bool {
true
}
fn name(&self) -> &str {
&self.0
}
fn prep(&self, _args: &[Expr]) -> Result<()> {
todo!()
}
fn get(&self, _args: &[Expr]) -> Result<Value> {
todo!()
}
}
pub(crate) fn extract_two_args<'a>(args: Vec<Value<'a>>) -> (Value<'a>, Value<'a>) {
let mut args = args.into_iter();
(args.next().unwrap(), args.next().unwrap())
}

@ -1,332 +1,199 @@
use crate::data::eval::EvalError;
use crate::data::op::{extract_two_args, Op};
use crate::data::value::Value;
use anyhow::Result;
use crate::data::expr::BuiltinFn;
pub(crate) struct OpAdd;
impl OpAdd {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_ADD: BuiltinFn = BuiltinFn {
name: NAME_OP_ADD,
arity: Some(2),
non_null_args: true,
func: op_add
};
pub(crate) const NAME_OP_ADD: &str = "+";
impl Op for OpAdd {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_ADD
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_add<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_ADD.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpSub;
impl OpSub {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_SUB: BuiltinFn = BuiltinFn {
name: NAME_OP_SUB,
arity: Some(2),
non_null_args: true,
func: op_sub
};
pub(crate) const NAME_OP_SUB: &str = "-";
impl Op for OpSub {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_SUB
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_sub<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_SUB.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpMul;
impl OpMul {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_MUL: BuiltinFn = BuiltinFn {
name: NAME_OP_MUL,
arity: Some(2),
non_null_args: true,
func: op_mul
};
pub(crate) const NAME_OP_MUL: &str = "*";
impl Op for OpMul {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_MUL
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_mul<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_MUL.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpDiv;
impl OpDiv {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_DIV: BuiltinFn = BuiltinFn {
name: NAME_OP_DIV,
arity: Some(2),
non_null_args: true,
func: op_div
};
pub(crate) const NAME_OP_DIV: &str = "/";
impl Op for OpDiv {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_DIV
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_div<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_DIV.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpMod;
impl OpMod {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_MOD: BuiltinFn = BuiltinFn {
name: NAME_OP_MOD,
arity: Some(2),
non_null_args: true,
func: op_mod
};
pub(crate) const NAME_OP_MOD: &str = "%";
impl Op for OpMod {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_MOD
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_mod<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
let res: Value = match (left, right) {
(Value::Int(l), Value::Int(r)) => (l % r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
NAME_OP_MOD.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpPow;
impl OpPow {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_POW: BuiltinFn = BuiltinFn {
name: NAME_OP_POW,
arity: Some(2),
non_null_args: true,
func: op_pow
};
pub(crate) const NAME_OP_POW: &str = "**";
impl Op for OpPow {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_POW
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
}
pub(crate) struct OpMinus;
impl OpMinus {
pub(crate) fn eval_one_non_null<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
match arg {
Value::Int(i) => Ok((-i).into()),
Value::Float(i) => Ok((-i).into()),
v => Err(
EvalError::OpTypeMismatch(self.name().to_string(), vec![v.into_static()]).into(),
),
pub(crate) fn op_pow<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_POW.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
}
};
Ok(res)
}
pub(crate) const OP_MINUS: BuiltinFn = BuiltinFn {
name: NAME_OP_MINUS,
arity: Some(1),
non_null_args: true,
func: op_mul
};
pub(crate) const NAME_OP_MINUS: &str = "--";
impl Op for OpMinus {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_MINUS
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
self.eval_one_non_null(args.into_iter().next().unwrap())
pub(crate) fn op_minus<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let arg = args.into_iter().next().unwrap();
match arg {
Value::Int(i) => Ok((-i).into()),
Value::Float(i) => Ok((-i).into()),
v => {
Err(EvalError::OpTypeMismatch(NAME_OP_MINUS.to_string(), vec![v.clone().into_static()]).into())
}
}
}

@ -1,113 +1,42 @@
use crate::data::eval::{EvalError, PartialEvalContext, RowEvalContext};
use crate::data::expr::Expr;
use crate::data::op::Op;
use crate::data::expr::{BuiltinFn, Expr};
use crate::data::value::Value;
use anyhow::Result;
use std::sync::Arc;
pub(crate) struct OpIsNull;
impl OpIsNull {
pub(crate) fn eval_one<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
Ok((arg == Value::Null).into())
}
}
pub(crate) const OP_IS_NULL: BuiltinFn = BuiltinFn {
name: NAME_OP_IS_NULL,
arity: Some(1),
non_null_args: false,
func: op_is_null,
};
pub(crate) const NAME_OP_IS_NULL: &str = "is_null";
impl Op for OpIsNull {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_IS_NULL
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
self.eval_one(args.into_iter().next().unwrap())
}
pub(crate) fn op_is_null<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let arg = args.into_iter().next().unwrap();
Ok((*arg == Value::Null).into())
}
pub(crate) struct OpNotNull;
impl OpNotNull {
pub(crate) fn eval_one<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
Ok((arg != Value::Null).into())
}
}
pub(crate) const OP_NOT_NULL: BuiltinFn = BuiltinFn {
name: NAME_OP_NOT_NULL,
arity: Some(1),
non_null_args: false,
func: op_not_null,
};
pub(crate) const NAME_OP_NOT_NULL: &str = "not_null";
impl Op for OpNotNull {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_NOT_NULL
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
self.eval_one(args.into_iter().next().unwrap())
}
pub(crate) fn op_not_null<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let arg = args.into_iter().next().unwrap();
Ok((*arg != Value::Null).into())
}
pub(crate) struct OpOr;
pub(crate) const NAME_OP_OR: &str = "||";
impl Op for OpOr {
fn arity(&self) -> Option<usize> {
None
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_OR
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let mut has_null = false;
for arg in args {
match arg {
Value::Null => has_null = true,
Value::Bool(true) => return Ok(Value::Bool(true)),
Value::Bool(false) => {}
v => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.into_static()],
)
.into());
}
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(false))
}
}
}
pub(crate) fn partial_eval_or<'a, T: PartialEvalContext>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
args: Vec<Expr>,
) -> Result<Expr> {
let mut collected = vec![];
let mut has_null = false;
for arg in args {
@ -120,12 +49,12 @@ pub(crate) fn partial_eval_or<'a, T: PartialEvalContext>(
}
Expr::Const(v) => {
return Err(EvalError::OpTypeMismatch(
OpOr.name().to_string(),
NAME_OP_OR.to_string(),
vec![v.into_static()],
)
.into());
}
Expr::Apply(op, mut args) if op.name() == OpOr.name() => {
Expr::OpOr(mut args) => {
if args.last() == Some(&Expr::Const(Value::Null)) {
has_null = true;
args.pop();
@ -141,80 +70,43 @@ pub(crate) fn partial_eval_or<'a, T: PartialEvalContext>(
Ok(match collected.len() {
0 => Expr::Const(Value::Bool(false)),
1 => collected.pop().unwrap(),
_ => Expr::Apply(Arc::new(OpOr), collected),
_ => Expr::OpOr(collected),
})
}
pub(crate) fn row_eval_or<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
left: &'a Expr<'a>,
right: &'a Expr<'a>,
args: &[Expr]
) -> Result<Value<'a>> {
let left = left.row_eval(ctx)?;
if left == Value::Bool(true) {
return Ok(Value::Bool(true));
}
let right = right.row_eval(ctx)?;
match (left, right) {
(Value::Null, Value::Bool(true)) => Ok(true.into()),
(Value::Null, Value::Bool(false)) => Ok(Value::Null),
(Value::Bool(false), Value::Null) => Ok(Value::Null),
(Value::Bool(false), Value::Bool(r)) => Ok(r.into()),
(l, r) => Err(EvalError::OpTypeMismatch(
OpOr.name().to_string(),
vec![l.into_static(), r.into_static()],
)
.into()),
}
}
pub(crate) struct OpAnd;
pub(crate) const NAME_OP_AND: &str = "&&";
impl Op for OpAnd {
fn arity(&self) -> Option<usize> {
None
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_AND
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let mut has_null = false;
for arg in args {
match arg {
Value::Null => has_null = true,
Value::Bool(false) => return Ok(Value::Bool(false)),
Value::Bool(true) => {}
v => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.into_static()],
)
let mut has_null = false;
for arg in args {
let arg = arg.row_eval(ctx)?;
match arg {
Value::Null => has_null = true,
Value::Bool(true) => return Ok(Value::Bool(true)),
Value::Bool(false) => {}
v => {
return Err(EvalError::OpTypeMismatch(
NAME_OP_OR.to_string(),
vec![v.clone().into_static()],
)
.into());
}
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(true))
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(false))
}
}
pub(crate) const NAME_OP_AND: &str = "&&";
pub(crate) fn partial_eval_and<'a, T: PartialEvalContext>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
args: Vec<Expr>,
) -> Result<Expr> {
let mut collected = vec![];
let mut has_null = false;
for arg in args {
@ -227,12 +119,12 @@ pub(crate) fn partial_eval_and<'a, T: PartialEvalContext>(
}
Expr::Const(v) => {
return Err(EvalError::OpTypeMismatch(
OpAnd.name().to_string(),
NAME_OP_AND.to_string(),
vec![v.into_static()],
)
.into());
}
Expr::Apply(op, mut args) if op.name() == OpAnd.name() => {
Expr::OpAnd(mut args) => {
if args.last() == Some(&Expr::Const(Value::Null)) {
has_null = true;
args.pop();
@ -248,62 +140,49 @@ pub(crate) fn partial_eval_and<'a, T: PartialEvalContext>(
Ok(match collected.len() {
0 => Expr::Const(Value::Bool(true)),
1 => collected.pop().unwrap(),
_ => Expr::Apply(Arc::new(OpAnd), collected),
_ => Expr::OpAnd(collected),
})
}
pub(crate) fn row_eval_and<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
left: &'a Expr<'a>,
right: &'a Expr<'a>,
args: &[Expr]
) -> Result<Value<'a>> {
let left = left.row_eval(ctx)?;
if left == Value::Bool(false) {
return Ok(Value::Bool(false));
}
let right = right.row_eval(ctx)?;
match (left, right) {
(Value::Null, Value::Bool(false)) => Ok(false.into()),
(Value::Null, Value::Bool(true)) => Ok(Value::Null),
(Value::Bool(true), Value::Null) => Ok(Value::Null),
(Value::Bool(true), Value::Bool(r)) => Ok(r.into()),
(l, r) => Err(EvalError::OpTypeMismatch(
OpAnd.name().to_string(),
vec![l.into_static(), r.into_static()],
)
.into()),
}
}
pub(crate) struct OpNot;
impl OpNot {
pub(crate) fn eval_one_non_null<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
let mut has_null = false;
for arg in args {
let arg = arg.row_eval(ctx)?;
match arg {
Value::Bool(b) => Ok((!b).into()),
v => Err(
EvalError::OpTypeMismatch(self.name().to_string(), vec![v.into_static()]).into(),
),
Value::Null => has_null = true,
Value::Bool(false) => return Ok(Value::Bool(false)),
Value::Bool(true) => {}
v => {
return Err(EvalError::OpTypeMismatch(
NAME_OP_AND.to_string(),
vec![v.clone().into_static()],
)
.into());
}
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(true))
}
}
pub(crate) const OP_NOT: BuiltinFn = BuiltinFn {
name: NAME_OP_NOT,
arity: Some(1),
non_null_args: true,
func: op_not,
};
pub(crate) const NAME_OP_NOT: &str = "!";
impl Op for OpNot {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn has_side_effect(&self) -> bool {
false
}
fn non_null_args(&self) -> bool {
true
}
fn name(&self) -> &str {
NAME_OP_NOT
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
self.eval_one_non_null(args.into_iter().next().unwrap())
pub(crate) fn op_not<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
match args.into_iter().next().unwrap() {
Value::Bool(b) => Ok((!b).into()),
v => Err(EvalError::OpTypeMismatch(NAME_OP_NOT.to_string(), vec![v.clone().into_static()]).into()),
}
}

@ -1,53 +1,39 @@
use crate::data::eval::{EvalError, PartialEvalContext};
use crate::data::eval::{EvalError, PartialEvalContext, RowEvalContext};
use crate::data::expr::Expr;
use crate::data::op::Op;
use crate::data::value::Value;
use anyhow::Result;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::sync::Arc;
pub(crate) struct OpConcat;
pub(crate) const NAME_OP_CONCAT: &str = "concat";
impl Op for OpConcat {
fn arity(&self) -> Option<usize> {
None
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_CONCAT
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
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.into_static()],
)
.into());
}
pub(crate) fn row_eval_concat<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
args: &'a [Expr],
) -> Result<Value<'a>> {
let mut coll: Vec<Value> = vec![];
for v in args.into_iter() {
match v.row_eval(ctx)? {
Value::Null => {}
Value::List(l) => coll.extend(l.clone()),
v => {
return Err(EvalError::OpTypeMismatch(
NAME_OP_CONCAT.to_string(),
vec![v.clone().into_static()],
)
.into());
}
}
Ok(coll.into())
}
Ok(coll.into())
}
pub(crate) fn partial_eval_concat_expr<'a, T: PartialEvalContext>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
args: Vec<Expr>,
) -> Result<Expr> {
let mut can_concat = true;
let mut all_const = true;
let args = args
@ -96,52 +82,37 @@ pub(crate) fn partial_eval_concat_expr<'a, T: PartialEvalContext>(
}
Ok(Expr::List(result))
} else {
Ok(Expr::Apply(Arc::new(OpConcat), args))
Ok(Expr::OpConcat(args))
}
}
pub(crate) struct OpMerge;
pub(crate) const NAME_OP_MERGE: &str = "merge";
impl Op for OpMerge {
fn arity(&self) -> Option<usize> {
None
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_MERGE
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
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.into_static()],
)
.into());
}
pub(crate) fn row_eval_merge<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
args: &'a [Expr],
) -> Result<Value<'a>> {
let mut coll: BTreeMap<Cow<str>, Value> = BTreeMap::new();
for v in args.into_iter() {
match v.row_eval(ctx)? {
Value::Null => {}
Value::Dict(d) => coll.extend(d.clone()),
v => {
return Err(EvalError::OpTypeMismatch(
NAME_OP_MERGE.to_string(),
vec![v.clone().into_static()],
)
.into());
}
}
Ok(coll.into())
}
Ok(coll.into())
}
pub(crate) fn partial_eval_merge_expr<'a, T: PartialEvalContext>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
args: Vec<Expr>,
) -> Result<Expr> {
let mut can_merge = true;
let mut all_const = true;
let args = args
@ -191,6 +162,6 @@ pub(crate) fn partial_eval_merge_expr<'a, T: PartialEvalContext>(
}
Ok(Expr::Dict(result))
} else {
Ok(Expr::Apply(Arc::new(OpMerge), args))
Ok(Expr::OpMerge(args))
}
}

@ -1,278 +1,162 @@
use crate::data::eval::EvalError;
use crate::data::op::{extract_two_args, Op};
use crate::data::expr::BuiltinFn;
use crate::data::value::Value;
use anyhow::Result;
pub(crate) struct OpEq;
impl OpEq {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
Ok((left == right).into())
}
}
pub(crate) const OP_EQ: BuiltinFn = BuiltinFn {
name: NAME_OP_EQ,
arity: Some(2),
non_null_args: true,
func: op_eq,
};
pub(crate) const NAME_OP_EQ: &str = "==";
impl Op for OpEq {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_EQ
}
pub(crate) fn op_eq<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
Ok((left == right).into())
}
pub(crate) struct OpNe;
impl OpNe {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
Ok((left != right).into())
}
}
pub(crate) const OP_NE: BuiltinFn = BuiltinFn {
name: NAME_OP_NE,
arity: Some(2),
non_null_args: true,
func: op_ne,
};
pub(crate) const NAME_OP_NE: &str = "!=";
impl Op for OpNe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
pub(crate) fn op_ne<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
fn name(&self) -> &str {
NAME_OP_NE
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
Ok((left != right).into())
}
pub(crate) struct OpGt;
impl OpGt {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_GT: BuiltinFn = BuiltinFn {
name: NAME_OP_GT,
arity: Some(2),
non_null_args: true,
func: op_gt,
};
pub(crate) const NAME_OP_GT: &str = ">";
impl Op for OpGt {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_GT
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_gt<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_GT.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpGe;
impl OpGe {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_GE: BuiltinFn = BuiltinFn {
name: NAME_OP_GE,
arity: Some(2),
non_null_args: true,
func: op_ge,
};
pub(crate) const NAME_OP_GE: &str = ">=";
impl Op for OpGe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_GE
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_ge<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_GE.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpLt;
impl OpLt {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_LT: BuiltinFn = BuiltinFn {
name: NAME_OP_LT,
arity: Some(2),
non_null_args: true,
func: op_lt,
};
pub(crate) const NAME_OP_LT: &str = "<";
impl Op for OpLt {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_LT
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_lt<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_LT.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}
pub(crate) struct OpLe;
impl OpLe {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
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.into_static(), r.into_static()],
)
.into());
}
};
Ok(res)
}
}
pub(crate) const OP_LE: BuiltinFn = BuiltinFn {
name: NAME_OP_LE,
arity: Some(2),
non_null_args: true,
func: op_le,
};
pub(crate) const NAME_OP_LE: &str = "<=";
impl Op for OpLe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_LE
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
pub(crate) fn op_le<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
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(
NAME_OP_LE.to_string(),
vec![l.clone().into_static(), r.clone().into_static()],
)
.into());
}
};
Ok(res)
}

@ -1,62 +1,34 @@
use crate::data::eval::{EvalError, PartialEvalContext, RowEvalContext};
use crate::data::expr::Expr;
use crate::data::op::Op;
use crate::data::value::Value;
use anyhow::Result;
use std::sync::Arc;
pub(crate) struct OpCoalesce;
pub(crate) const NAME_OP_COALESCE: &str = "~~";
impl Op for OpCoalesce {
fn arity(&self) -> Option<usize> {
None
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_COALESCE
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
if arg != Value::Null {
return Ok(arg);
}
}
Ok(Value::Null)
}
}
pub(crate) fn row_eval_coalesce<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
left: &'a Expr<'a>,
right: &'a Expr<'a>,
args: &'a [Expr],
) -> Result<Value<'a>> {
let left = left.row_eval(ctx)?;
if left != Value::Null {
return Ok(left);
for arg in args {
let arg = arg.row_eval(ctx)?;
if arg != Value::Null {
return Ok(arg.clone());
}
}
right.row_eval(ctx)
Ok(Value::Null)
}
pub(crate) const IF_NAME: &str = "if";
pub(crate) fn partial_eval_coalesce<'a, T: PartialEvalContext>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
args: Vec<Expr>,
) -> Result<Expr> {
let mut collected = vec![];
for arg in args {
match arg.partial_eval(ctx)? {
Expr::Const(Value::Null) => {}
Expr::Apply(op, args) if op.name() == OpCoalesce.name() => {
Expr::OpCoalesce(args) => {
collected.extend(args);
}
expr => collected.push(expr),
@ -65,15 +37,15 @@ pub(crate) fn partial_eval_coalesce<'a, T: PartialEvalContext>(
Ok(match collected.len() {
0 => Expr::Const(Value::Null),
1 => collected.pop().unwrap(),
_ => Expr::Apply(Arc::new(OpCoalesce), collected),
_ => Expr::OpCoalesce(collected),
})
}
pub(crate) fn row_eval_if_expr<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
cond: &'a Expr<'a>,
if_part: &'a Expr<'a>,
else_part: &'a Expr<'a>,
cond: &'a Expr,
if_part: &'a Expr,
else_part: &'a Expr,
) -> Result<Value<'a>> {
let cond = cond.row_eval(ctx)?;
match cond {
@ -89,10 +61,10 @@ pub(crate) fn row_eval_if_expr<'a, T: RowEvalContext + 'a>(
pub(crate) fn partial_eval_if_expr<'a, T: PartialEvalContext>(
ctx: &'a T,
cond: Expr<'a>,
if_part: Expr<'a>,
else_part: Expr<'a>,
) -> Result<Expr<'a>> {
cond: Expr,
if_part: Expr,
else_part: Expr,
) -> Result<Expr> {
let cond = cond.partial_eval(ctx)?;
match cond {
Expr::Const(Value::Null) => Ok(Expr::Const(Value::Null)),
@ -114,7 +86,7 @@ pub(crate) fn partial_eval_if_expr<'a, T: PartialEvalContext>(
pub(crate) fn row_eval_switch_expr<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
args: &'a [(Expr<'a>, Expr<'a>)],
args: &'a [(Expr, Expr)],
) -> Result<Value<'a>> {
let mut args = args.iter();
let (expr, default) = args.next().unwrap();
@ -130,8 +102,8 @@ pub(crate) fn row_eval_switch_expr<'a, T: RowEvalContext + 'a>(
pub(crate) fn partial_eval_switch_expr<'a, T: PartialEvalContext>(
ctx: &'a T,
args: Vec<(Expr<'a>, Expr<'a>)>,
) -> Result<Expr<'a>> {
args: Vec<(Expr, Expr)>,
) -> Result<Expr> {
let mut args = args.into_iter();
let (expr, mut default) = args.next().unwrap();
let expr = expr.partial_eval(ctx)?;

@ -1,28 +0,0 @@
use crate::data::op::Op;
use crate::data::value::Value;
pub(crate) struct SeqNext;
const NAME_OP_SEQ_NEXT: &str = "seq_next";
impl Op for SeqNext {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn has_side_effect(&self) -> bool {
true
}
fn name(&self) -> &str {
NAME_OP_SEQ_NEXT
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, _args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
todo!()
}
}

@ -1,52 +1,31 @@
use crate::data::eval::EvalError;
use crate::data::op::{extract_two_args, Op};
use crate::data::value::Value;
use anyhow::Result;
use crate::data::expr::BuiltinFn;
pub(crate) struct OpStrCat;
pub(crate) const OP_STR_CAT: BuiltinFn = BuiltinFn {
name: NAME_OP_STR_CAT,
arity: None,
non_null_args: true,
func: op_str_cat
};
impl OpStrCat {
pub(crate) fn eval_two_non_null<'a>(
&self,
left: Value<'a>,
right: Value<'a>,
) -> Result<Value<'a>> {
match (left, right) {
(Value::Text(l), Value::Text(r)) => {
let mut l = l.into_owned();
l += r.as_ref();
Ok(l.into())
pub(crate) const NAME_OP_STR_CAT: &str = "++";
pub(crate) fn op_str_cat<'a>(args: &[Value<'a>]) -> Result<Value<'a>> {
let mut ret = String::new();
for arg in args {
match arg {
Value::Text(t) => {
ret += t.as_ref();
}
_ => {
return Err(EvalError::OpTypeMismatch(
NAME_OP_STR_CAT.to_string(),
args.iter().cloned().map(|v| v.into_static()).collect(),
)
.into());
}
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.into_static(), r.into_static()],
)
.into()),
}
}
}
pub(crate) const NAME_OP_STR_CAT: &str = "++";
impl Op for OpStrCat {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str {
NAME_OP_STR_CAT
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
let (left, right) = extract_two_args(args);
self.eval_two_non_null(left, right)
}
Ok(ret.into())
}

@ -1,28 +0,0 @@
use crate::data::op::Op;
use crate::data::value::Value;
pub(crate) struct OpGenUuidV1;
const NAME_OP_GEN_UUID_V1: &str = "gen_uuid_v1";
impl Op for OpGenUuidV1 {
fn arity(&self) -> Option<usize> {
Some(0)
}
fn has_side_effect(&self) -> bool {
true
}
fn name(&self) -> &str {
NAME_OP_GEN_UUID_V1
}
fn non_null_args(&self) -> bool {
true
}
fn eval<'a>(&self, _args: Vec<Value<'a>>) -> crate::data::op::Result<Value<'a>> {
todo!()
}
}

@ -9,7 +9,6 @@ use lazy_static::lazy_static;
use pest::prec_climber::{Assoc, Operator, PrecClimber};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::sync::Arc;
#[derive(thiserror::Error, Debug)]
pub enum ExprParseError {
@ -17,7 +16,7 @@ pub enum ExprParseError {
SpreadingError(String),
}
impl<'a> TryFrom<Pair<'a>> for Expr<'a> {
impl<'a> TryFrom<Pair<'a>> for Expr {
type Error = anyhow::Error;
fn try_from(pair: Pair<'a>) -> Result<Self> {
@ -77,9 +76,9 @@ fn build_cond_expr(pair: Pair) -> Result<Expr> {
fn build_call_expr(pair: Pair) -> Result<Expr> {
let mut pairs = pair.into_inner();
let method = get_method(pairs.next().unwrap().as_str());
let op_name = pairs.next().unwrap().as_str();
let args = pairs.map(Expr::try_from).collect::<Result<Vec<_>>>()?;
Ok(Expr::Apply(method, args))
build_method_call(op_name, args)
}
fn build_switch_expr(pair: Pair) -> Result<Expr> {
@ -138,11 +137,10 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
}
Rule::call => {
let mut pairs = p.into_inner();
let op: Arc<dyn Op + Send + Sync> =
get_method(pairs.next().unwrap().as_str());
let op_name = pairs.next().unwrap().as_str();
let mut args = vec![head];
args.extend(pairs.map(Expr::try_from).collect::<Result<Vec<_>>>()?);
head = Expr::Apply(op, args);
head = build_method_call(op_name, args)?;
}
_ => todo!(),
}
@ -155,17 +153,19 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
let mut inner = pair.into_inner();
let p = inner.next().unwrap();
let op = p.as_rule();
let op: Arc<dyn Op + Send + Sync> = match op {
Ok(match op {
Rule::term => return build_expr_primary(p),
Rule::negate => Arc::new(OpNot),
Rule::minus => Arc::new(OpMinus),
Rule::minus => {
Expr::BuiltinFn(OP_MINUS, vec![build_expr_primary(inner.next().unwrap())?])
}
Rule::negate => {
Expr::BuiltinFn(OP_NOT, vec![build_expr_primary(inner.next().unwrap())?])
}
Rule::if_expr => return build_if_expr(p),
Rule::cond_expr => return build_cond_expr(p),
Rule::switch_expr => return build_switch_expr(p),
r => unreachable!("Encountered unknown op {:?}", r),
};
let term = build_expr_primary(inner.next().unwrap())?;
Ok(Expr::Apply(op, vec![term]))
})
}
Rule::pos_int => Ok(Expr::Const(Value::Int(
@ -197,7 +197,10 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
| Expr::Variable(_)
| Expr::IdxAcc(_, _)
| Expr::FieldAcc(_, _)
| Expr::Apply(_, _)
| Expr::BuiltinFn(_, _)
| Expr::OpConcat(_)
| Expr::OpMerge(_)
| Expr::OpCoalesce(_)
) {
return Err(
ExprParseError::SpreadingError(format!("{:?}", to_concat)).into()
@ -218,7 +221,7 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
if !collected.is_empty() {
spread_collected.push(Expr::List(collected));
}
Ok(Expr::Apply(Arc::new(OpConcat), spread_collected))
Ok(Expr::OpConcat(spread_collected))
}
Rule::dict => {
let mut spread_collected = vec![];
@ -245,7 +248,10 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
| Expr::Variable(_)
| Expr::IdxAcc(_, _)
| Expr::FieldAcc(_, _)
| Expr::Apply(_, _)
| Expr::BuiltinFn(_, _)
| Expr::OpConcat(_)
| Expr::OpMerge(_)
| Expr::OpCoalesce(_)
) {
return Err(
ExprParseError::SpreadingError(format!("{:?}", to_concat)).into()
@ -268,7 +274,7 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
if !collected.is_empty() {
spread_collected.push(Expr::Dict(collected));
}
Ok(Expr::Apply(Arc::new(OpMerge), spread_collected))
Ok(Expr::OpMerge(spread_collected))
}
Rule::param => Ok(Expr::Variable(pair.as_str().into())),
Rule::ident => Ok(Expr::Variable(pair.as_str().into())),
@ -280,43 +286,37 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
}
}
fn get_method(name: &str) -> Arc<dyn Op + Send + Sync> {
match name {
NAME_OP_IS_NULL => Arc::new(OpIsNull),
NAME_OP_NOT_NULL => Arc::new(OpNotNull),
NAME_OP_CONCAT => Arc::new(OpConcat),
NAME_OP_MERGE => Arc::new(OpMerge),
method_name => Arc::new(UnresolvedOp(method_name.to_string())),
}
fn build_method_call(name: &str, args: Vec<Expr>) -> Result<Expr> {
Ok(match name {
NAME_OP_IS_NULL => Expr::BuiltinFn(OP_IS_NULL, args),
NAME_OP_NOT_NULL => Expr::BuiltinFn(OP_NOT_NULL, args),
NAME_OP_CONCAT => Expr::OpConcat(args),
NAME_OP_MERGE => Expr::OpMerge(args),
_method_name => unimplemented!(),
})
}
fn build_expr_infix<'a>(
lhs: Result<Expr<'a>>,
op: Pair,
rhs: Result<Expr<'a>>,
) -> Result<Expr<'a>> {
let lhs = lhs?;
let rhs = rhs?;
let op: Arc<dyn Op + Send + Sync> = match op.as_rule() {
Rule::op_add => Arc::new(OpAdd),
Rule::op_str_cat => Arc::new(OpStrCat),
Rule::op_sub => Arc::new(OpSub),
Rule::op_mul => Arc::new(OpMul),
Rule::op_div => Arc::new(OpDiv),
Rule::op_eq => Arc::new(OpEq),
Rule::op_ne => Arc::new(OpNe),
Rule::op_or => Arc::new(OpOr),
Rule::op_and => Arc::new(OpAnd),
Rule::op_mod => Arc::new(OpMod),
Rule::op_gt => Arc::new(OpGt),
Rule::op_ge => Arc::new(OpGe),
Rule::op_lt => Arc::new(OpLt),
Rule::op_le => Arc::new(OpLe),
Rule::op_pow => Arc::new(OpPow),
Rule::op_coalesce => Arc::new(OpCoalesce),
fn build_expr_infix<'a>(lhs: Result<Expr>, op: Pair, rhs: Result<Expr>) -> Result<Expr> {
let args = vec![lhs?, rhs?];
Ok(match op.as_rule() {
Rule::op_add => Expr::BuiltinFn(OP_ADD, args),
Rule::op_sub => Expr::BuiltinFn(OP_SUB, args),
Rule::op_mul => Expr::BuiltinFn(OP_MUL, args),
Rule::op_div => Expr::BuiltinFn(OP_DIV, args),
Rule::op_mod => Expr::BuiltinFn(OP_MOD, args),
Rule::op_pow => Expr::BuiltinFn(OP_POW, args),
Rule::op_eq => Expr::BuiltinFn(OP_EQ, args),
Rule::op_ne => Expr::BuiltinFn(OP_NE, args),
Rule::op_gt => Expr::BuiltinFn(OP_GT, args),
Rule::op_ge => Expr::BuiltinFn(OP_GE, args),
Rule::op_lt => Expr::BuiltinFn(OP_LT, args),
Rule::op_le => Expr::BuiltinFn(OP_LE, args),
Rule::op_str_cat => Expr::BuiltinFn(OP_STR_CAT, args),
Rule::op_or => Expr::OpOr(args),
Rule::op_and => Expr::OpAnd(args),
Rule::op_coalesce => Expr::OpCoalesce(args),
_ => unreachable!(),
};
Ok(Expr::Apply(op, vec![lhs, rhs]))
})
}
pub(crate) fn parse_scoped_dict(pair: Pair) -> Result<(String, BTreeMap<String, Expr>, Expr)> {
@ -359,7 +359,10 @@ pub(crate) fn parse_keyed_dict(keyed_dict: Pair) -> Result<(BTreeMap<String, Exp
| Expr::Variable(_)
| Expr::IdxAcc(_, _)
| Expr::FieldAcc(_, _)
| Expr::Apply(_, _)
| Expr::BuiltinFn(_, _)
| Expr::OpConcat(_)
| Expr::OpMerge(_)
| Expr::OpCoalesce(_)
) {
return Err(ExprParseError::SpreadingError(format!("{:?}", to_concat)).into());
}
@ -379,7 +382,7 @@ pub(crate) fn parse_keyed_dict(keyed_dict: Pair) -> Result<(BTreeMap<String, Exp
if !collected.is_empty() {
spread_collected.push(Expr::Dict(collected));
}
Expr::Apply(Arc::new(OpMerge), spread_collected)
Expr::OpMerge(spread_collected)
};
Ok((keys, vals))
}

@ -312,7 +312,7 @@ impl RowEvalContext for TupleSet {
}
}
pub(crate) type TupleBuilder<'a> = Vec<(Expr<'a>, Typing)>;
pub(crate) type TupleBuilder<'a> = Vec<(Expr, Typing)>;
impl<'a> TupleSetEvalContext<'a> {
pub(crate) fn eval_to_tuple(&self, prefix: u32, builder: &TupleBuilder) -> Result<OwnTuple> {

@ -1,4 +1,4 @@
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::{Expr};
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use crate::parser::text_identifier::build_name_in_def;
@ -20,18 +20,17 @@ pub enum DdlParseError {
pub(crate) struct ColSchema {
pub(crate) name: String,
pub(crate) typing: Typing,
pub(crate) default: StaticExpr,
pub(crate) default: Expr,
}
pub(crate) type ColExtractor = (StaticExpr, Typing);
pub(crate) type ColExtractor = (Expr, Typing);
impl ColSchema {
pub(crate) fn make_extractor(&self, extractor_map: &BTreeMap<String, Expr>) -> ColExtractor {
let extractor = extractor_map
.get(&self.name)
.cloned()
.unwrap_or(Expr::Const(Value::Null))
.into_static();
.unwrap_or(Expr::Const(Value::Null));
let typing = self.typing.clone();
(extractor, typing)
}
@ -103,7 +102,7 @@ pub(crate) struct IndexSchema {
pub(crate) name: String,
pub(crate) src_name: String,
pub(crate) assoc_names: Vec<String>,
pub(crate) index: Vec<StaticExpr>,
pub(crate) index: Vec<Expr>,
}
#[derive(Debug, Clone)]
@ -201,7 +200,7 @@ impl<'a> TryFrom<Pair<'a>> for IndexSchema {
for pair in pairs {
match pair.as_rule() {
Rule::name_in_def => associate_names.push(build_name_in_def(pair, false)?),
_ => indices.push(Expr::try_from(pair)?.into_static()),
_ => indices.push(Expr::try_from(pair)?),
}
}
if indices.is_empty() {
@ -242,7 +241,7 @@ fn parse_col_entry(pair: Pair) -> Result<(bool, ColSchema)> {
let typing = Typing::try_from(pairs.next().unwrap())?;
let default = match pairs.next() {
None => Expr::Const(Value::Null),
Some(pair) => Expr::try_from(pair)?.into_static(),
Some(pair) => Expr::try_from(pair)?,
};
Ok((
is_key,

@ -1,6 +1,6 @@
use crate::context::{MainDbContext, TempDbContext};
use crate::data::eval::PartialEvalContext;
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr::Expr;
use crate::data::tuple::{
DataKind, OwnTuple, Tuple, DATAKIND_ASSOC, DATAKIND_EDGE, DATAKIND_INDEX, DATAKIND_NODE,
DATAKIND_SEQUENCE,
@ -220,7 +220,7 @@ impl<T: AsRef<[u8]>> TryFrom<Tuple<T>> for TableInfo {
}))
}
DATAKIND_INDEX => {
let mut it = tuple.iter();
let mut it = tuple.iter().map(|v| v.map(|v| v.into_static()));
let name = it
.next()
.ok_or_else(gen_err)??
@ -401,7 +401,7 @@ pub(crate) struct AssocInfo {
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum IndexCol {
Col(TupleSetIdx),
Expr(StaticExpr),
Expr(Expr),
}
impl From<IndexCol> for StaticValue {
@ -413,13 +413,13 @@ impl From<IndexCol> for StaticValue {
}
}
impl<'a> TryFrom<Value<'a>> for IndexCol {
impl TryFrom<StaticValue> for IndexCol {
type Error = anyhow::Error;
fn try_from(value: Value<'a>) -> Result<Self> {
fn try_from(value: StaticValue) -> Result<Self> {
Ok(match Expr::try_from(value)? {
Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx),
expr => IndexCol::Expr(expr.into_static()),
expr => IndexCol::Expr(expr),
})
}
}
@ -573,7 +573,7 @@ pub(crate) trait DdlContext {
.map(|ex| {
ex.partial_eval(&ctx).map(|ex| match ex {
Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx),
ex => IndexCol::Expr(ex.into_static()),
ex => IndexCol::Expr(ex),
})
})
.collect::<result::Result<Vec<_>, _>>()?
@ -602,7 +602,7 @@ pub(crate) trait DdlContext {
.map(|ex| {
ex.partial_eval(&ctx).map(|ex| match ex {
Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx),
ex => IndexCol::Expr(ex.into_static()),
ex => IndexCol::Expr(ex),
})
})
.collect::<result::Result<Vec<_>, _>>()?

@ -1,4 +1,3 @@
use crate::data::expr::StaticExpr;
use crate::data::tuple::{DataKind, OwnTuple, Tuple};
use crate::data::tuple_set::{TableId, MIN_TABLE_ID_BOUND};
use crate::data::value::{StaticValue, Value};
@ -15,10 +14,11 @@ use pest::Parser;
use std::collections::{BTreeMap, BTreeSet};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Mutex};
use crate::data::expr::Expr;
pub(crate) enum Definable {
Value(StaticValue),
Expr(StaticExpr),
Expr(Expr),
Table(u32), // TODO
}

Loading…
Cancel
Save