diff --git a/query-parser/src/parse.rs b/query-parser/src/parse.rs index 1a5870ef..69e2c2d1 100644 --- a/query-parser/src/parse.rs +++ b/query-parser/src/parse.rs @@ -43,6 +43,8 @@ use self::mentat_query::{ FromValue, OrJoin, OrWhereClause, + NotJoin, + WhereNotClause, Pattern, PatternNonValuePlace, PatternValuePlace, @@ -163,6 +165,10 @@ def_parser!(Where, or_join, edn::ValueAndSpan, { }) }); +def_matches_plain_symbol!(Where, or_join, "not"); + +def_matches_plain_symbol!(Where, or_join, "not-join"); + def_parser!(Where, rule_vars, Vec, { seq() .of_exactly(many1(Query::variable())) @@ -210,6 +216,53 @@ def_parser!(Where, or_join_clause, WhereClause, { })) }); +def_value_parser_fn!(Where, not_pattern_clause, WhereNotClause, input, { + Where::clause().map(|clause| WhereNotClause::Clause(clause)).parse_stream(input) +}); + +def_value_parser_fn!(Where, where_not_clause, WhereNotClause, input, { + choice([Where::not_pattern_clause()]).parse_stream(input) +}); + +def_value_parser_fn!(Where, not_clause, WhereClause, input, { + satisfy_map(|x: edn::Value| { + seq(x).and_then(|items| { + let mut p = Where::not() + .with(many1(Where::where_not_clause())) + .skip(eof()) + .map(|clauses| { + WhereClause::NotJoin( + NotJoin { + unify_vars: UnifyVars::Implicit, + clauses: clauses, + }) + }); + let r: ParseResult = p.parse_lazy(&items[..]).into(); + Query::to_parsed_value(r) + }) + }).parse_stream(input) +}); + +def_value_parser_fn!(Where, not_join_clause, WhereClause, input, { + satisfy_map(|x: edn::Value| { + seq(x).and_then(|items| { + let mut p = Where::not_join() + .with(Where::rule_vars()) + .and(many1(Where::where_not_clause())) + .skip(eof()) + .map(|(vars, clauses)| { + WhereClause::NotJoin( + NotJoin { + unify_vars: UnifyVars::Explicit(vars), + clauses: clauses, + }) + }); + let r: ParseResult = p.parse_lazy(&items[..]).into(); + Query::to_parsed_value(r) + }) + }).parse_stream(input) +}); + /// A vector containing just a parenthesized filter expression. def_parser!(Where, pred, WhereClause, { // Accept either a nested list or a nested vector here: @@ -293,6 +346,8 @@ def_parser!(Where, clause, WhereClause, { // We don't yet handle source vars. try(Where::or_join_clause()), try(Where::or_clause()), + try(Where::not_join_clause()), + try(Where::not_clause()), try(Where::pred()), try(Where::where_fn()), @@ -641,6 +696,59 @@ mod test { })); } + #[test] + fn test_not() { + let oj = edn::PlainSymbol::new("not"); + let e = edn::PlainSymbol::new("?e"); + let a = edn::PlainSymbol::new("?a"); + let v = edn::PlainSymbol::new("?v"); + let input = [edn::Value::List( + vec![edn::Value::PlainSymbol(oj), + edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()), + edn::Value::PlainSymbol(a.clone()), + edn::Value::PlainSymbol(v.clone())])].into_iter().collect())]; + assert_parses_to!(Where::not_clause, input, + WhereClause::NotJoin( + NotJoin { + unify_vars: UnifyVars::Implicit, + clauses: vec![WhereNotClause::Clause( + WhereClause::Pattern(Pattern { + source: None, + entity: PatternNonValuePlace::Variable(variable(e)), + attribute: PatternNonValuePlace::Variable(variable(a)), + value: PatternValuePlace::Variable(variable(v)), + tx: PatternNonValuePlace::Placeholder, + }))], + })); + } + + #[test] + fn test_not_join() { + let oj = edn::PlainSymbol::new("not-join"); + let e = edn::PlainSymbol::new("?e"); + let a = edn::PlainSymbol::new("?a"); + let v = edn::PlainSymbol::new("?v"); + let input = [edn::Value::List( + vec![edn::Value::PlainSymbol(oj), + edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone())]), + edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()), + edn::Value::PlainSymbol(a.clone()), + edn::Value::PlainSymbol(v.clone())])].into_iter().collect())]; + assert_parses_to!(Where::not_join_clause, input, + WhereClause::NotJoin( + NotJoin { + unify_vars: UnifyVars::Explicit(vec![variable(e.clone())]), + clauses: vec![WhereNotClause::Clause( + WhereClause::Pattern(Pattern { + source: None, + entity: PatternNonValuePlace::Variable(variable(e)), + attribute: PatternNonValuePlace::Variable(variable(a)), + value: PatternValuePlace::Variable(variable(v)), + tx: PatternNonValuePlace::Placeholder, + }))], + })); + } + #[test] fn test_find_sp_variable() { let sym = edn::PlainSymbol::new("?x"); diff --git a/query/src/lib.rs b/query/src/lib.rs index 18edfc3d..de9c2e03 100644 --- a/query/src/lib.rs +++ b/query/src/lib.rs @@ -189,18 +189,6 @@ pub enum FnArg { impl FromValue for FnArg { fn from_value(v: edn::ValueAndSpan) -> Option { -<<<<<<< HEAD - // TODO: support SrcVars. - Variable::from_value(v.clone()) // TODO: don't clone! - .and_then(|v| Some(FnArg::Variable(v))) - .or_else(|| { - println!("from_value {}", v.inner); - match v.inner { - edn::SpannedValue::Integer(i) => Some(FnArg::EntidOrInteger(i)), - edn::SpannedValue::Float(f) => Some(FnArg::Constant(NonIntegerConstant::Float(f))), - _ => unimplemented!(), - }}) -======= use edn::SpannedValue::*; match v.inner { Integer(x) => @@ -229,7 +217,6 @@ impl FromValue for FnArg { Set(_) | Map(_) => None, } ->>>>>>> 71d3aa29ed3b383f030e9b3d13eeef5a12820be1 } } @@ -631,11 +618,30 @@ pub struct OrJoin { pub clauses: Vec, } +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum WhereNotClause { + Clause(WhereClause), +} + +impl WhereNotClause { + pub fn is_pattern_or_patterns(&self) -> bool { + match self { + &WhereNotClause::Clause(WhereClause::Pattern(_)) => true, + _ => false, + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct NotJoin { + pub unify_vars: UnifyVars, + pub clauses: Vec, +} + #[allow(dead_code)] #[derive(Clone, Debug, Eq, PartialEq)] pub enum WhereClause { - Not, - NotJoin, + NotJoin(NotJoin), OrJoin(OrJoin), Pred(Predicate), WhereFn(WhereFn), @@ -689,9 +695,14 @@ impl ContainsVariables for WhereClause { &OrJoin(ref o) => o.accumulate_mentioned_variables(acc), &Pred(ref p) => p.accumulate_mentioned_variables(acc), &Pattern(ref p) => p.accumulate_mentioned_variables(acc), +<<<<<<< HEAD &Not => (), &NotJoin => (), &WhereFn(_) => (), +======= + &NotJoin(ref n) => n.accumulate_mentioned_variables(acc), + &WhereFn => (), +>>>>>>> Part 1 - Parse `not` and `not-join` &RuleExpr => (), } } @@ -715,6 +726,23 @@ impl ContainsVariables for OrJoin { } } +impl ContainsVariables for NotJoin { + fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet) { + for clause in &self.clauses { + clause.accumulate_mentioned_variables(acc); + } + } +} + +impl ContainsVariables for WhereNotClause { + fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet) { + use WhereNotClause::*; + match self { + &Clause(ref clause) => clause.accumulate_mentioned_variables(acc), + } + } +} + impl ContainsVariables for Predicate { fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet) { for arg in &self.args {