Skip to content

Commit 7104a8c

Browse files
authored
Implement other binary and unary ops in evaluator (#210)
1 parent a3778d0 commit 7104a8c

File tree

6 files changed

+787
-196
lines changed

6 files changed

+787
-196
lines changed

partiql-eval/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ ordered-float = "3.*"
2727
itertools = "0.10.*"
2828
unicase = "2.*"
2929
rust_decimal = { version = "1.25.0", default-features = false, features = ["std"] }
30+
rust_decimal_macros = "1.26"
3031

3132
[dev-dependencies]
3233
criterion = "0.4"

partiql-eval/src/eval.rs

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use petgraph::prelude::StableGraph;
99
use petgraph::{Directed, Incoming, Outgoing};
1010

1111
use partiql_value::Value::{Boolean, Missing, Null};
12-
use partiql_value::{partiql_bag, Bag, BindingsName, Tuple, Value};
12+
use partiql_value::{
13+
partiql_bag, Bag, BinaryAnd, BinaryOr, BindingsName, NullableEq, NullableOrd, Tuple, UnaryPlus,
14+
Value,
15+
};
1316

1417
use crate::env::basic::MapBindings;
1518
use crate::env::Bindings;
@@ -278,16 +281,40 @@ impl EvalExpr for EvalLitExpr {
278281
}
279282

280283
#[derive(Debug)]
281-
pub struct EvalBinopExpr {
282-
pub op: EvalBinop,
284+
pub struct EvalUnaryOpExpr {
285+
pub op: EvalUnaryOp,
286+
pub operand: Box<dyn EvalExpr>,
287+
}
288+
289+
#[derive(Debug)]
290+
pub struct EvalBinOpExpr {
291+
pub op: EvalBinOp,
283292
pub lhs: Box<dyn EvalExpr>,
284293
pub rhs: Box<dyn EvalExpr>,
285294
}
286295

287296
// TODO we should replace this enum with some identifier that can be looked up in a symtab/funcregistry
288297
#[derive(Debug)]
289-
#[allow(dead_code)] // TODO remove once out of PoC
290-
pub enum EvalBinop {
298+
pub enum EvalUnaryOp {
299+
Pos,
300+
Neg,
301+
Not,
302+
}
303+
304+
impl EvalExpr for EvalUnaryOpExpr {
305+
fn evaluate(&self, bindings: &Tuple, ctx: &dyn EvalContext) -> Value {
306+
let value = self.operand.evaluate(bindings, ctx);
307+
match self.op {
308+
EvalUnaryOp::Pos => value.positive(),
309+
EvalUnaryOp::Neg => -value,
310+
EvalUnaryOp::Not => !value,
311+
}
312+
}
313+
}
314+
315+
// TODO we should replace this enum with some identifier that can be looked up in a symtab/funcregistry
316+
#[derive(Debug)]
317+
pub enum EvalBinOp {
291318
And,
292319
Or,
293320
Concat,
@@ -307,46 +334,53 @@ pub enum EvalBinop {
307334
Exp,
308335
}
309336

310-
impl EvalExpr for EvalBinopExpr {
337+
impl EvalExpr for EvalBinOpExpr {
311338
fn evaluate(&self, bindings: &Tuple, ctx: &dyn EvalContext) -> Value {
339+
#[inline]
340+
fn short_circuit(op: &EvalBinOp, value: &Value) -> Option<Value> {
341+
match (op, value) {
342+
(EvalBinOp::And, Value::Boolean(false)) => Some(false.into()),
343+
(EvalBinOp::Or, Value::Boolean(true)) => Some(true.into()),
344+
(_, Value::Missing) => Some(Value::Missing),
345+
_ => None,
346+
}
347+
}
348+
312349
let lhs = self.lhs.evaluate(bindings, ctx);
350+
if let Some(propagate) = short_circuit(&self.op, &lhs) {
351+
return propagate;
352+
}
353+
313354
let rhs = self.rhs.evaluate(bindings, ctx);
314-
// Missing and Null propagation. Missing has precedence over Null
315-
if lhs == Value::Missing || rhs == Value::Missing {
316-
Value::Missing
317-
} else if lhs == Value::Null || rhs == Value::Null {
318-
Value::Null
319-
} else {
320-
match self.op {
321-
EvalBinop::And => todo!(),
322-
EvalBinop::Or => todo!(),
323-
EvalBinop::Concat => {
324-
// TODO non-naive concat
325-
let lhs = if let Value::String(s) = lhs {
326-
*s
327-
} else {
328-
format!("{:?}", lhs)
329-
};
330-
let rhs = if let Value::String(s) = rhs {
331-
*s
332-
} else {
333-
format!("{:?}", lhs)
334-
};
335-
Value::String(Box::new(format!("{}{}", lhs, rhs)))
336-
}
337-
EvalBinop::Eq => todo!(),
338-
EvalBinop::Neq => todo!(),
339-
EvalBinop::Gt => Boolean(lhs > rhs),
340-
EvalBinop::Gteq => Boolean(lhs >= rhs),
341-
EvalBinop::Lt => Boolean(lhs < rhs),
342-
EvalBinop::Lteq => Boolean(lhs <= rhs),
343-
EvalBinop::Add => lhs + rhs,
344-
EvalBinop::Sub => lhs - rhs,
345-
EvalBinop::Mul => lhs * rhs,
346-
EvalBinop::Div => lhs / rhs,
347-
EvalBinop::Mod => lhs % rhs,
348-
EvalBinop::Exp => todo!("Exponentiation"),
355+
match self.op {
356+
EvalBinOp::And => lhs.and(rhs),
357+
EvalBinOp::Or => lhs.or(rhs),
358+
EvalBinOp::Concat => {
359+
// TODO non-naive concat. Also doesn't properly propagate MISSING and NULL
360+
let lhs = if let Value::String(s) = lhs {
361+
*s
362+
} else {
363+
format!("{:?}", lhs)
364+
};
365+
let rhs = if let Value::String(s) = rhs {
366+
*s
367+
} else {
368+
format!("{:?}", lhs)
369+
};
370+
Value::String(Box::new(format!("{}{}", lhs, rhs)))
349371
}
372+
EvalBinOp::Eq => lhs.eq(rhs),
373+
EvalBinOp::Neq => lhs.neq(rhs),
374+
EvalBinOp::Gt => lhs.gt(rhs),
375+
EvalBinOp::Gteq => lhs.gteq(rhs),
376+
EvalBinOp::Lt => lhs.lt(rhs),
377+
EvalBinOp::Lteq => lhs.lteq(rhs),
378+
EvalBinOp::Add => lhs + rhs,
379+
EvalBinOp::Sub => lhs - rhs,
380+
EvalBinOp::Mul => lhs * rhs,
381+
EvalBinOp::Div => lhs / rhs,
382+
EvalBinOp::Mod => lhs % rhs,
383+
EvalBinOp::Exp => todo!("Exponentiation"),
350384
}
351385
}
352386
}

0 commit comments

Comments
 (0)