switch expr

main
Ziyang Hu 2 years ago
parent 8484ae33a4
commit 274d6477f1

@ -24,7 +24,7 @@ impl<'s> Session<'s> {
tuple.push_int(depth_code);
tuple
}
fn parse_cols(&self, pair: Pair<Rule>) -> Result<(Typing, Typing)> {
fn parse_cols(&self, pair: Pair) -> Result<(Typing, Typing)> {
let col_res = pair
.into_inner()
.map(|p| {
@ -69,7 +69,7 @@ impl<'s> Session<'s> {
#[allow(clippy::type_complexity)]
fn parse_definition(
&self,
pair: Pair<Rule>,
pair: Pair,
in_root: bool,
) -> Result<(bool, (String, OwnTuple, Vec<OwnTuple>))> {
Ok(match pair.as_rule() {
@ -83,7 +83,7 @@ impl<'s> Session<'s> {
}
fn parse_assoc_def(
&self,
mut pairs: Pairs<Rule>,
mut pairs: Pairs,
in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let name = build_name_in_def(pairs.next().unwrap(), true)?;
@ -137,7 +137,7 @@ impl<'s> Session<'s> {
}
fn parse_type_def(
&self,
mut pairs: Pairs<Rule>,
mut pairs: Pairs,
_in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let name = build_name_in_def(pairs.next().unwrap(), true)?;
@ -149,7 +149,7 @@ impl<'s> Session<'s> {
fn parse_edge_def(
&self,
mut pairs: Pairs<Rule>,
mut pairs: Pairs,
in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let src_name = build_name_in_def(pairs.next().unwrap(), true)?;
@ -269,7 +269,7 @@ impl<'s> Session<'s> {
}
fn parse_node_def(
&self,
mut pairs: Pairs<Rule>,
mut pairs: Pairs,
_in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let name = build_name_in_def(pairs.next().unwrap(), true)?;
@ -282,7 +282,7 @@ impl<'s> Session<'s> {
tuple.push_null(); // TODO default values for cols
Ok((name, tuple, vec![]))
}
pub fn run_definition(&mut self, pair: Pair<Rule>) -> Result<()> {
pub fn run_definition(&mut self, pair: Pair) -> Result<()> {
let in_root = match pair.as_rule() {
Rule::global_def => true,
Rule::local_def => false,

@ -38,7 +38,7 @@ enum MutationKind {
impl<'a> Session<'a> {
pub fn run_mutation(
&mut self,
pair: Pair<Rule>,
pair: Pair,
params: &BTreeMap<String, Value>,
) -> Result<()> {
let mut pairs = pair.into_inner();

@ -844,7 +844,7 @@ impl<'a> Session<'a> {
};
Ok(plan)
}
pub fn query_to_plan(&self, pair: Pair<Rule>) -> Result<ExecPlan> {
pub fn query_to_plan(&self, pair: Pair) -> Result<ExecPlan> {
let mut pairs = pair.into_inner();
let from_data = self.parse_from_pattern(pairs.next().unwrap())?;
let mut nxt = pairs.next().unwrap();

@ -43,7 +43,7 @@ pub struct EdgeOrNodeEl {
}
impl<'a> Session<'a> {
pub fn parse_from_pattern(&self, pair: Pair<Rule>) -> Result<Vec<FromEl>> {
pub fn parse_from_pattern(&self, pair: Pair) -> Result<Vec<FromEl>> {
let res: Result<Vec<_>> = pair
.into_inner()
.map(|p| match p.as_rule() {
@ -55,7 +55,7 @@ impl<'a> Session<'a> {
res
}
fn parse_simple_from_pattern(&self, pair: Pair<Rule>) -> Result<FromEl> {
fn parse_simple_from_pattern(&self, pair: Pair) -> Result<FromEl> {
let mut pairs = pair.into_inner();
let name = pairs.next().unwrap().as_str();
if name.starts_with('_') {
@ -81,7 +81,7 @@ impl<'a> Session<'a> {
Ok(ret)
}
fn parse_node_edge_pattern(&self, pair: Pair<Rule>) -> Result<FromEl> {
fn parse_node_edge_pattern(&self, pair: Pair) -> Result<FromEl> {
let res: Result<Vec<_>> = pair
.into_inner()
.map(|p| match p.as_rule() {
@ -140,7 +140,7 @@ impl<'a> Session<'a> {
Ok(FromEl::Chain(res))
}
fn parse_node_pattern(&self, pair: Pair<Rule>) -> Result<EdgeOrNodeEl> {
fn parse_node_pattern(&self, pair: Pair) -> Result<EdgeOrNodeEl> {
let (table, binding, info, associates) = self.parse_node_or_edge(pair)?;
if info.kind != DataKind::Node {
return Err(CozoError::LogicError(format!("{} is not a node", table)));
@ -156,7 +156,7 @@ impl<'a> Session<'a> {
})
}
fn parse_edge_pattern(&self, pair: Pair<Rule>, is_fwd: bool) -> Result<EdgeOrNodeEl> {
fn parse_edge_pattern(&self, pair: Pair, is_fwd: bool) -> Result<EdgeOrNodeEl> {
let (table, binding, info, associates) = self.parse_node_or_edge(pair)?;
if info.kind != DataKind::Edge {
return Err(CozoError::LogicError(format!("{} is not an edge", table)));
@ -178,7 +178,7 @@ impl<'a> Session<'a> {
fn parse_node_or_edge(
&self,
pair: Pair<Rule>,
pair: Pair,
) -> Result<(String, Option<String>, TableInfo, Vec<(String, TableInfo)>)> {
let name;
@ -209,7 +209,7 @@ impl<'a> Session<'a> {
))
}
pub fn parse_where_pattern(&self, pair: Pair<Rule>) -> Result<Value> {
pub fn parse_where_pattern(&self, pair: Pair) -> Result<Value> {
let conditions = pair
.into_inner()
.map(Value::from_pair)
@ -217,7 +217,7 @@ impl<'a> Session<'a> {
Ok(Value::Apply(value::OP_AND.into(), conditions).to_static())
}
pub fn parse_select_pattern(&self, pair: Pair<Rule>) -> Result<Selection> {
pub fn parse_select_pattern(&self, pair: Pair) -> Result<Selection> {
let mut pairs = pair.into_inner();
let mut nxt = pairs.next().unwrap();
let scoped = match nxt.as_rule() {

@ -1,6 +1,12 @@
use crate::data::expr::{Expr, StaticExpr};
use crate::data::expr_parser::ExprParseError;
use crate::data::op::{Op, OpAdd, OpAnd, OpCoalesce, OpConcat, OpDiv, OpEq, OpGe, OpGt, OpIsNull, OpLe, OpLt, OpMerge, OpMinus, OpMod, OpMul, OpNe, OpNot, OpNotNull, OpOr, OpPow, OpStrCat, OpSub, partial_eval_and, partial_eval_coalesce, partial_eval_if_expr, partial_eval_or, row_eval_and, row_eval_coalesce, row_eval_if_expr, row_eval_or};
use crate::data::op::{
partial_eval_and, partial_eval_coalesce, partial_eval_if_expr, partial_eval_or,
partial_eval_switch_expr, row_eval_and, row_eval_coalesce, row_eval_if_expr, row_eval_or,
row_eval_switch_expr, Op, OpAdd, OpAnd, OpCoalesce, OpConcat, OpDiv, OpEq, OpGe, OpGt,
OpIsNull, OpLe, OpLt, OpMerge, OpMinus, OpMod, OpMul, OpNe, OpNot, OpNotNull, OpOr, OpPow,
OpStrCat, OpSub,
};
use crate::data::tuple_set::{ColId, TableId, TupleSetIdx};
use crate::data::value::{StaticValue, Value};
use std::borrow::Cow;
@ -82,7 +88,7 @@ impl<'a> Expr<'a> {
pub(crate) fn interpret_eval<C: ExprEvalContext + 'a>(self, ctx: &'a C) -> Result<Value> {
match self.partial_eval(ctx)? {
Expr::Const(v) => Ok(v),
v => Err(EvalError::IncompleteEvaluation(format!("{:?}", v)))
v => Err(EvalError::IncompleteEvaluation(format!("{:?}", v))),
}
}
@ -174,18 +180,19 @@ impl<'a> Expr<'a> {
has_null = true;
}
v
}).collect::<Result<Vec<_>>>()?;
})
.collect::<Result<Vec<_>>>()?;
if has_unevaluated {
Expr::Apply(op, args)
} else {
let args = args.into_iter().map(|v| {
match v {
let args = args
.into_iter()
.map(|v| match v {
Expr::Const(v) => v,
_ => unreachable!()
}
}).collect();
op.eval(has_null, args)
.map(Expr::Const)?
_ => unreachable!(),
})
.collect();
op.eval(has_null, args).map(Expr::Const)?
}
}
}
@ -205,6 +212,7 @@ impl<'a> Expr<'a> {
let (cond, if_part, else_part) = *args;
partial_eval_if_expr(ctx, cond, if_part, else_part)?
}
Expr::SwitchExpr(args) => partial_eval_switch_expr(ctx, args)?,
Expr::ApplyZero(_)
| Expr::ApplyOne(_, _)
| Expr::ApplyTwo(_, _)
@ -254,9 +262,7 @@ impl<'a> Expr<'a> {
name if name == OpGe.name() => Expr::Ge(extract_optimized_bin_args(args).into()),
name if name == OpLt.name() => Expr::Lt(extract_optimized_bin_args(args).into()),
name if name == OpLe.name() => Expr::Le(extract_optimized_bin_args(args).into()),
name if name == OpNot.name() => {
Expr::Not(extract_optimized_u_args(args).into())
}
name if name == OpNot.name() => Expr::Not(extract_optimized_u_args(args).into()),
name if name == OpMinus.name() => {
Expr::Minus(extract_optimized_u_args(args).into())
}
@ -290,19 +296,17 @@ impl<'a> Expr<'a> {
}
arg
}
_ => {
match op.arity() {
Some(0) => Expr::ApplyZero(op),
Some(1) => Expr::ApplyOne(op, args.into_iter().next().unwrap().into()),
Some(2) => {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
Expr::ApplyTwo(op, (left, right).into())
}
_ => Expr::Apply(op, args.into_iter().map(|v| v.optimize_ops()).collect())
_ => match op.arity() {
Some(0) => Expr::ApplyZero(op),
Some(1) => Expr::ApplyOne(op, args.into_iter().next().unwrap().into()),
Some(2) => {
let mut args = args.into_iter();
let left = args.next().unwrap();
let right = args.next().unwrap();
Expr::ApplyTwo(op, (left, right).into())
}
}
_ => Expr::Apply(op, args.into_iter().map(|v| v.optimize_ops()).collect()),
},
},
Expr::ApplyAgg(op, a_args, args) => Expr::ApplyAgg(
op,
@ -313,8 +317,20 @@ impl<'a> Expr<'a> {
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::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::TableCol(_, _)
@ -434,6 +450,7 @@ impl<'a> Expr<'a> {
let (cond, if_part, else_part) = args.as_ref();
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)? {
@ -565,12 +582,10 @@ impl<'a> Expr<'a> {
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::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,
@ -578,21 +593,9 @@ impl<'a> Expr<'a> {
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::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)?,
};
Ok(res)
}

@ -36,6 +36,7 @@ pub(crate) enum 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
ApplyZero(Arc<dyn Op + Send + Sync>),
ApplyOne(Arc<dyn Op + Send + Sync>, Box<Expr<'a>>),
@ -104,7 +105,13 @@ impl<'a> Debug for Expr<'a> {
),
Expr::ApplyZero(op) => write!(f, "({})", op.name()),
Expr::ApplyOne(op, arg) => write!(f, "({} {:?})", op.name(), arg),
Expr::ApplyTwo(op, args) => write!(f, "({} {:?} {:?})", op.name(), args.as_ref().0, args.as_ref().1),
Expr::ApplyTwo(op, args) => write!(
f,
"({} {:?} {:?})",
op.name(),
args.as_ref().0,
args.as_ref().1
),
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),
@ -143,6 +150,15 @@ impl<'a> Debug for Expr<'a> {
let args = args.as_ref();
write!(f, "(if {:?} {:?} {:?})", args.0, args.1, args.2)
}
Expr::SwitchExpr(args) => {
let mut args = args.iter();
let (expr, default) = args.next().unwrap();
write!(f, "(switch {:?}", expr)?;
for (cond, expr) in args {
write!(f, ", {:?} => {:?}", cond, expr)?;
}
write!(f, ", .. => {:?})", default)
}
Expr::FieldAcc(field, arg) => write!(f, "(.{} {:?})", field, arg),
Expr::IdxAcc(i, arg) => write!(f, "(.{} {:?})", i, arg),
}
@ -313,7 +329,7 @@ fn build_value_from_binop<'a>(name: &str, (left, right): (Expr<'a>, Expr<'a>)) -
Value::from(name.to_string()),
Value::from(vec![Value::from(left), Value::from(right)]),
]
.into(),
.into(),
)
}
@ -324,7 +340,7 @@ fn build_value_from_uop<'a>(name: &str, arg: Expr<'a>) -> Value<'a> {
Value::from(name.to_string()),
Value::from(vec![Value::from(arg)]),
]
.into(),
.into(),
)
}
@ -352,7 +368,7 @@ impl<'a> From<Expr<'a>> for Value<'a> {
cid.is_key.into(),
Value::from(cid.id as i64),
]
.into(),
.into(),
),
Expr::TupleSetIdx(sid) => build_tagged_value(
"TupleSetIdx",
@ -361,14 +377,12 @@ impl<'a> From<Expr<'a>> for Value<'a> {
Value::from(sid.t_set as i64),
Value::from(sid.col_idx as i64),
]
.into(),
.into(),
),
Expr::ApplyZero(op) => build_tagged_value(
"Apply",
vec![Value::from(op.name().to_string()), Value::List(vec![])].into(),
),
Expr::ApplyZero(op) => {
build_tagged_value(
"Apply",
vec![Value::from(op.name().to_string()), Value::List(vec![])].into(),
)
}
Expr::ApplyOne(op, arg) => build_value_from_uop(op.name(), *arg),
Expr::ApplyTwo(op, args) => build_value_from_binop(op.name(), *args),
Expr::Add(arg) => build_value_from_binop(OpAdd.name(), *arg),
@ -397,11 +411,14 @@ impl<'a> From<Expr<'a>> for Value<'a> {
Value::from(op.name().to_string()),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
.into(),
),
Expr::IfExpr(_) => {
todo!()
},
}
Expr::SwitchExpr(_) => {
todo!()
}
Expr::ApplyAgg(op, a_args, args) => build_tagged_value(
"ApplyAgg",
vec![
@ -413,7 +430,7 @@ impl<'a> From<Expr<'a>> for Value<'a> {
.into(),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
.into(),
),
Expr::FieldAcc(f, v) => {
build_tagged_value("FieldAcc", vec![f.into(), Value::from(*v)].into())

@ -6,9 +6,8 @@ use crate::data::op::{
use crate::data::value::Value;
use crate::parser::number::parse_int;
use crate::parser::text_identifier::parse_string;
use crate::parser::Rule;
use crate::parser::{Pair, Rule};
use lazy_static::lazy_static;
use pest::iterators::Pair;
use pest::prec_climber::{Assoc, Operator, PrecClimber};
use std::borrow::Cow;
use std::collections::BTreeMap;
@ -32,10 +31,10 @@ pub(crate) enum ExprParseError {
type Result<T> = result::Result<T, ExprParseError>;
impl<'a> TryFrom<Pair<'a, Rule>> for Expr<'a> {
impl<'a> TryFrom<Pair<'a>> for Expr<'a> {
type Error = ExprParseError;
fn try_from(pair: Pair<'a, Rule>) -> Result<Self> {
fn try_from(pair: Pair<'a>) -> Result<Self> {
PREC_CLIMBER.climb(pair.into_inner(), build_expr_primary, build_expr_infix)
}
}
@ -63,7 +62,7 @@ lazy_static! {
};
}
fn build_if_expr(pair: Pair<Rule>) -> Result<Expr> {
fn build_if_expr(pair: Pair) -> Result<Expr> {
let mut if_parts = vec![];
let mut else_part = Expr::Const(Value::Null);
for pair in pair.into_inner() {
@ -73,13 +72,52 @@ fn build_if_expr(pair: Pair<Rule>) -> Result<Expr> {
if_parts.push(build_if_clause(pair)?)
}
}
Ok(if_parts.into_iter().rev().fold(else_part, |accum, (cond, expr)| {
Expr::IfExpr((cond, expr, accum).into())
}))
Ok(if_parts
.into_iter()
.rev()
.fold(else_part, |accum, (cond, expr)| {
Expr::IfExpr((cond, expr, accum).into())
}))
}
fn build_cond_expr(pair: Pair) -> Result<Expr> {
let mut res = Expr::Const(Value::Null);
for pair in pair.into_inner().rev() {
let (cond, expr) = build_switch_pattern(pair)?;
res = Expr::IfExpr((cond, expr, res).into());
}
Ok(res)
}
fn build_switch_expr(pair: Pair) -> Result<Expr> {
let mut pairs = pair.into_inner();
let expr = pairs.next().unwrap();
let expr = Expr::try_from(expr)?;
let mut collected = vec![(expr, Expr::Const(Value::Null))];
for pair in pairs {
match pair.as_rule() {
Rule::switch_pattern => {
collected.push(build_switch_pattern(pair)?);
}
Rule::default_pattern => {
collected[0].1 = Expr::try_from(pair.into_inner().next().unwrap())?;
break;
}
_ => unreachable!(),
}
}
Ok(Expr::SwitchExpr(collected))
}
fn build_switch_pattern(pair: Pair) -> Result<(Expr, Expr)> {
let mut pairs = pair.into_inner();
Ok((
Expr::try_from(pairs.next().unwrap())?,
Expr::try_from(pairs.next().unwrap())?,
))
}
fn build_if_clause(pair: Pair<Rule>) -> Result<(Expr, Expr)> {
fn build_if_clause(pair: Pair) -> Result<(Expr, Expr)> {
let mut pairs = pair.into_inner();
let cond = pairs.next().unwrap();
let cond = Expr::try_from(cond)?;
@ -88,7 +126,7 @@ fn build_if_clause(pair: Pair<Rule>) -> Result<(Expr, Expr)> {
Ok((cond, expr))
}
fn build_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
fn build_expr_primary(pair: Pair) -> Result<Expr> {
match pair.as_rule() {
Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()),
Rule::term => {
@ -129,6 +167,8 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
Rule::negate => Arc::new(OpNot),
Rule::minus => Arc::new(OpMinus),
Rule::if_expr => return build_if_expr(p),
Rule::cond_expr => return build_cond_expr(p),
Rule::switch_expr => return build_switch_expr(p),
_ => unreachable!(),
};
let term = build_expr_primary(inner.next().unwrap())?;
@ -245,7 +285,7 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
fn build_expr_infix<'a>(
lhs: Result<Expr<'a>>,
op: Pair<Rule>,
op: Pair,
rhs: Result<Expr<'a>>,
) -> Result<Expr<'a>> {
let lhs = lhs?;
@ -365,28 +405,26 @@ pub(crate) mod tests {
#[test]
fn conditionals() -> Result<()> {
let s = r#"if a { b + c * d } else if (x) { y } else {z}"#;
dbg!(str2expr(s));
dbg!(str2expr(s))?;
let s = r#"if a { b + c * d }"#;
dbg!(str2expr(s));
dbg!(str2expr(s))?;
let s = r#"(if a { b + c * d } else if (x) { y } else {z})+1"#;
dbg!(str2expr(s));
// let s = r#"cond {
// a > 1 => 1,
// a == 1 => 2,
// true => 3
// }"#;
// let pair = CozoParser::parse(Rule::expr, s).unwrap();
// dbg!(pair);
//
// let s = r#"switch(a) {
// 1 => 1,
// 2 => 2,
// .. => 3
// }"#;
// let pair = CozoParser::parse(Rule::expr, s).unwrap();
// dbg!(pair);
dbg!(str2expr(s))?;
let s = r#"cond {
a > 1 => 1,
a == 1 => 2,
true => 3
}"#;
dbg!(str2expr(s))?;
let s = r#"switch(a) {
1 => 1,
2 => 2,
.. => 3
}"#;
dbg!(str2expr(s))?;
Ok(())
}

@ -2,11 +2,10 @@ mod arithmetic;
mod boolean;
mod combine;
mod comparison;
mod text;
mod control;
mod text;
use crate::data::eval::EvalError;
use crate::data::expr::Expr;
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use std::result;
@ -15,8 +14,8 @@ pub(crate) use arithmetic::*;
pub(crate) use boolean::*;
pub(crate) use combine::*;
pub(crate) use comparison::*;
pub(crate) use text::*;
pub(crate) use control::*;
pub(crate) use text::*;
type Result<T> = result::Result<T, EvalError>;
@ -99,39 +98,6 @@ pub(crate) trait Op: Send + Sync {
self.name()
)
}
// fn partial_eval<'a>(&self, args: Vec<Expr<'a>>) -> Result<Option<Expr<'a>>> {
// // usually those functions that needs specialized implementations are those with arity None
// if let Some(arity) = self.arity() {
// if arity != args.len() {
// return Err(EvalError::ArityMismatch(self.name().to_string(), arity));
// }
// }
// let mut has_null = false;
// match args
// .iter()
// .map(|v| match v {
// Expr::Const(v) => {
// if *v == Value::Null {
// has_null = true;
// }
// Some(v.clone())
// }
// _ => None,
// })
// .collect::<Vec<_>>()
// .into_iter()
// .collect::<Option<Vec<Value>>>()
// {
// Some(args) => Ok(Some(Expr::Const(self.eval(has_null, args)?))),
// None => {
// if self.non_null_args() && has_null {
// Ok(Some(Expr::Const(Value::Null)))
// } else {
// Ok(None)
// }
// }
// }
// }
}
pub(crate) trait AggOp: Send + Sync {
@ -145,13 +111,6 @@ pub(crate) trait AggOp: Send + Sync {
false
}
fn name(&self) -> &str;
// fn partial_eval<'a>(
// &self,
// a_args: Vec<Expr<'a>>,
// args: Vec<Expr<'a>>,
// ) -> Result<Option<Expr<'a>>> {
// todo!()
// }
}
pub(crate) struct UnresolvedOp(pub String);

@ -76,7 +76,10 @@ impl Op for OpOr {
}
}
pub(crate) fn partial_eval_or<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Vec<Expr<'a>>) -> Result<Expr<'a>> {
pub(crate) fn partial_eval_or<'a, T: ExprEvalContext + 'a>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
let mut collected = vec![];
let mut has_null = false;
for arg in args {
@ -100,7 +103,7 @@ pub(crate) fn partial_eval_or<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Vec
}
collected.extend(args);
}
expr => collected.push(expr)
expr => collected.push(expr),
}
}
if has_null {
@ -109,12 +112,15 @@ pub(crate) fn partial_eval_or<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Vec
Ok(match collected.len() {
0 => Expr::Const(Value::Bool(false)),
1 => collected.pop().unwrap(),
_ => Expr::Apply(Arc::new(OpOr), collected)
_ => Expr::Apply(Arc::new(OpOr), collected),
})
}
pub(crate) fn row_eval_or<'a, T: RowEvalContext + 'a>(ctx: &'a T, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Result<Value<'a>> {
pub(crate) fn row_eval_or<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
left: &'a Expr<'a>,
right: &'a Expr<'a>,
) -> Result<Value<'a>> {
let left = left.row_eval(ctx)?;
if left == Value::Bool(true) {
return Ok(Value::Bool(true));
@ -166,7 +172,10 @@ impl Op for OpAnd {
}
}
pub(crate) fn partial_eval_and<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Vec<Expr<'a>>) -> Result<Expr<'a>> {
pub(crate) fn partial_eval_and<'a, T: ExprEvalContext + 'a>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
let mut collected = vec![];
let mut has_null = false;
for arg in args {
@ -190,7 +199,7 @@ pub(crate) fn partial_eval_and<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Ve
}
collected.extend(args);
}
expr => collected.push(expr)
expr => collected.push(expr),
}
}
if has_null {
@ -199,11 +208,15 @@ pub(crate) fn partial_eval_and<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Ve
Ok(match collected.len() {
0 => Expr::Const(Value::Bool(true)),
1 => collected.pop().unwrap(),
_ => Expr::Apply(Arc::new(OpAnd), collected)
_ => Expr::Apply(Arc::new(OpAnd), collected),
})
}
pub(crate) fn row_eval_and<'a, T: RowEvalContext + 'a>(ctx: &'a T, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Result<Value<'a>> {
pub(crate) fn row_eval_and<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
left: &'a Expr<'a>,
right: &'a Expr<'a>,
) -> Result<Value<'a>> {
let left = left.row_eval(ctx)?;
if left == Value::Bool(false) {
return Ok(Value::Bool(false));
@ -221,7 +234,6 @@ pub(crate) fn row_eval_and<'a, T: RowEvalContext + 'a>(ctx: &'a T, left: &'a Exp
}
}
pub(crate) struct OpNot;
impl Op for OpNot {

@ -66,4 +66,4 @@ impl Op for OpMerge {
}
Ok(coll.into())
}
}
}

@ -1,9 +1,9 @@
use std::result;
use std::sync::Arc;
use crate::data::eval::{EvalError, ExprEvalContext, RowEvalContext};
use crate::data::expr::Expr;
use crate::data::op::Op;
use crate::data::value::Value;
use std::result;
use std::sync::Arc;
type Result<T> = result::Result<T, EvalError>;
@ -31,7 +31,11 @@ impl Op for OpCoalesce {
}
}
pub(crate) fn row_eval_coalesce<'a, T: RowEvalContext + 'a>(ctx: &'a T, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Result<Value<'a>> {
pub(crate) fn row_eval_coalesce<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
left: &'a Expr<'a>,
right: &'a Expr<'a>,
) -> Result<Value<'a>> {
let left = left.row_eval(ctx)?;
if left != Value::Null {
return Ok(left);
@ -41,7 +45,10 @@ pub(crate) fn row_eval_coalesce<'a, T: RowEvalContext + 'a>(ctx: &'a T, left: &'
const IF_NAME: &str = "if";
pub(crate) fn partial_eval_coalesce<'a, T: ExprEvalContext + 'a>(ctx: &'a T, args: Vec<Expr<'a>>) -> Result<Expr<'a>> {
pub(crate) fn partial_eval_coalesce<'a, T: ExprEvalContext + 'a>(
ctx: &'a T,
args: Vec<Expr<'a>>,
) -> Result<Expr<'a>> {
let mut collected = vec![];
for arg in args {
match arg.partial_eval(ctx)? {
@ -49,44 +56,105 @@ pub(crate) fn partial_eval_coalesce<'a, T: ExprEvalContext + 'a>(ctx: &'a T, arg
Expr::Apply(op, args) if op.name() == OpCoalesce.name() => {
collected.extend(args);
}
expr => collected.push(expr)
expr => collected.push(expr),
}
}
Ok(match collected.len() {
0 => Expr::Const(Value::Null),
1 => collected.pop().unwrap(),
_ => Expr::Apply(Arc::new(OpCoalesce), collected)
_ => Expr::Apply(Arc::new(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>) -> Result<Value<'a>> {
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>,
) -> Result<Value<'a>> {
let cond = cond.row_eval(ctx)?;
match cond {
Value::Bool(b) => {
Ok(if b {
if_part.row_eval(ctx)?
} else {
else_part.row_eval(ctx)?
})
}
Value::Bool(b) => Ok(if b {
if_part.row_eval(ctx)?
} else {
else_part.row_eval(ctx)?
}),
Value::Null => Ok(Value::Null),
v => Err(EvalError::OpTypeMismatch(IF_NAME.to_string(), vec![v.to_static()]))
v => Err(EvalError::OpTypeMismatch(
IF_NAME.to_string(),
vec![v.to_static()],
)),
}
}
pub(crate) fn partial_eval_if_expr<'a, T: ExprEvalContext + 'a>(ctx: &'a T, cond: Expr<'a>, if_part: Expr<'a>, else_part: Expr<'a>) -> Result<Expr<'a>> {
pub(crate) fn partial_eval_if_expr<'a, T: ExprEvalContext + 'a>(
ctx: &'a T,
cond: Expr<'a>,
if_part: Expr<'a>,
else_part: Expr<'a>,
) -> Result<Expr<'a>> {
let cond = cond.partial_eval(ctx)?;
match cond {
Expr::Const(Value::Null) => Ok(Expr::Const(Value::Null)),
Expr::Const(Value::Bool(b)) => {
Ok(if b {
if_part.partial_eval(ctx)?
} else {
else_part.partial_eval(ctx)?
})
Expr::Const(Value::Bool(b)) => Ok(if b {
if_part.partial_eval(ctx)?
} else {
else_part.partial_eval(ctx)?
}),
cond => Ok(Expr::IfExpr(
(
cond,
if_part.partial_eval(ctx)?,
else_part.partial_eval(ctx)?,
)
.into(),
)),
}
}
pub(crate) fn row_eval_switch_expr<'a, T: RowEvalContext + 'a>(
ctx: &'a T,
args: &'a [(Expr<'a>, Expr<'a>)],
) -> Result<Value<'a>> {
let mut args = args.iter();
let (expr, default) = args.next().unwrap();
let expr = expr.row_eval(ctx)?;
for (cond, target) in args {
let cond = cond.row_eval(ctx)?;
if cond == expr {
return target.row_eval(ctx);
}
cond => {
Ok(Expr::IfExpr((cond, if_part.partial_eval(ctx)?, else_part.partial_eval(ctx)?).into()))
}
default.row_eval(ctx)
}
pub(crate) fn partial_eval_switch_expr<'a, T: ExprEvalContext + 'a>(
ctx: &'a T,
args: Vec<(Expr<'a>, Expr<'a>)>,
) -> Result<Expr<'a>> {
let mut args = args.into_iter();
let (expr, mut default) = args.next().unwrap();
let expr = expr.partial_eval(ctx)?;
let expr_evaluated = matches!(expr, Expr::Const(_));
let mut collected = vec![];
for (cond, target) in args {
let cond = cond.partial_eval(ctx)?;
if expr_evaluated && matches!(cond, Expr::Const(_)) {
if cond == expr {
default = target.partial_eval(ctx)?;
break;
} else {
// cannot match, fall through
}
} else {
collected.push((cond, target.partial_eval(ctx)?))
}
}
}
if collected.is_empty() {
Ok(default)
} else {
let mut args = vec![(expr, default)];
args.extend(collected);
Ok(Expr::SwitchExpr(args))
}
}

@ -1,7 +1,6 @@
use crate::data::value::{StaticValue, Value};
use crate::parser::text_identifier::build_name_in_def;
use crate::parser::{CozoParser, Rule};
use pest::iterators::Pair;
use crate::parser::{CozoParser, Pair, Rule};
use pest::Parser;
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter};
@ -212,10 +211,10 @@ impl TryFrom<&str> for Typing {
}
}
impl TryFrom<Pair<'_, Rule>> for Typing {
impl TryFrom<Pair<'_>> for Typing {
type Error = TypingError;
fn try_from(pair: Pair<Rule>) -> Result<Self> {
fn try_from(pair: Pair) -> Result<Self> {
Ok(match pair.as_rule() {
Rule::simple_type => match pair.as_str() {
"Any" => Typing::Any,

@ -6,6 +6,9 @@ use pest_derive::Parser;
#[grammar = "grammar.pest"]
pub(crate) struct CozoParser;
pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>;
pub(crate) type Pairs<'a> = pest::iterators::Pairs<'a, Rule>;
#[cfg(test)]
mod tests {
use super::*;

@ -1,6 +1,5 @@
use crate::parser::number::parse_int;
use crate::parser::Rule;
use pest::iterators::Pair;
use crate::parser::{Pair, Rule};
use std::result;
#[derive(thiserror::Error, Debug)]
@ -18,7 +17,7 @@ pub(crate) enum TextParseError {
type Result<T> = result::Result<T, TextParseError>;
#[inline]
fn parse_raw_string(pair: Pair<Rule>) -> Result<String> {
fn parse_raw_string(pair: Pair) -> Result<String> {
Ok(pair
.into_inner()
.into_iter()
@ -29,7 +28,7 @@ fn parse_raw_string(pair: Pair<Rule>) -> Result<String> {
}
#[inline]
fn parse_quoted_string(pair: Pair<Rule>) -> Result<String> {
fn parse_quoted_string(pair: Pair) -> Result<String> {
let pairs = pair.into_inner().next().unwrap().into_inner();
let mut ret = String::with_capacity(pairs.as_str().len());
for pair in pairs {
@ -50,7 +49,7 @@ fn parse_quoted_string(pair: Pair<Rule>) -> Result<String> {
ret.push(ch);
}
s if s.starts_with('\\') => {
return Err(TextParseError::InvalidEscapeSequence(s.to_string()))
return Err(TextParseError::InvalidEscapeSequence(s.to_string()));
}
s => ret.push_str(s),
}
@ -59,7 +58,7 @@ fn parse_quoted_string(pair: Pair<Rule>) -> Result<String> {
}
#[inline]
fn parse_s_quoted_string(pair: Pair<Rule>) -> Result<String> {
fn parse_s_quoted_string(pair: Pair) -> Result<String> {
let pairs = pair.into_inner().next().unwrap().into_inner();
let mut ret = String::with_capacity(pairs.as_str().len());
for pair in pairs {
@ -80,7 +79,7 @@ fn parse_s_quoted_string(pair: Pair<Rule>) -> Result<String> {
ret.push(ch);
}
s if s.starts_with('\\') => {
return Err(TextParseError::InvalidEscapeSequence(s.to_string()))
return Err(TextParseError::InvalidEscapeSequence(s.to_string()));
}
s => ret.push_str(s),
}
@ -89,7 +88,7 @@ fn parse_s_quoted_string(pair: Pair<Rule>) -> Result<String> {
}
#[inline]
pub(crate) fn parse_string(pair: Pair<Rule>) -> Result<String> {
pub(crate) fn parse_string(pair: Pair) -> Result<String> {
match pair.as_rule() {
Rule::quoted_string => Ok(parse_quoted_string(pair)?),
Rule::s_quoted_string => Ok(parse_s_quoted_string(pair)?),
@ -99,11 +98,11 @@ pub(crate) fn parse_string(pair: Pair<Rule>) -> Result<String> {
}
}
pub(crate) fn parse_ident(pair: Pair<Rule>) -> String {
pub(crate) fn parse_ident(pair: Pair) -> String {
pair.as_str().to_string()
}
pub(crate) fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Result<String> {
pub(crate) fn build_name_in_def(pair: Pair, forbid_underscore: bool) -> Result<String> {
let inner = pair.into_inner().next().unwrap();
let name = match inner.as_rule() {
Rule::ident => parse_ident(inner),
@ -117,7 +116,7 @@ pub(crate) fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Re
}
}
pub(crate) fn parse_col_name(pair: Pair<Rule>) -> Result<(String, bool)> {
pub(crate) fn parse_col_name(pair: Pair) -> Result<(String, bool)> {
let mut pairs = pair.into_inner();
let mut is_key = false;
let mut nxt_pair = pairs.next().unwrap();

Loading…
Cancel
Save