Part 1: parse :in.
We also at this point switch from using `Vec<Variable>` to `BTreeSet<Variable>`. This allows us to guarantee no duplicates later; we'll reject duplicates at parse time.
This commit is contained in:
parent
01af45ab3f
commit
a9a82ea1a7
2 changed files with 50 additions and 13 deletions
|
@ -15,6 +15,8 @@ extern crate mentat_query;
|
||||||
|
|
||||||
use std; // To refer to std::result::Result.
|
use std; // To refer to std::result::Result.
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use self::combine::{eof, many, many1, optional, parser, satisfy, satisfy_map, Parser, ParseResult, Stream};
|
use self::combine::{eof, many, many1, optional, parser, satisfy, satisfy_map, Parser, ParseResult, Stream};
|
||||||
use self::combine::combinator::{choice, or, try};
|
use self::combine::combinator::{choice, or, try};
|
||||||
|
|
||||||
|
@ -65,6 +67,11 @@ error_chain! {
|
||||||
}
|
}
|
||||||
|
|
||||||
errors {
|
errors {
|
||||||
|
DuplicateVariableError {
|
||||||
|
description("duplicate variable")
|
||||||
|
display("duplicates in variable list")
|
||||||
|
}
|
||||||
|
|
||||||
NotAVariableError(value: edn::ValueAndSpan) {
|
NotAVariableError(value: edn::ValueAndSpan) {
|
||||||
description("not a variable")
|
description("not a variable")
|
||||||
display("not a variable: '{}'", value)
|
display("not a variable: '{}'", value)
|
||||||
|
@ -328,6 +335,8 @@ def_parser!(Find, spec, FindSpec, {
|
||||||
|
|
||||||
def_matches_keyword!(Find, literal_find, "find");
|
def_matches_keyword!(Find, literal_find, "find");
|
||||||
|
|
||||||
|
def_matches_keyword!(Find, literal_in, "in");
|
||||||
|
|
||||||
def_matches_keyword!(Find, literal_with, "with");
|
def_matches_keyword!(Find, literal_with, "with");
|
||||||
|
|
||||||
def_matches_keyword!(Find, literal_where, "where");
|
def_matches_keyword!(Find, literal_where, "where");
|
||||||
|
@ -337,11 +346,26 @@ def_matches_keyword!(Find, literal_order, "order");
|
||||||
/// Express something close to a builder pattern for a `FindQuery`.
|
/// Express something close to a builder pattern for a `FindQuery`.
|
||||||
enum FindQueryPart {
|
enum FindQueryPart {
|
||||||
FindSpec(FindSpec),
|
FindSpec(FindSpec),
|
||||||
With(Vec<Variable>),
|
With(BTreeSet<Variable>),
|
||||||
|
In(BTreeSet<Variable>),
|
||||||
WhereClauses(Vec<WhereClause>),
|
WhereClauses(Vec<WhereClause>),
|
||||||
Order(Vec<Order>),
|
Order(Vec<Order>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def_parser!(Find, vars, BTreeSet<Variable>, {
|
||||||
|
vector().of_exactly(many(Query::variable()).map(|vars: Vec<Variable>| {
|
||||||
|
let given = vars.len();
|
||||||
|
let set: BTreeSet<Variable> = vars.into_iter().collect();
|
||||||
|
if given != set.len() {
|
||||||
|
// TODO: find out what the variable is!
|
||||||
|
// TODO: figure out how to use `and_then` to return an error here.
|
||||||
|
panic!(Error::from_kind(ErrorKind::DuplicateVariableError));
|
||||||
|
} else {
|
||||||
|
set
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
/// 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
|
||||||
/// queries, then we use `FindQueryPart` to collect parts that have heterogeneous types; and then we
|
/// queries, then we use `FindQueryPart` to collect parts that have heterogeneous types; and then we
|
||||||
/// construct a `FindQuery` from them.
|
/// construct a `FindQuery` from them.
|
||||||
|
@ -349,8 +373,9 @@ def_parser!(Find, query, FindQuery, {
|
||||||
let p_find_spec = Find::literal_find()
|
let p_find_spec = Find::literal_find()
|
||||||
.with(vector().of_exactly(Find::spec().map(FindQueryPart::FindSpec)));
|
.with(vector().of_exactly(Find::spec().map(FindQueryPart::FindSpec)));
|
||||||
|
|
||||||
let p_with_vars = Find::literal_with()
|
let p_in_vars = Find::literal_in().with(Find::vars().map(FindQueryPart::In));
|
||||||
.with(vector().of_exactly(many(Query::variable()).map(FindQueryPart::With)));
|
|
||||||
|
let p_with_vars = Find::literal_with().with(Find::vars().map(FindQueryPart::With));
|
||||||
|
|
||||||
let p_where_clauses = Find::literal_where()
|
let p_where_clauses = Find::literal_where()
|
||||||
.with(vector().of_exactly(Where::clauses().map(FindQueryPart::WhereClauses))).expected(":where clauses");
|
.with(vector().of_exactly(Where::clauses().map(FindQueryPart::WhereClauses))).expected(":where clauses");
|
||||||
|
@ -359,14 +384,16 @@ def_parser!(Find, query, FindQuery, {
|
||||||
.with(vector().of_exactly(many1(Query::order()).map(FindQueryPart::Order)));
|
.with(vector().of_exactly(many1(Query::order()).map(FindQueryPart::Order)));
|
||||||
|
|
||||||
(or(map(), keyword_map()))
|
(or(map(), keyword_map()))
|
||||||
.of_exactly(many(choice::<[&mut Parser<Input = ValueStream, Output = FindQueryPart>; 4], _>([
|
.of_exactly(many(choice::<[&mut Parser<Input = ValueStream, Output = FindQueryPart>; 5], _>([
|
||||||
&mut try(p_find_spec),
|
&mut try(p_find_spec),
|
||||||
|
&mut try(p_in_vars),
|
||||||
&mut try(p_with_vars),
|
&mut try(p_with_vars),
|
||||||
&mut try(p_where_clauses),
|
&mut try(p_where_clauses),
|
||||||
&mut try(p_order_clauses),
|
&mut try(p_order_clauses),
|
||||||
])))
|
])))
|
||||||
.and_then(|parts: Vec<FindQueryPart>| -> std::result::Result<FindQuery, combine::primitives::Error<edn::ValueAndSpan, edn::ValueAndSpan>> {
|
.and_then(|parts: Vec<FindQueryPart>| -> std::result::Result<FindQuery, combine::primitives::Error<edn::ValueAndSpan, edn::ValueAndSpan>> {
|
||||||
let mut find_spec = None;
|
let mut find_spec = None;
|
||||||
|
let mut in_vars = None;
|
||||||
let mut with_vars = None;
|
let mut with_vars = None;
|
||||||
let mut where_clauses = None;
|
let mut where_clauses = None;
|
||||||
let mut order_clauses = None;
|
let mut order_clauses = None;
|
||||||
|
@ -375,6 +402,7 @@ def_parser!(Find, query, FindQuery, {
|
||||||
match part {
|
match part {
|
||||||
FindQueryPart::FindSpec(x) => find_spec = Some(x),
|
FindQueryPart::FindSpec(x) => find_spec = Some(x),
|
||||||
FindQueryPart::With(x) => with_vars = Some(x),
|
FindQueryPart::With(x) => with_vars = Some(x),
|
||||||
|
FindQueryPart::In(x) => in_vars = Some(x),
|
||||||
FindQueryPart::WhereClauses(x) => where_clauses = Some(x),
|
FindQueryPart::WhereClauses(x) => where_clauses = Some(x),
|
||||||
FindQueryPart::Order(x) => order_clauses = Some(x),
|
FindQueryPart::Order(x) => order_clauses = Some(x),
|
||||||
}
|
}
|
||||||
|
@ -383,9 +411,9 @@ def_parser!(Find, query, FindQuery, {
|
||||||
Ok(FindQuery {
|
Ok(FindQuery {
|
||||||
find_spec: find_spec.clone().ok_or(combine::primitives::Error::Unexpected("expected :find".into()))?,
|
find_spec: find_spec.clone().ok_or(combine::primitives::Error::Unexpected("expected :find".into()))?,
|
||||||
default_source: SrcVar::DefaultSrc,
|
default_source: SrcVar::DefaultSrc,
|
||||||
with: with_vars.unwrap_or(vec![]),
|
with: with_vars.unwrap_or(BTreeSet::default()),
|
||||||
in_vars: vec![], // TODO
|
in_vars: in_vars.unwrap_or(BTreeSet::default()),
|
||||||
in_sources: vec![], // TODO
|
in_sources: BTreeSet::default(), // TODO
|
||||||
order: order_clauses,
|
order: order_clauses,
|
||||||
where_clauses: where_clauses.ok_or(combine::primitives::Error::Unexpected("expected :where".into()))?,
|
where_clauses: where_clauses.ok_or(combine::primitives::Error::Unexpected("expected :where".into()))?,
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,12 +33,21 @@
|
||||||
extern crate edn;
|
extern crate edn;
|
||||||
extern crate mentat_core;
|
extern crate mentat_core;
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::{
|
||||||
|
BTreeMap,
|
||||||
|
BTreeSet,
|
||||||
|
};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use edn::{BigInt, OrderedFloat};
|
use edn::{BigInt, OrderedFloat};
|
||||||
pub use edn::{NamespacedKeyword, PlainSymbol};
|
pub use edn::{NamespacedKeyword, PlainSymbol};
|
||||||
use mentat_core::TypedValue;
|
|
||||||
|
use mentat_core::{
|
||||||
|
TypedValue,
|
||||||
|
ValueType,
|
||||||
|
};
|
||||||
|
|
||||||
pub type SrcVarName = String; // Do not include the required syntactic '$'.
|
pub type SrcVarName = String; // Do not include the required syntactic '$'.
|
||||||
|
|
||||||
|
@ -138,7 +147,7 @@ pub enum Direction {
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Order(pub Direction, pub Variable); // Future: Element instead of Variable?
|
pub struct Order(pub Direction, pub Variable); // Future: Element instead of Variable?
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum SrcVar {
|
pub enum SrcVar {
|
||||||
DefaultSrc,
|
DefaultSrc,
|
||||||
NamedSrc(SrcVarName),
|
NamedSrc(SrcVarName),
|
||||||
|
@ -600,9 +609,9 @@ pub enum WhereClause {
|
||||||
pub struct FindQuery {
|
pub struct FindQuery {
|
||||||
pub find_spec: FindSpec,
|
pub find_spec: FindSpec,
|
||||||
pub default_source: SrcVar,
|
pub default_source: SrcVar,
|
||||||
pub with: Vec<Variable>,
|
pub with: BTreeSet<Variable>,
|
||||||
pub in_vars: Vec<Variable>,
|
pub in_vars: BTreeSet<Variable>,
|
||||||
pub in_sources: Vec<SrcVar>,
|
pub in_sources: BTreeSet<SrcVar>,
|
||||||
pub where_clauses: Vec<WhereClause>,
|
pub where_clauses: Vec<WhereClause>,
|
||||||
pub order: Option<Vec<Order>>,
|
pub order: Option<Vec<Order>>,
|
||||||
// TODO: in_rules;
|
// TODO: in_rules;
|
||||||
|
|
Loading…
Reference in a new issue