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:
Richard Newman 2017-04-17 18:46:40 -07:00
parent 01af45ab3f
commit a9a82ea1a7
2 changed files with 50 additions and 13 deletions

View file

@ -15,6 +15,8 @@ extern crate mentat_query;
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::combinator::{choice, or, try};
@ -65,6 +67,11 @@ error_chain! {
}
errors {
DuplicateVariableError {
description("duplicate variable")
display("duplicates in variable list")
}
NotAVariableError(value: edn::ValueAndSpan) {
description("not a variable")
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_in, "in");
def_matches_keyword!(Find, literal_with, "with");
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`.
enum FindQueryPart {
FindSpec(FindSpec),
With(Vec<Variable>),
With(BTreeSet<Variable>),
In(BTreeSet<Variable>),
WhereClauses(Vec<WhereClause>),
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
/// queries, then we use `FindQueryPart` to collect parts that have heterogeneous types; and then we
/// construct a `FindQuery` from them.
@ -349,8 +373,9 @@ def_parser!(Find, query, FindQuery, {
let p_find_spec = Find::literal_find()
.with(vector().of_exactly(Find::spec().map(FindQueryPart::FindSpec)));
let p_with_vars = Find::literal_with()
.with(vector().of_exactly(many(Query::variable()).map(FindQueryPart::With)));
let p_in_vars = Find::literal_in().with(Find::vars().map(FindQueryPart::In));
let p_with_vars = Find::literal_with().with(Find::vars().map(FindQueryPart::With));
let p_where_clauses = Find::literal_where()
.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)));
(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_in_vars),
&mut try(p_with_vars),
&mut try(p_where_clauses),
&mut try(p_order_clauses),
])))
.and_then(|parts: Vec<FindQueryPart>| -> std::result::Result<FindQuery, combine::primitives::Error<edn::ValueAndSpan, edn::ValueAndSpan>> {
let mut find_spec = None;
let mut in_vars = None;
let mut with_vars = None;
let mut where_clauses = None;
let mut order_clauses = None;
@ -375,6 +402,7 @@ def_parser!(Find, query, FindQuery, {
match part {
FindQueryPart::FindSpec(x) => find_spec = Some(x),
FindQueryPart::With(x) => with_vars = Some(x),
FindQueryPart::In(x) => in_vars = Some(x),
FindQueryPart::WhereClauses(x) => where_clauses = Some(x),
FindQueryPart::Order(x) => order_clauses = Some(x),
}
@ -383,9 +411,9 @@ def_parser!(Find, query, FindQuery, {
Ok(FindQuery {
find_spec: find_spec.clone().ok_or(combine::primitives::Error::Unexpected("expected :find".into()))?,
default_source: SrcVar::DefaultSrc,
with: with_vars.unwrap_or(vec![]),
in_vars: vec![], // TODO
in_sources: vec![], // TODO
with: with_vars.unwrap_or(BTreeSet::default()),
in_vars: in_vars.unwrap_or(BTreeSet::default()),
in_sources: BTreeSet::default(), // TODO
order: order_clauses,
where_clauses: where_clauses.ok_or(combine::primitives::Error::Unexpected("expected :where".into()))?,
})

View file

@ -33,12 +33,21 @@
extern crate edn;
extern crate mentat_core;
use std::collections::BTreeSet;
use std::collections::{
BTreeMap,
BTreeSet,
};
use std::fmt;
use std::rc::Rc;
use edn::{BigInt, OrderedFloat};
pub use edn::{NamespacedKeyword, PlainSymbol};
use mentat_core::TypedValue;
use mentat_core::{
TypedValue,
ValueType,
};
pub type SrcVarName = String; // Do not include the required syntactic '$'.
@ -138,7 +147,7 @@ pub enum Direction {
#[derive(Clone, Debug, Eq, PartialEq)]
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 {
DefaultSrc,
NamedSrc(SrcVarName),
@ -600,9 +609,9 @@ pub enum WhereClause {
pub struct FindQuery {
pub find_spec: FindSpec,
pub default_source: SrcVar,
pub with: Vec<Variable>,
pub in_vars: Vec<Variable>,
pub in_sources: Vec<SrcVar>,
pub with: BTreeSet<Variable>,
pub in_vars: BTreeSet<Variable>,
pub in_sources: BTreeSet<SrcVar>,
pub where_clauses: Vec<WhereClause>,
pub order: Option<Vec<Order>>,
// TODO: in_rules;