expressions

main
Ziyang Hu 2 years ago
parent 4c12cb6b7e
commit 62c63771d6

@ -8,6 +8,7 @@ authors = ["Ziyang Hu"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
casey = "0.3.3"
uuid = { version = "0.8", features = ["v1", "v4", "serde"] }
rand = "0.8.5"
anyhow = "1.0"

@ -1,3 +1,12 @@
## TODO
* Use extension traits to simplify stuff!
* [ ] predicates
* [ ] negation
* [ ] aggregation
* [ ] stratum
* [ ] disjunction
* [ ] magic sets
* [ ] function symbol
* [ ] arithmetic
* [ ] range scan
* [ ] public API

@ -0,0 +1,154 @@
use std::fmt::{Debug, Formatter};
use anyhow::Result;
use itertools::Itertools;
use crate::data::expr::ExprError::UnexpectedArgs;
use crate::data::value::DataValue;
use crate::query::compile::Term;
#[derive(Debug, thiserror::Error)]
pub enum ExprError {
#[error("unexpected args for {0}: {1:?}")]
UnexpectedArgs(&'static str, Vec<DataValue>),
}
#[derive(Debug, Clone)]
pub(crate) enum Expr {
Const(Term<DataValue>),
Apply(&'static Op, Box<[Expr]>),
}
#[derive(Clone)]
pub(crate) struct Op {
name: &'static str,
min_arity: usize,
vararg: bool,
is_predicate: bool,
inner: fn(&[DataValue]) -> Result<DataValue>,
}
impl Debug for Op {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(self.name).field(&self.min_arity).finish()
}
}
macro_rules! define_op {
($name:ident, $min_arity:expr, $vararg:expr, $is_pred:expr) => {
pub(crate) const $name: Op = Op {
name: stringify!($name),
min_arity: $min_arity,
vararg: $vararg,
is_predicate: $is_pred,
inner: ::casey::lower!($name),
};
};
}
define_op!(OP_EQ, 0, true, true);
pub(crate) fn op_eq(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(args.iter().all_equal()))
}
define_op!(OP_NEQ, 0, true, true);
fn op_neq(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(!args.iter().all_equal()))
}
define_op!(OP_ADD, 0, true, false);
fn op_add(args: &[DataValue]) -> Result<DataValue> {
let mut i_accum = 0i64;
let mut f_accum = 0.0f64;
for arg in args {
match arg {
DataValue::Int(i) => i_accum += i,
DataValue::Float(f) => f_accum += f.0,
_ => return Err(UnexpectedArgs("add", args.to_vec()).into()),
}
}
if f_accum == 0.0f64 {
Ok(DataValue::Int(i_accum))
} else {
Ok(DataValue::Float((i_accum as f64 + f_accum).into()))
}
}
define_op!(OP_SUB, 2, false, false);
fn op_sub(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => DataValue::Int(*a - *b),
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(*a - *b),
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64) - b.0).into()),
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0 - (*b as f64)).into()),
_ => return Err(UnexpectedArgs("sub", args.to_vec()).into()),
})
}
define_op!(OP_MUL, 0, true, false);
fn op_mul(args: &[DataValue]) -> Result<DataValue> {
let mut i_accum = 1i64;
let mut f_accum = 1.0f64;
for arg in args {
match arg {
DataValue::Int(i) => i_accum *= i,
DataValue::Float(f) => f_accum *= f.0,
_ => return Err(UnexpectedArgs("mul", args.to_vec()).into()),
}
}
if f_accum == 1.0f64 {
Ok(DataValue::Int(i_accum))
} else {
Ok(DataValue::Float((i_accum as f64 + f_accum).into()))
}
}
define_op!(OP_DIV, 2, false, false);
fn op_div(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => {
DataValue::Float(((*a as f64) / (*b as f64)).into())
}
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(*a / *b),
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64) / b.0).into()),
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0 / (*b as f64)).into()),
_ => return Err(UnexpectedArgs("div", args.to_vec()).into()),
})
}
define_op!(OP_AND, 0, true, true);
fn op_and(args: &[DataValue]) -> Result<DataValue> {
for arg in args {
if let DataValue::Bool(b) = arg {
if !b {
return Ok(DataValue::Bool(false));
}
} else {
return Err(UnexpectedArgs("and", args.to_vec()).into());
}
}
Ok(DataValue::Bool(true))
}
define_op!(OP_OR, 0, true, true);
fn op_or(args: &[DataValue]) -> Result<DataValue> {
for arg in args {
if let DataValue::Bool(b) = arg {
if *b {
return Ok(DataValue::Bool(true));
}
} else {
return Err(UnexpectedArgs("or", args.to_vec()).into());
}
}
Ok(DataValue::Bool(false))
}
define_op!(OP_NOT, 1, false, true);
fn op_not(args: &[DataValue]) -> Result<DataValue> {
if let DataValue::Bool(b) = &args[0] {
Ok(DataValue::Bool(!*b))
} else {
Err(UnexpectedArgs("not", args.to_vec()).into())
}
}

@ -7,4 +7,5 @@ pub(crate) mod keyword;
pub(crate) mod triple;
pub(crate) mod value;
pub(crate) mod tuple;
pub(crate) mod expr;

@ -98,11 +98,6 @@ pub struct PredicateAtom {
pub(crate) right: Term<DataValue>,
}
#[derive(Clone, Debug)]
pub(crate) enum Expr {
Const(Term<DataValue>),
}
#[derive(Clone, Debug)]
pub enum Atom {
AttrTriple(AttrTripleAtom),

Loading…
Cancel
Save