main
Ziyang Hu 2 years ago
parent 1cfa704fcc
commit 79162f833e

@ -103,4 +103,10 @@ Helpers
Aggregation
* Aggregation functions should implement `.step()` and `.result()`
* Aggregation functions should implement `.step()` and `.result()`
Differentiation
* function calls use parentheses, names start with lowercase letters or "_"
* aggregation calls are the same as function calls except that square brackets are used instead
* query calls are the same as function calls except that query names start with upper case or "#"

@ -1,6 +1,8 @@
mod parser;
use crate::data::expr::StaticExpr;
use crate::data::tuple_set::TupleSet;
use crate::data::value::{StaticValue, Value};
use crate::data::value::{Value};
pub(crate) trait Algebra {
fn get_iterator(&self) -> TupleSource;

@ -0,0 +1,74 @@
use std::result;
use crate::parser::{Pair, Pairs};
#[derive(thiserror::Error, Debug)]
pub enum AlgebraParseError {
#[error("{0} cannot be chained")]
Unchainable(String)
}
type Result<T> = result::Result<T, AlgebraParseError>;
trait RelationalAlgebra {
fn name(&self) -> &str;
}
const NAME_VALUES: &str = "Values";
struct RaFromValues;
impl RaFromValues {
fn build(prev: Option<()>, args: Pairs) -> Result<Self> {
if prev!= None {
return Err(AlgebraParseError::Unchainable(NAME_VALUES.to_string()))
}
dbg!(args);
todo!()
}
}
impl RelationalAlgebra for RaFromValues {
fn name(&self) -> &str {
NAME_VALUES
}
}
const NAME_INSERT: &str = "Insert";
fn build_ra_expr(pair: Pair) {
let built: Option<()> = None;
for pair in pair.into_inner() {
let mut pairs = pair.into_inner();
match pairs.next().unwrap().as_str() {
NAME_INSERT => todo!(),
NAME_VALUES => {
let _res = RaFromValues::build(built, pairs);
},
_ => unimplemented!()
}
}
todo!()
}
#[cfg(test)]
mod tests {
use crate::parser::{CozoParser, Rule};
use pest::Parser;
use crate::algebra::parser::build_ra_expr;
#[test]
fn parse_ra() {
let s = r#"
Values([{x: 1}])
.Insert(f:Friend)
"#;
build_ra_expr(CozoParser::parse(Rule::ra_expr_all, s).unwrap().into_iter().next().unwrap());
let s = r#"
From(f:Person-[:HasJob]->j:Job,
f.id == 101, j.id > 10)
.Select(f: {*id: f.id})
"#;
build_ra_expr(CozoParser::parse(Rule::ra_expr_all, s).unwrap().into_iter().next().unwrap());
}
}

@ -1,6 +1,6 @@
pub(crate) mod eval;
pub(crate) mod expr;
pub(crate) mod expr_parser;
pub(crate) mod parser;
pub(crate) mod key_order;
pub(crate) mod op;
pub(crate) mod tuple;

@ -1,5 +1,5 @@
use crate::data::expr::{Expr};
use crate::data::expr_parser::ExprParseError;
use crate::data::parser::ExprParseError;
use crate::data::op::*;
use crate::data::tuple_set::{ColId, TableId, TupleSetIdx};
use crate::data::value::{StaticValue, Value};
@ -163,9 +163,9 @@ impl<'a> Expr<'a> {
}
match op.name() {
// special cases
n if n == OpAnd.name() => partial_eval_and(ctx, args)?,
n if n == OpOr.name() => partial_eval_or(ctx, args)?,
n if n == OpCoalesce.name() => partial_eval_coalesce(ctx, args)?,
NAME_OP_AND => partial_eval_and(ctx, args)?,
NAME_OP_OR => partial_eval_or(ctx, args)?,
NAME_OP_COALESCE => partial_eval_coalesce(ctx, args)?,
_ => {
let mut has_unevaluated = false;
let non_null_args_fn = op.non_null_args();
@ -242,32 +242,24 @@ impl<'a> Expr<'a> {
Expr::Dict(d.into_iter().map(|(k, v)| (k, v.optimize_ops())).collect())
}
Expr::Apply(op, args) => match op.name() {
name if name == OpAdd.name() => Expr::Add(extract_optimized_bin_args(args).into()),
name if name == OpSub.name() => Expr::Sub(extract_optimized_bin_args(args).into()),
name if name == OpMul.name() => Expr::Mul(extract_optimized_bin_args(args).into()),
name if name == OpDiv.name() => Expr::Div(extract_optimized_bin_args(args).into()),
name if name == OpPow.name() => Expr::Pow(extract_optimized_bin_args(args).into()),
name if name == OpMod.name() => Expr::Mod(extract_optimized_bin_args(args).into()),
name if name == OpStrCat.name() => {
Expr::StrCat(extract_optimized_bin_args(args).into())
}
name if name == OpEq.name() => Expr::Eq(extract_optimized_bin_args(args).into()),
name if name == OpNe.name() => Expr::Ne(extract_optimized_bin_args(args).into()),
name if name == OpGt.name() => Expr::Gt(extract_optimized_bin_args(args).into()),
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 == OpMinus.name() => {
Expr::Minus(extract_optimized_u_args(args).into())
}
name if name == OpIsNull.name() => {
Expr::IsNull(extract_optimized_u_args(args).into())
}
name if name == OpNotNull.name() => {
Expr::NotNull(extract_optimized_u_args(args).into())
}
name if name == OpCoalesce.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 {
@ -275,7 +267,7 @@ impl<'a> Expr<'a> {
}
arg
}
name if name == OpOr.name() => {
NAME_OP_OR => {
let mut args = args.into_iter();
let mut arg = args.next().unwrap().optimize_ops();
for nxt in args {
@ -283,7 +275,7 @@ impl<'a> Expr<'a> {
}
arg
}
name if name == OpAnd.name() => {
NAME_OP_AND => {
let mut args = args.into_iter();
let mut arg = args.next().unwrap().optimize_ops();
for nxt in args {
@ -370,7 +362,7 @@ impl<'a> Expr<'a> {
for v in args {
let v = v.row_eval(ctx)?;
if op_non_null_args && v == Value::Null {
return Ok(Value::Null)
return Ok(Value::Null);
} else {
eval_args.push(v);
}
@ -554,7 +546,7 @@ impl<'a> Expr<'a> {
#[cfg(test)]
mod tests {
use super::*;
use crate::data::expr_parser::tests::str2expr;
use crate::data::parser::tests::str2expr;
#[test]
fn evaluations() -> Result<()> {

@ -6,8 +6,7 @@ mod control;
mod text;
use crate::data::eval::EvalError;
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use crate::data::value::{Value};
use std::result;
pub(crate) use arithmetic::*;

@ -1,6 +1,6 @@
use crate::data::eval::EvalError;
use crate::data::op::{extract_two_args, Op};
use crate::data::value::{StaticValue, Value};
use crate::data::value::{Value};
use std::result;
type Result<T> = result::Result<T, EvalError>;
@ -25,6 +25,8 @@ impl OpAdd {
}
}
pub(crate) const NAME_OP_ADD: &str = "+";
impl Op for OpAdd {
fn arity(&self) -> Option<usize> {
Some(2)
@ -35,7 +37,7 @@ impl Op for OpAdd {
}
fn name(&self) -> &str {
"+"
NAME_OP_ADD
}
fn non_null_args(&self) -> bool {
@ -67,6 +69,8 @@ impl OpSub {
}
}
pub(crate) const NAME_OP_SUB: &str = "-";
impl Op for OpSub {
fn arity(&self) -> Option<usize> {
Some(2)
@ -77,7 +81,7 @@ impl Op for OpSub {
}
fn name(&self) -> &str {
"-"
NAME_OP_SUB
}
fn non_null_args(&self) -> bool {
@ -109,6 +113,8 @@ impl OpMul {
}
}
pub(crate) const NAME_OP_MUL: &str = "*";
impl Op for OpMul {
fn arity(&self) -> Option<usize> {
Some(2)
@ -119,7 +125,7 @@ impl Op for OpMul {
}
fn name(&self) -> &str {
"*"
NAME_OP_MUL
}
fn non_null_args(&self) -> bool {
@ -152,6 +158,8 @@ impl OpDiv {
}
}
pub(crate) const NAME_OP_DIV: &str = "/";
impl Op for OpDiv {
fn arity(&self) -> Option<usize> {
Some(2)
@ -162,7 +170,7 @@ impl Op for OpDiv {
}
fn name(&self) -> &str {
"/"
NAME_OP_DIV
}
fn non_null_args(&self) -> bool {
@ -192,6 +200,8 @@ impl OpMod {
}
}
pub(crate) const NAME_OP_MOD: &str = "%";
impl Op for OpMod {
fn arity(&self) -> Option<usize> {
Some(2)
@ -202,7 +212,7 @@ impl Op for OpMod {
}
fn name(&self) -> &str {
"%"
NAME_OP_MOD
}
fn non_null_args(&self) -> bool {
@ -235,6 +245,8 @@ impl OpPow {
}
}
pub(crate) const NAME_OP_POW: &str = "**";
impl Op for OpPow {
fn arity(&self) -> Option<usize> {
Some(2)
@ -245,7 +257,7 @@ impl Op for OpPow {
}
fn name(&self) -> &str {
"**"
NAME_OP_POW
}
fn non_null_args(&self) -> bool {
@ -272,6 +284,8 @@ impl OpMinus {
}
}
pub(crate) const NAME_OP_MINUS: &str = "--";
impl Op for OpMinus {
fn arity(&self) -> Option<usize> {
Some(1)
@ -279,12 +293,12 @@ impl Op for OpMinus {
fn has_side_effect(&self) -> bool {
false
}
fn non_null_args(&self) -> bool {
true
}
fn name(&self) -> &str {
"--"
}
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())
}

@ -1,8 +1,7 @@
use crate::data::eval::{EvalError, ExprEvalContext, RowEvalContext};
use crate::data::expr::Expr;
use crate::data::op::Op;
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use crate::data::value::{Value};
use std::result;
use std::sync::Arc;
@ -16,6 +15,8 @@ impl OpIsNull {
}
}
pub(crate) const NAME_OP_IS_NULL: &str = "is_null";
impl Op for OpIsNull {
fn arity(&self) -> Option<usize> {
Some(1)
@ -24,7 +25,7 @@ impl Op for OpIsNull {
false
}
fn name(&self) -> &str {
"is_null"
NAME_OP_IS_NULL
}
fn non_null_args(&self) -> bool {
false
@ -42,6 +43,8 @@ impl OpNotNull {
}
}
pub(crate) const NAME_OP_NOT_NULL: &str = "not_null";
impl Op for OpNotNull {
fn arity(&self) -> Option<usize> {
Some(1)
@ -50,7 +53,7 @@ impl Op for OpNotNull {
false
}
fn name(&self) -> &str {
"not_null"
NAME_OP_NOT_NULL
}
fn non_null_args(&self) -> bool {
false
@ -63,6 +66,8 @@ impl Op for OpNotNull {
pub(crate) struct OpOr;
pub(crate) const NAME_OP_OR: &str = "||";
impl Op for OpOr {
fn arity(&self) -> Option<usize> {
None
@ -73,7 +78,7 @@ impl Op for OpOr {
}
fn name(&self) -> &str {
"||"
NAME_OP_OR
}
fn non_null_args(&self) -> bool {
false
@ -165,6 +170,8 @@ pub(crate) fn row_eval_or<'a, T: RowEvalContext + 'a>(
pub(crate) struct OpAnd;
pub(crate) const NAME_OP_AND: &str = "&&";
impl Op for OpAnd {
fn arity(&self) -> Option<usize> {
None
@ -175,7 +182,7 @@ impl Op for OpAnd {
}
fn name(&self) -> &str {
"&&"
NAME_OP_AND
}
fn non_null_args(&self) -> bool {
false
@ -279,6 +286,8 @@ impl OpNot {
}
}
pub(crate) const NAME_OP_NOT: &str = "!";
impl Op for OpNot {
fn arity(&self) -> Option<usize> {
Some(1)
@ -290,7 +299,7 @@ impl Op for OpNot {
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())

@ -1,8 +1,6 @@
use crate::data::eval::{EvalError, ExprEvalContext};
use crate::data::expr::Expr;
use crate::data::eval::{EvalError};
use crate::data::op::Op;
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use crate::data::value::{Value};
use std::collections::BTreeMap;
use std::result;
@ -10,6 +8,8 @@ type Result<T> = result::Result<T, EvalError>;
pub(crate) struct OpConcat;
pub(crate) const NAME_OP_CONCAT: &str = "concat";
impl Op for OpConcat {
fn arity(&self) -> Option<usize> {
None
@ -20,7 +20,7 @@ impl Op for OpConcat {
}
fn name(&self) -> &str {
"concat"
NAME_OP_CONCAT
}
fn non_null_args(&self) -> bool {
false
@ -45,6 +45,8 @@ impl Op for OpConcat {
pub(crate) struct OpMerge;
pub(crate) const NAME_OP_MERGE: &str = "merge";
impl Op for OpMerge {
fn arity(&self) -> Option<usize> {
None
@ -55,7 +57,7 @@ impl Op for OpMerge {
}
fn name(&self) -> &str {
"merge"
NAME_OP_MERGE
}
fn non_null_args(&self) -> bool {
false

@ -13,6 +13,8 @@ impl OpEq {
}
}
pub(crate) const NAME_OP_EQ: &str = "==";
impl Op for OpEq {
fn arity(&self) -> Option<usize> {
Some(2)
@ -23,7 +25,7 @@ impl Op for OpEq {
}
fn name(&self) -> &str {
"=="
NAME_OP_EQ
}
fn non_null_args(&self) -> bool {
@ -44,6 +46,8 @@ impl OpNe {
}
}
pub(crate) const NAME_OP_NE: &str = "!=";
impl Op for OpNe {
fn arity(&self) -> Option<usize> {
Some(2)
@ -54,7 +58,7 @@ impl Op for OpNe {
}
fn name(&self) -> &str {
"!="
NAME_OP_NE
}
fn non_null_args(&self) -> bool {
@ -88,6 +92,8 @@ impl OpGt {
}
}
pub(crate) const NAME_OP_GT: &str = ">";
impl Op for OpGt {
fn arity(&self) -> Option<usize> {
Some(2)
@ -98,7 +104,7 @@ impl Op for OpGt {
}
fn name(&self) -> &str {
">"
NAME_OP_GT
}
fn non_null_args(&self) -> bool {
@ -131,6 +137,8 @@ impl OpGe {
}
}
pub(crate) const NAME_OP_GE: &str = ">=";
impl Op for OpGe {
fn arity(&self) -> Option<usize> {
Some(2)
@ -141,7 +149,7 @@ impl Op for OpGe {
}
fn name(&self) -> &str {
">="
NAME_OP_GE
}
fn non_null_args(&self) -> bool {
@ -174,6 +182,8 @@ impl OpLt {
}
}
pub(crate) const NAME_OP_LT: &str = "<";
impl Op for OpLt {
fn arity(&self) -> Option<usize> {
Some(2)
@ -184,7 +194,7 @@ impl Op for OpLt {
}
fn name(&self) -> &str {
"<"
NAME_OP_LT
}
fn non_null_args(&self) -> bool {
@ -217,6 +227,8 @@ impl OpLe {
}
}
pub(crate) const NAME_OP_LE: &str = "<=";
impl Op for OpLe {
fn arity(&self) -> Option<usize> {
Some(2)
@ -227,7 +239,7 @@ impl Op for OpLe {
}
fn name(&self) -> &str {
"<="
NAME_OP_LE
}
fn non_null_args(&self) -> bool {

@ -11,6 +11,8 @@ pub(crate) struct OpCond;
pub(crate) struct OpCoalesce;
pub(crate) const NAME_OP_COALESCE: &str = "~~";
impl Op for OpCoalesce {
fn arity(&self) -> Option<usize> {
None
@ -21,7 +23,7 @@ impl Op for OpCoalesce {
}
fn name(&self) -> &str {
"~~"
NAME_OP_COALESCE
}
fn non_null_args(&self) -> bool {
false
@ -48,7 +50,7 @@ pub(crate) fn row_eval_coalesce<'a, T: RowEvalContext + 'a>(
right.row_eval(ctx)
}
const IF_NAME: &str = "if";
pub(crate) const IF_NAME: &str = "if";
pub(crate) fn partial_eval_coalesce<'a, T: ExprEvalContext + 'a>(
ctx: &'a T,

@ -23,6 +23,8 @@ impl OpStrCat {
}
}
pub(crate) const NAME_OP_STR_CAT: &str = "++";
impl Op for OpStrCat {
fn arity(&self) -> Option<usize> {
Some(2)
@ -33,7 +35,7 @@ impl Op for OpStrCat {
}
fn name(&self) -> &str {
"++"
NAME_OP_STR_CAT
}
fn non_null_args(&self) -> bool {

@ -1,5 +1,5 @@
use crate::data::expr::Expr;
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, UnresolvedOp};
use crate::data::op::*;
use crate::data::value::Value;
use crate::parser::number::parse_int;
use crate::parser::text_identifier::parse_string;
@ -172,7 +172,6 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
Rule::if_expr => return build_if_expr(p),
Rule::cond_expr => return build_cond_expr(p),
Rule::switch_expr => return build_switch_expr(p),
Rule::call_expr => return build_call_expr(p),
r => unreachable!("Encountered unknown op {:?}", r),
};
let term = build_expr_primary(inner.next().unwrap())?;
@ -280,6 +279,7 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
}
Rule::param => Ok(Expr::Variable(pair.as_str().into())),
Rule::ident => Ok(Expr::Variable(pair.as_str().into())),
Rule::call_expr => build_call_expr(pair),
_ => {
println!("Unhandled rule {:?}", pair.as_rule());
unimplemented!()
@ -289,8 +289,10 @@ fn build_expr_primary(pair: Pair) -> Result<Expr> {
fn get_method(name: &str) -> Arc<dyn Op + Send + Sync> {
match name {
n if n == OpIsNull.name() => Arc::new(OpIsNull),
n if n == OpNotNull.name() => Arc::new(OpNotNull),
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()))
}
}
@ -331,7 +333,7 @@ pub(crate) mod tests {
use pest::Parser;
pub(crate) fn str2expr(s: &str) -> Result<Expr> {
let pair = CozoParser::parse(Rule::expr, s)
let pair = CozoParser::parse(Rule::expr_all, s)
.unwrap()
.next()
.unwrap();

@ -11,6 +11,8 @@ COMMENT = _{(BLOCK_COMMENT | LINE_COMMENT)}
// identifiers
ident = @{("_" | XID_START) ~ ("_" | XID_CONTINUE)*}
fn_ident = @{("_" | LOWERCASE_LETTER) ~ ("_" | XID_CONTINUE)*}
query_ident = @{("#" | UPPERCASE_LETTER) ~ ("_" | XID_CONTINUE)*}
param = @{"$" ~ ("_" | XID_CONTINUE)+}
@ -83,6 +85,7 @@ literal = _{ null | boolean | number | string}
// Expressions
comma_sep_expr = { expr ~ ("," ~ expr)* }
expr_all = _{SOI ~ expr ~ EOI}
expr = {unary ~ (operation ~ unary) *}
operation = _{ (op_and | op_or | op_pow | op_str_cat | op_add | op_sub | op_mul | op_div | op_mod | op_coalesce |
op_ge | op_le | op_gt | op_lt | op_eq | op_ne)}
@ -103,14 +106,16 @@ op_ge = { ">=" }
op_le = { "<=" }
op_pow = { "^" }
unary = { cond_expr | switch_expr | if_expr | call_expr | (unary_op ~ unary) | term }
unary = { cond_expr | switch_expr | if_expr | (unary_op ~ unary) | term }
unary_op = _{ minus | negate }
minus = { "-" }
negate = { "!" }
call_expr = { ident ~ "(" ~ (expr ~ ",")* ~ expr? ~ ")" }
term = { (grouping | literal | ident | param | list | dict) ~ (call | accessor | index_accessor)* }
call = {"." ~ ident ~ "(" ~ (expr ~ ",")* ~ expr? ~ ")"}
call_expr = { fn_ident ~ "(" ~ (expr ~ ",")* ~ expr? ~ ")" }
aggr_expr = { fn_ident ~ "[" ~ (expr ~ ",")* ~ expr? ~ "]" }
term = { (grouping | call_expr | aggr_expr | literal | ident | param | list | dict) ~ (call | aggr | accessor | index_accessor)* }
call = {"." ~ fn_ident ~ "(" ~ (expr ~ ",")* ~ expr? ~ ")"}
aggr = {"." ~ fn_ident ~ "[" ~ (expr ~ ",")* ~ expr? ~ "]"}
accessor = {"." ~ ident}
index_accessor = {"[" ~ int ~ "]"}
grouping = { "(" ~ expr ~ ")" }
@ -134,11 +139,11 @@ dict_entry = _{ spreading | dict_pair | scoped_accessor }
scoped_accessor = { ident }
dict_pair = {(ident | string) ~ ":" ~ expr}
select_dict = { "{" ~ (select_dict_entry ~ ",")* ~ select_dict_entry? ~ "}"}
select_dict_entry = _{ grouped_pair | spreading | dict_pair | scoped_accessor }
grouped_pair = { "*" ~ (ident | string) ~ ":" ~ expr}
keyed_dict = { "{" ~ (keyed_dict_entry ~ ",")* ~ keyed_dict_entry? ~ "}"}
keyed_dict_entry = _{ keyed_pair | spreading | dict_pair | scoped_accessor }
keyed_pair = { "*" ~ (ident | string) ~ ":" ~ expr}
scoped_dict = { ident ~ select_dict }
scoped_dict = { ident ~ ":" ~ keyed_dict }
name_in_def = {(ident | string)}
col_entry = { col_name ~ ":" ~ typing ~ ("=" ~ expr)? }
@ -215,3 +220,21 @@ statement = _{ global_def | local_def }
// Relational algebra
// ra = { (ra_source | ra_fn_call) ~ ra_method_call* }
chain = { (node_part ~ (edge_part ~ node_part)* ~ edge_part?) | (edge_part ~ (node_part ~ edge_part)* ~ node_part?) }
node_part = {ident? ~ ":" ~ name_in_def}
edge_part = {edge_src_marker ~ node_part ~ edge_dst_marker}
edge_src_marker = {outer_marker? ~ bwd_marker? ~ "-["}
edge_dst_marker = {"]-" ~ fwd_marker? ~ outer_marker?}
outer_marker = {"?"}
bwd_marker = {"<"}
fwd_marker = {">"}
sort_arg = {expr ~ "=>" ~ sort_dir}
sort_dir = _{asc_dir | desc_dir}
asc_dir = {"asc"}
desc_dir = {"desc"}
ra_arg = { ra_expr | chain | scoped_dict | keyed_dict | sort_arg | expr }
ra_call_expr = { query_ident ~ "(" ~ (ra_arg ~ ",")* ~ ra_arg? ~ ")" }
ra_call = {"." ~ query_ident ~ "(" ~ (ra_arg ~ ",")* ~ ra_arg? ~ ")"}
ra_expr = { ra_call_expr ~ ra_call* }
ra_expr_all = _{SOI ~ ra_expr ~ EOI}
Loading…
Cancel
Save