Pre: make rule_vars return unique vars.

This commit is contained in:
Richard Newman 2017-06-02 15:36:12 -07:00 committed by Richard Newman
parent d30ad428e8
commit c6e933c396
8 changed files with 37 additions and 25 deletions

View file

@ -32,7 +32,7 @@ impl ConjoiningClauses {
pub fn apply_not_join(&mut self, schema: &Schema, not_join: NotJoin) -> Result<()> { pub fn apply_not_join(&mut self, schema: &Schema, not_join: NotJoin) -> Result<()> {
let unified = match not_join.unify_vars { let unified = match not_join.unify_vars {
UnifyVars::Implicit => not_join.collect_mentioned_variables(), UnifyVars::Implicit => not_join.collect_mentioned_variables(),
UnifyVars::Explicit(vs) => vs.into_iter().collect(), UnifyVars::Explicit(vs) => vs,
}; };
let mut template = self.use_as_template(&unified); let mut template = self.use_as_template(&unified);

View file

@ -552,7 +552,7 @@ impl ConjoiningClauses {
let (join_clauses, unify_vars, mentioned_vars) = or_join.dismember(); let (join_clauses, unify_vars, mentioned_vars) = or_join.dismember();
let projected = match unify_vars { let projected = match unify_vars {
UnifyVars::Implicit => mentioned_vars.into_iter().collect(), UnifyVars::Implicit => mentioned_vars.into_iter().collect(),
UnifyVars::Explicit(vs) => vs.into_iter().collect(), UnifyVars::Explicit(vs) => vs,
}; };
let template = self.use_as_template(&projected); let template = self.use_as_template(&projected);

View file

@ -13,6 +13,10 @@ extern crate enum_set;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
#[cfg(test)]
#[macro_use]
extern crate maplit;
extern crate mentat_core; extern crate mentat_core;
extern crate mentat_query; extern crate mentat_query;

View file

@ -212,7 +212,7 @@ mod tests {
(and [?artist :artist/type ?type] (and [?artist :artist/type ?type]
[?type :artist/role :artist.role/parody]))]"#; [?type :artist/role :artist.role/parody]))]"#;
let parsed = parse_find_string(query).expect("expected successful parse"); let parsed = parse_find_string(query).expect("expected successful parse");
let clauses = valid_or_join(parsed, UnifyVars::Explicit(vec![Variable::from_valid_name("?artist")])); let clauses = valid_or_join(parsed, UnifyVars::Explicit(btreeset!{Variable::from_valid_name("?artist")}));
// Let's do some detailed parse checks. // Let's do some detailed parse checks.
let mut arms = clauses.into_iter(); let mut arms = clauses.into_iter();
@ -322,7 +322,7 @@ mod tests {
[?release :release/artists ?artist] [?release :release/artists ?artist]
[?release :release/year 1970])]"#; [?release :release/year 1970])]"#;
let parsed = parse_find_string(query).expect("expected successful parse"); let parsed = parse_find_string(query).expect("expected successful parse");
let clauses = valid_not_join(parsed, UnifyVars::Explicit(vec![Variable::from_valid_name("?artist")])); let clauses = valid_not_join(parsed, UnifyVars::Explicit(btreeset!{Variable::from_valid_name("?artist")}));
let release = PatternNonValuePlace::Variable(Variable::from_valid_name("?release")); let release = PatternNonValuePlace::Variable(Variable::from_valid_name("?release"));
let artist = PatternValuePlace::Variable(Variable::from_valid_name("?artist")); let artist = PatternValuePlace::Variable(Variable::from_valid_name("?artist"));

View file

@ -10,6 +10,9 @@
#![allow(unused_imports)] #![allow(unused_imports)]
#[macro_use]
extern crate maplit;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;

View file

@ -197,9 +197,9 @@ def_matches_plain_symbol!(Where, not, "not");
def_matches_plain_symbol!(Where, not_join, "not-join"); def_matches_plain_symbol!(Where, not_join, "not-join");
def_parser!(Where, rule_vars, Vec<Variable>, { def_parser!(Where, rule_vars, BTreeSet<Variable>, {
seq() seq()
.of_exactly(many1(Query::variable())) .of_exactly(many1(Query::variable()).and_then(unique_vars))
}); });
def_parser!(Where, or_pattern_clause, OrWhereClause, { def_parser!(Where, or_pattern_clause, OrWhereClause, {
@ -392,8 +392,7 @@ def_parser!(Find, spec, FindSpec, {
&mut try(Find::find_rel())]) &mut try(Find::find_rel())])
}); });
def_parser!(Find, vars, BTreeSet<Variable>, { fn unique_vars<T, E>(vars: Vec<Variable>) -> std::result::Result<BTreeSet<Variable>, combine::primitives::Error<T, E>> {
many(Query::variable()).and_then(|vars: Vec<Variable>| {
let given = vars.len(); let given = vars.len();
let set: BTreeSet<Variable> = vars.into_iter().collect(); let set: BTreeSet<Variable> = vars.into_iter().collect();
if given != set.len() { if given != set.len() {
@ -403,7 +402,10 @@ def_parser!(Find, vars, BTreeSet<Variable>, {
} else { } else {
Ok(set) Ok(set)
} }
}) }
def_parser!(Find, vars, BTreeSet<Variable>, {
many(Query::variable()).and_then(unique_vars)
}); });
/// This is awkward, but will do for now. We use `keyword_map()` to optionally accept vector find /// This is awkward, but will do for now. We use `keyword_map()` to optionally accept vector find
@ -573,7 +575,7 @@ mod test {
let e = edn::PlainSymbol::new("?e"); let e = edn::PlainSymbol::new("?e");
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone())]); let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone())]);
assert_parses_to!(Where::rule_vars, input, assert_parses_to!(Where::rule_vars, input,
vec![variable(e.clone())]); btreeset!{variable(e.clone())});
} }
#[test] #[test]
@ -583,7 +585,7 @@ mod test {
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()), let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()),
edn::Value::PlainSymbol(f.clone()),]); edn::Value::PlainSymbol(f.clone()),]);
assert_parses_to!(|| vector().of_exactly(Find::vars()), input, assert_parses_to!(|| vector().of_exactly(Find::vars()), input,
vec![variable(e.clone()), variable(f.clone())].into_iter().collect()); btreeset!{variable(e.clone()), variable(f.clone())});
let g = edn::PlainSymbol::new("?g"); let g = edn::PlainSymbol::new("?g");
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(g.clone()), let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(g.clone()),
@ -642,7 +644,7 @@ mod test {
edn::Value::PlainSymbol(v.clone())])].into_iter().collect()); edn::Value::PlainSymbol(v.clone())])].into_iter().collect());
assert_parses_to!(Where::or_join_clause, input, assert_parses_to!(Where::or_join_clause, input,
WhereClause::OrJoin( WhereClause::OrJoin(
OrJoin::new(UnifyVars::Explicit(vec![variable(e.clone())]), OrJoin::new(UnifyVars::Explicit(btreeset!{variable(e.clone())}),
vec![OrWhereClause::Clause( vec![OrWhereClause::Clause(
WhereClause::Pattern(Pattern { WhereClause::Pattern(Pattern {
source: None, source: None,
@ -685,7 +687,7 @@ mod test {
"(not-join [?e] [?e ?a ?v])", "(not-join [?e] [?e ?a ?v])",
WhereClause::NotJoin( WhereClause::NotJoin(
NotJoin { NotJoin {
unify_vars: UnifyVars::Explicit(vec![variable(e.clone())]), unify_vars: UnifyVars::Explicit(btreeset!{variable(e.clone())}),
clauses: vec![WhereClause::Pattern(Pattern { clauses: vec![WhereClause::Pattern(Pattern {
source: None, source: None,
entity: PatternNonValuePlace::Variable(variable(e)), entity: PatternNonValuePlace::Variable(variable(e)),

View file

@ -8,6 +8,9 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#[macro_use]
extern crate maplit;
extern crate edn; extern crate edn;
extern crate mentat_core; extern crate mentat_core;
extern crate mentat_query; extern crate mentat_query;
@ -111,7 +114,7 @@ fn can_parse_unit_or_join() {
assert_eq!(p.where_clauses, assert_eq!(p.where_clauses,
vec![ vec![
WhereClause::OrJoin(OrJoin::new( WhereClause::OrJoin(OrJoin::new(
UnifyVars::Explicit(vec![Variable::from_valid_name("?x")]), UnifyVars::Explicit(btreeset!{Variable::from_valid_name("?x")}),
vec![ vec![
OrWhereClause::Clause( OrWhereClause::Clause(
WhereClause::Pattern(Pattern { WhereClause::Pattern(Pattern {
@ -136,7 +139,7 @@ fn can_parse_simple_or_join() {
assert_eq!(p.where_clauses, assert_eq!(p.where_clauses,
vec![ vec![
WhereClause::OrJoin(OrJoin::new( WhereClause::OrJoin(OrJoin::new(
UnifyVars::Explicit(vec![Variable::from_valid_name("?x")]), UnifyVars::Explicit(btreeset!{Variable::from_valid_name("?x")}),
vec![ vec![
OrWhereClause::Clause( OrWhereClause::Clause(
WhereClause::Pattern(Pattern { WhereClause::Pattern(Pattern {

View file

@ -615,7 +615,7 @@ pub enum UnifyVars {
/// Only the named variables will be unified with the enclosing query. /// Only the named variables will be unified with the enclosing query.
/// ///
/// Every 'arm' in an `or-join` must mention the entire set of explicit vars. /// Every 'arm' in an `or-join` must mention the entire set of explicit vars.
Explicit(Vec<Variable>), Explicit(BTreeSet<Variable>),
} }
impl WhereClause { impl WhereClause {