Part 3: Use value_and_span
apparatus in query-parser/.
This commit is contained in:
parent
e947a32c59
commit
ff136b2546
6 changed files with 346 additions and 749 deletions
|
@ -1,261 +0,0 @@
|
||||||
// Copyright 2016 Mozilla
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License. You may obtain a copy of the
|
|
||||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
/// ! This module defines the interface and implementation for parsing an EDN
|
|
||||||
/// ! input into a structured Datalog query.
|
|
||||||
/// !
|
|
||||||
/// ! The query types are defined in the `query` crate, because they
|
|
||||||
/// ! are shared between the parser (EDN -> query), the translator
|
|
||||||
/// ! (query -> SQL), and the executor (query, SQL -> running code).
|
|
||||||
/// !
|
|
||||||
/// ! The query input can be in two forms: a 'flat' human-oriented
|
|
||||||
/// ! sequence:
|
|
||||||
/// !
|
|
||||||
/// ! ```clojure
|
|
||||||
/// ! [:find ?y :in $ ?x :where [?x :foaf/knows ?y]]
|
|
||||||
/// ! ```
|
|
||||||
/// !
|
|
||||||
/// ! or a more programmatically generable map:
|
|
||||||
/// !
|
|
||||||
/// ! ```clojure
|
|
||||||
/// ! {:find [?y]
|
|
||||||
/// ! :in [$]
|
|
||||||
/// ! :where [[?x :foaf/knows ?y]]}
|
|
||||||
/// ! ```
|
|
||||||
/// !
|
|
||||||
/// ! We parse by expanding the array format into four parts, treating them as the four
|
|
||||||
/// ! parts of the map.
|
|
||||||
|
|
||||||
extern crate edn;
|
|
||||||
extern crate mentat_parser_utils;
|
|
||||||
extern crate mentat_query;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use self::mentat_query::{
|
|
||||||
FindQuery,
|
|
||||||
FnArg,
|
|
||||||
FromValue,
|
|
||||||
Predicate,
|
|
||||||
PredicateFn,
|
|
||||||
SrcVar,
|
|
||||||
Variable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use self::mentat_parser_utils::ValueParseError;
|
|
||||||
|
|
||||||
use super::parse::{
|
|
||||||
ErrorKind,
|
|
||||||
QueryParseResult,
|
|
||||||
Result,
|
|
||||||
clause_seq_to_patterns,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::util::vec_to_keyword_map;
|
|
||||||
|
|
||||||
/// If the provided slice of EDN values are all variables as
|
|
||||||
/// defined by `value_to_variable`, return a `Vec` of `Variable`s.
|
|
||||||
/// Otherwise, return the unrecognized Value in a `NotAVariableError`.
|
|
||||||
fn values_to_variables(vals: &[edn::Value]) -> Result<Vec<Variable>> {
|
|
||||||
let mut out: Vec<Variable> = Vec::with_capacity(vals.len());
|
|
||||||
for v in vals {
|
|
||||||
if let Some(var) = Variable::from_value(v) {
|
|
||||||
out.push(var);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bail!(ErrorKind::NotAVariableError(v.clone()));
|
|
||||||
}
|
|
||||||
return Ok(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
fn parse_find_parts(find: &[edn::Value],
|
|
||||||
ins: Option<&[edn::Value]>,
|
|
||||||
with: Option<&[edn::Value]>,
|
|
||||||
wheres: &[edn::Value])
|
|
||||||
-> QueryParseResult {
|
|
||||||
// :find must be an array of plain var symbols (?foo), pull expressions, and aggregates.
|
|
||||||
// For now we only support variables and the annotations necessary to declare which
|
|
||||||
// flavor of :find we want:
|
|
||||||
// ?x ?y ?z = FindRel
|
|
||||||
// [?x ...] = FindColl
|
|
||||||
// ?x . = FindScalar
|
|
||||||
// [?x ?y ?z] = FindTuple
|
|
||||||
//
|
|
||||||
// :in must be an array of sources ($), rules (%), and vars (?). For now we only support the
|
|
||||||
// default source. :in can be omitted, in which case the default is equivalent to `:in $`.
|
|
||||||
// TODO: process `ins`.
|
|
||||||
let source = SrcVar::DefaultSrc;
|
|
||||||
|
|
||||||
// :with is an array of variables. This is simple, so we don't use a parser.
|
|
||||||
let with_vars = if let Some(vals) = with {
|
|
||||||
values_to_variables(vals)?
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
// :wheres is a whole datastructure.
|
|
||||||
let where_clauses = clause_seq_to_patterns(wheres)?;
|
|
||||||
|
|
||||||
super::parse::find_seq_to_find_spec(find)
|
|
||||||
.map(|spec| {
|
|
||||||
FindQuery {
|
|
||||||
find_spec: spec,
|
|
||||||
default_source: source,
|
|
||||||
with: with_vars,
|
|
||||||
in_vars: vec![], // TODO
|
|
||||||
in_sources: vec![], // TODO
|
|
||||||
where_clauses: where_clauses,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_find_map(map: BTreeMap<edn::Keyword, Vec<edn::Value>>) -> QueryParseResult {
|
|
||||||
// Eagerly awaiting `const fn`.
|
|
||||||
let kw_find = edn::Keyword::new("find");
|
|
||||||
let kw_in = edn::Keyword::new("in");
|
|
||||||
let kw_with = edn::Keyword::new("with");
|
|
||||||
let kw_where = edn::Keyword::new("where");
|
|
||||||
|
|
||||||
// Oh, if only we had `guard`.
|
|
||||||
if let Some(find) = map.get(&kw_find) {
|
|
||||||
if let Some(wheres) = map.get(&kw_where) {
|
|
||||||
parse_find_parts(find,
|
|
||||||
map.get(&kw_in).map(|x| x.as_slice()),
|
|
||||||
map.get(&kw_with).map(|x| x.as_slice()),
|
|
||||||
wheres)
|
|
||||||
} else {
|
|
||||||
bail!(ErrorKind::MissingFieldError(kw_where))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bail!(ErrorKind::MissingFieldError(kw_find))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_find_edn_map(map: BTreeMap<edn::Value, edn::Value>) -> QueryParseResult {
|
|
||||||
// Every key must be a Keyword. Every value must be a Vec.
|
|
||||||
let mut m = BTreeMap::new();
|
|
||||||
|
|
||||||
if map.is_empty() {
|
|
||||||
return parse_find_map(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (k, v) in map {
|
|
||||||
if let edn::Value::Keyword(kw) = k {
|
|
||||||
if let edn::Value::Vector(vec) = v {
|
|
||||||
m.insert(kw, vec);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
bail!(ErrorKind::InvalidInputError(v))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bail!(ErrorKind::InvalidInputError(k))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_find_map(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_find_string(string: &str) -> QueryParseResult {
|
|
||||||
let expr = edn::parse::value(string)?;
|
|
||||||
parse_find(expr.without_spans())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_find(expr: edn::Value) -> QueryParseResult {
|
|
||||||
// No `match` because scoping and use of `expr` in error handling is nuts.
|
|
||||||
if let edn::Value::Map(m) = expr {
|
|
||||||
return parse_find_edn_map(m);
|
|
||||||
}
|
|
||||||
if let edn::Value::Vector(ref v) = expr {
|
|
||||||
if let Some(m) = vec_to_keyword_map(v) {
|
|
||||||
return parse_find_map(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bail!(ErrorKind::InvalidInputError(expr))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test_parse {
|
|
||||||
extern crate edn;
|
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use self::edn::{NamespacedKeyword, PlainSymbol};
|
|
||||||
use self::edn::types::Value;
|
|
||||||
use super::mentat_query::{
|
|
||||||
Element,
|
|
||||||
FindSpec,
|
|
||||||
Pattern,
|
|
||||||
PatternNonValuePlace,
|
|
||||||
PatternValuePlace,
|
|
||||||
SrcVar,
|
|
||||||
Variable,
|
|
||||||
WhereClause,
|
|
||||||
};
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
// TODO: when #224 lands, fix to_keyword to be variadic.
|
|
||||||
#[test]
|
|
||||||
fn test_parse_find() {
|
|
||||||
let truncated_input = edn::Value::Vector(vec![Value::from_keyword(None, "find")]);
|
|
||||||
assert!(parse_find(truncated_input).is_err());
|
|
||||||
|
|
||||||
let input =
|
|
||||||
edn::Value::Vector(vec![Value::from_keyword(None, "find"),
|
|
||||||
Value::from_symbol(None, "?x"),
|
|
||||||
Value::from_symbol(None, "?y"),
|
|
||||||
Value::from_keyword(None, "where"),
|
|
||||||
edn::Value::Vector(vec![Value::from_symbol(None, "?x"),
|
|
||||||
Value::from_keyword("foo", "bar"),
|
|
||||||
Value::from_symbol(None, "?y")])]);
|
|
||||||
|
|
||||||
let parsed = parse_find(input).unwrap();
|
|
||||||
if let FindSpec::FindRel(elems) = parsed.find_spec {
|
|
||||||
assert_eq!(2, elems.len());
|
|
||||||
assert_eq!(vec![Element::Variable(Variable::from_valid_name("?x")),
|
|
||||||
Element::Variable(Variable::from_valid_name("?y"))],
|
|
||||||
elems);
|
|
||||||
} else {
|
|
||||||
panic!("Expected FindRel.");
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(SrcVar::DefaultSrc, parsed.default_source);
|
|
||||||
assert_eq!(parsed.where_clauses,
|
|
||||||
vec![
|
|
||||||
WhereClause::Pattern(Pattern {
|
|
||||||
source: None,
|
|
||||||
entity: PatternNonValuePlace::Variable(Variable::from_valid_name("?x")),
|
|
||||||
attribute: PatternNonValuePlace::Ident(Rc::new(NamespacedKeyword::new("foo", "bar"))),
|
|
||||||
value: PatternValuePlace::Variable(Variable::from_valid_name("?y")),
|
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
|
||||||
})]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_predicate() {
|
|
||||||
let input = "[:find ?x :where [?x :foo/bar ?y] [[< ?y 10]]]";
|
|
||||||
let parsed = parse_find_string(input).unwrap();
|
|
||||||
assert_eq!(parsed.where_clauses,
|
|
||||||
vec![
|
|
||||||
WhereClause::Pattern(Pattern {
|
|
||||||
source: None,
|
|
||||||
entity: PatternNonValuePlace::Variable(Variable::from_valid_name("?x")),
|
|
||||||
attribute: PatternNonValuePlace::Ident(Rc::new(NamespacedKeyword::new("foo", "bar"))),
|
|
||||||
value: PatternValuePlace::Variable(Variable::from_valid_name("?y")),
|
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
|
||||||
}),
|
|
||||||
WhereClause::Pred(Predicate {
|
|
||||||
operator: PlainSymbol::new("<"),
|
|
||||||
args: vec![FnArg::Variable(Variable::from_valid_name("?y")),
|
|
||||||
FnArg::EntidOrInteger(10)],
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,19 +21,12 @@ extern crate edn;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate mentat_parser_utils;
|
extern crate mentat_parser_utils;
|
||||||
|
|
||||||
mod util;
|
|
||||||
mod parse;
|
mod parse;
|
||||||
pub mod find;
|
|
||||||
|
|
||||||
pub use find::{
|
|
||||||
parse_find,
|
|
||||||
parse_find_string,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use parse::{
|
pub use parse::{
|
||||||
Error,
|
Error,
|
||||||
ErrorKind,
|
ErrorKind,
|
||||||
QueryParseResult,
|
|
||||||
Result,
|
Result,
|
||||||
ResultExt,
|
ResultExt,
|
||||||
|
parse_find_string,
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,14 +13,27 @@ extern crate edn;
|
||||||
extern crate mentat_parser_utils;
|
extern crate mentat_parser_utils;
|
||||||
extern crate mentat_query;
|
extern crate mentat_query;
|
||||||
|
|
||||||
use self::combine::{eof, many, many1, optional, parser, satisfy_map, Parser, ParseResult, Stream};
|
use std; // To refer to std::result::Result.
|
||||||
use self::combine::combinator::{choice, try};
|
|
||||||
|
use self::combine::{eof, many, many1, optional, parser, satisfy, satisfy_map, Parser, ParseResult, Stream};
|
||||||
|
use self::combine::combinator::{choice, or, try};
|
||||||
|
|
||||||
use self::mentat_parser_utils::{
|
use self::mentat_parser_utils::{
|
||||||
ResultParser,
|
ResultParser,
|
||||||
ValueParseError,
|
ValueParseError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::mentat_parser_utils::value_and_span::Stream as ValueStream;
|
||||||
|
use self::mentat_parser_utils::value_and_span::{
|
||||||
|
Item,
|
||||||
|
OfParsing,
|
||||||
|
keyword_map,
|
||||||
|
list,
|
||||||
|
map,
|
||||||
|
seq,
|
||||||
|
vector,
|
||||||
|
};
|
||||||
|
|
||||||
use self::mentat_query::{
|
use self::mentat_query::{
|
||||||
Element,
|
Element,
|
||||||
FindQuery,
|
FindQuery,
|
||||||
|
@ -50,17 +63,17 @@ error_chain! {
|
||||||
}
|
}
|
||||||
|
|
||||||
errors {
|
errors {
|
||||||
NotAVariableError(value: edn::Value) {
|
NotAVariableError(value: edn::ValueAndSpan) {
|
||||||
description("not a variable")
|
description("not a variable")
|
||||||
display("not a variable: '{}'", value)
|
display("not a variable: '{}'", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
FindParseError(e: ValueParseError) {
|
FindParseError(e: combine::ParseError<ValueStream>) {
|
||||||
description(":find parse error")
|
description(":find parse error")
|
||||||
display(":find parse error")
|
display(":find parse error")
|
||||||
}
|
}
|
||||||
|
|
||||||
WhereParseError(e: ValueParseError) {
|
WhereParseError(e: combine::ParseError<ValueStream>) {
|
||||||
description(":where parse error")
|
description(":where parse error")
|
||||||
display(":where parse error")
|
display(":where parse error")
|
||||||
}
|
}
|
||||||
|
@ -83,321 +96,349 @@ error_chain! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type WhereParseResult = Result<Vec<WhereClause>>;
|
pub struct Query;
|
||||||
pub type FindParseResult = Result<FindSpec>;
|
|
||||||
pub type QueryParseResult = Result<FindQuery>;
|
|
||||||
|
|
||||||
pub struct Query<I>(::std::marker::PhantomData<fn(I) -> I>);
|
def_parser!(Query, variable, Variable, {
|
||||||
|
satisfy_map(Variable::from_value)
|
||||||
|
});
|
||||||
|
|
||||||
impl<I> Query<I>
|
def_parser!(Query, source_var, SrcVar, {
|
||||||
where I: Stream<Item = edn::Value>
|
satisfy_map(SrcVar::from_value)
|
||||||
{
|
});
|
||||||
fn to_parsed_value<T>(r: ParseResult<T, I>) -> Option<T> {
|
|
||||||
r.ok().map(|x| x.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: interning.
|
// TODO: interning.
|
||||||
def_value_satisfy_parser_fn!(Query, variable, Variable, Variable::from_value);
|
def_parser!(Query, predicate_fn, PredicateFn, {
|
||||||
def_value_satisfy_parser_fn!(Query, source_var, SrcVar, SrcVar::from_value);
|
satisfy_map(PredicateFn::from_value)
|
||||||
def_value_satisfy_parser_fn!(Query, predicate_fn, PredicateFn, PredicateFn::from_value);
|
});
|
||||||
def_value_satisfy_parser_fn!(Query, fn_arg, FnArg, FnArg::from_value);
|
|
||||||
|
|
||||||
pub struct Where<I>(::std::marker::PhantomData<fn(I) -> I>);
|
def_parser!(Query, fn_arg, FnArg, {
|
||||||
|
satisfy_map(FnArg::from_value)
|
||||||
|
});
|
||||||
|
|
||||||
def_value_satisfy_parser_fn!(Where,
|
def_parser!(Query, arguments, Vec<FnArg>, {
|
||||||
pattern_value_place,
|
(many::<Vec<FnArg>, _>(Query::fn_arg()))
|
||||||
PatternValuePlace,
|
});
|
||||||
PatternValuePlace::from_value);
|
|
||||||
def_value_satisfy_parser_fn!(Where,
|
|
||||||
pattern_non_value_place,
|
|
||||||
PatternNonValuePlace,
|
|
||||||
PatternNonValuePlace::from_value);
|
|
||||||
|
|
||||||
fn seq<T: Into<Option<edn::Value>>>(x: T) -> Option<Vec<edn::Value>> {
|
pub struct Where;
|
||||||
match x.into() {
|
|
||||||
Some(edn::Value::List(items)) => Some(items.into_iter().collect()),
|
|
||||||
Some(edn::Value::Vector(items)) => Some(items),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take a vector Value containing one vector Value, and return the `Vec` inside the inner vector.
|
def_parser!(Where, pattern_value_place, PatternValuePlace, {
|
||||||
/// Also accepts an inner list, returning it as a `Vec`.
|
satisfy_map(PatternValuePlace::from_value)
|
||||||
fn unwrap_nested(x: edn::Value) -> Option<Vec<edn::Value>> {
|
});
|
||||||
match x {
|
|
||||||
edn::Value::Vector(mut v) => {
|
def_parser!(Where, pattern_non_value_place, PatternNonValuePlace, {
|
||||||
seq(v.pop())
|
satisfy_map(PatternNonValuePlace::from_value)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
def_parser!(Where, and, edn::ValueAndSpan, {
|
||||||
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
|
s.0.as_str() == "and"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
_ => None,
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def_value_parser_fn!(Where, and, (), input, {
|
|
||||||
matches_plain_symbol!("and", input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or, (), input, {
|
def_parser!(Where, or, edn::ValueAndSpan, {
|
||||||
matches_plain_symbol!("or", input)
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
|
s.0.as_str() == "or"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or_join, (), input, {
|
def_parser!(Where, or_join, edn::ValueAndSpan, {
|
||||||
matches_plain_symbol!("or-join", input)
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
|
s.0.as_str() == "or-join"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, rule_vars, Vec<Variable>, input, {
|
def_parser!(Where, rule_vars, Vec<Variable>, {
|
||||||
satisfy_map(|x: edn::Value| {
|
seq()
|
||||||
seq(x).and_then(|items| {
|
.of(many1(Query::variable()))
|
||||||
let mut p = many1(Query::variable()).skip(eof());
|
|
||||||
Query::to_parsed_value(p.parse_lazy(&items[..]).into())
|
|
||||||
})}).parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or_pattern_clause, OrWhereClause, input, {
|
def_parser!(Where, or_pattern_clause, OrWhereClause, {
|
||||||
Where::clause().map(|clause| OrWhereClause::Clause(clause)).parse_stream(input)
|
Where::clause().map(|clause| OrWhereClause::Clause(clause))
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or_and_clause, OrWhereClause, input, {
|
def_parser!(Where, or_and_clause, OrWhereClause, {
|
||||||
satisfy_map(|x: edn::Value| {
|
seq()
|
||||||
seq(x).and_then(|items| {
|
.of(Where::and()
|
||||||
let mut p = Where::and()
|
.with(many1(Where::clause()))
|
||||||
.with(many1(Where::clause()))
|
.map(OrWhereClause::And))
|
||||||
.skip(eof())
|
|
||||||
.map(OrWhereClause::And);
|
|
||||||
let r: ParseResult<OrWhereClause, _> = p.parse_lazy(&items[..]).into();
|
|
||||||
Query::to_parsed_value(r)
|
|
||||||
})
|
|
||||||
}).parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or_where_clause, OrWhereClause, input, {
|
def_parser!(Where, or_where_clause, OrWhereClause, {
|
||||||
choice([Where::or_pattern_clause(), Where::or_and_clause()]).parse_stream(input)
|
choice([Where::or_pattern_clause(), Where::or_and_clause()])
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or_clause, WhereClause, input, {
|
def_parser!(Where, or_clause, WhereClause, {
|
||||||
satisfy_map(|x: edn::Value| {
|
seq()
|
||||||
seq(x).and_then(|items| {
|
.of(Where::or()
|
||||||
let mut p = Where::or()
|
.with(many1(Where::or_where_clause()))
|
||||||
.with(many1(Where::or_where_clause()))
|
.map(|clauses| {
|
||||||
.skip(eof())
|
WhereClause::OrJoin(
|
||||||
.map(|clauses| {
|
OrJoin {
|
||||||
WhereClause::OrJoin(
|
unify_vars: UnifyVars::Implicit,
|
||||||
OrJoin {
|
clauses: clauses,
|
||||||
unify_vars: UnifyVars::Implicit,
|
})
|
||||||
clauses: clauses,
|
}))
|
||||||
})
|
|
||||||
});
|
|
||||||
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
|
|
||||||
Query::to_parsed_value(r)
|
|
||||||
})
|
|
||||||
}).parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, or_join_clause, WhereClause, input, {
|
def_parser!(Where, or_join_clause, WhereClause, {
|
||||||
satisfy_map(|x: edn::Value| {
|
seq()
|
||||||
seq(x).and_then(|items| {
|
.of(Where::or_join()
|
||||||
let mut p = Where::or_join()
|
.with(Where::rule_vars())
|
||||||
.with(Where::rule_vars())
|
.and(many1(Where::or_where_clause()))
|
||||||
.and(many1(Where::or_where_clause()))
|
.map(|(vars, clauses)| {
|
||||||
.skip(eof())
|
WhereClause::OrJoin(
|
||||||
.map(|(vars, clauses)| {
|
OrJoin {
|
||||||
WhereClause::OrJoin(
|
unify_vars: UnifyVars::Explicit(vars),
|
||||||
OrJoin {
|
clauses: clauses,
|
||||||
unify_vars: UnifyVars::Explicit(vars),
|
})
|
||||||
clauses: clauses,
|
}))
|
||||||
})
|
|
||||||
});
|
|
||||||
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
|
|
||||||
Query::to_parsed_value(r)
|
|
||||||
})
|
|
||||||
}).parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// A vector containing just a parenthesized filter expression.
|
/// A vector containing just a parenthesized filter expression.
|
||||||
def_value_parser_fn!(Where, pred, WhereClause, input, {
|
def_parser!(Where, pred, WhereClause, {
|
||||||
satisfy_map(|x: edn::Value| {
|
// Accept either a nested list or a nested vector here:
|
||||||
// Accept either a list or a vector here:
|
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
|
||||||
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
|
vector()
|
||||||
unwrap_nested(x).and_then(|items| {
|
.of(seq()
|
||||||
let mut p = (Query::predicate_fn(), Query::arguments())
|
.of((Query::predicate_fn(), Query::arguments())
|
||||||
.skip(eof())
|
.map(|(f, args)| {
|
||||||
.map(|(f, args)| {
|
WhereClause::Pred(
|
||||||
WhereClause::Pred(
|
Predicate {
|
||||||
Predicate {
|
operator: f.0,
|
||||||
operator: f.0,
|
args: args,
|
||||||
args: args,
|
})
|
||||||
})
|
})))
|
||||||
});
|
|
||||||
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
|
|
||||||
Query::to_parsed_value(r)
|
|
||||||
})
|
|
||||||
}).parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, pattern, WhereClause, input, {
|
def_parser!(Where, pattern, WhereClause, {
|
||||||
satisfy_map(|x: edn::Value| {
|
vector()
|
||||||
if let edn::Value::Vector(y) = x {
|
.of(
|
||||||
// While *technically* Datomic allows you to have a query like:
|
// While *technically* Datomic allows you to have a query like:
|
||||||
// [:find … :where [[?x]]]
|
// [:find … :where [[?x]]]
|
||||||
// We don't -- we require at least e, a.
|
// We don't -- we require at least e, a.
|
||||||
let mut p = (optional(Query::source_var()), // src
|
(optional(Query::source_var()), // src
|
||||||
Where::pattern_non_value_place(), // e
|
Where::pattern_non_value_place(), // e
|
||||||
Where::pattern_non_value_place(), // a
|
Where::pattern_non_value_place(), // a
|
||||||
optional(Where::pattern_value_place()), // v
|
optional(Where::pattern_value_place()), // v
|
||||||
optional(Where::pattern_non_value_place())) // tx
|
optional(Where::pattern_non_value_place())) // tx
|
||||||
.skip(eof())
|
.and_then(|(src, e, a, v, tx)| {
|
||||||
.map(|(src, e, a, v, tx)| {
|
let v = v.unwrap_or(PatternValuePlace::Placeholder);
|
||||||
let v = v.unwrap_or(PatternValuePlace::Placeholder);
|
let tx = tx.unwrap_or(PatternNonValuePlace::Placeholder);
|
||||||
let tx = tx.unwrap_or(PatternNonValuePlace::Placeholder);
|
|
||||||
|
|
||||||
// Pattern::new takes care of reversal of reversed
|
// Pattern::new takes care of reversal of reversed
|
||||||
// attributes: [?x :foo/_bar ?y] turns into
|
// attributes: [?x :foo/_bar ?y] turns into
|
||||||
// [?y :foo/bar ?x].
|
// [?y :foo/bar ?x].
|
||||||
Pattern::new(src, e, a, v, tx).map(WhereClause::Pattern)
|
//
|
||||||
});
|
// This is a bit messy: the inner conversion to a Pattern can
|
||||||
|
// fail if the input is something like
|
||||||
// This is a bit messy: the inner conversion to a Pattern can
|
//
|
||||||
// fail if the input is something like
|
// ```edn
|
||||||
//
|
// [?x :foo/_reversed 23.4]
|
||||||
// ```edn
|
// ```
|
||||||
// [?x :foo/_reversed 23.4]
|
//
|
||||||
// ```
|
// because
|
||||||
//
|
//
|
||||||
// because
|
// ```edn
|
||||||
//
|
// [23.4 :foo/reversed ?x]
|
||||||
// ```edn
|
// ```
|
||||||
// [23.4 :foo/reversed ?x]
|
//
|
||||||
// ```
|
// is nonsense. That leaves us with a nested optional, which we unwrap here.
|
||||||
//
|
Pattern::new(src, e, a, v, tx)
|
||||||
// is nonsense. That leaves us with nested optionals; we unwrap them here.
|
.map(WhereClause::Pattern)
|
||||||
let r: ParseResult<Option<WhereClause>, _> = p.parse_lazy(&y[..]).into();
|
.ok_or(combine::primitives::Error::Expected("pattern".into()))
|
||||||
let v: Option<Option<WhereClause>> = Query::to_parsed_value(r);
|
}))
|
||||||
v.unwrap_or(None)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}).parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Query, arguments, Vec<FnArg>, input, {
|
def_parser!(Where, clause, WhereClause, {
|
||||||
(many::<Vec<FnArg>, _>(Query::fn_arg()))
|
choice([try(Where::pattern()),
|
||||||
.skip(eof())
|
|
||||||
.parse_stream(input)
|
|
||||||
});
|
|
||||||
|
|
||||||
def_value_parser_fn!(Where, clause, WhereClause, input, {
|
|
||||||
choice([Where::pattern(),
|
|
||||||
Where::pred(),
|
|
||||||
// It's either
|
// It's either
|
||||||
// (or-join [vars] clauses…)
|
// (or-join [vars] clauses…)
|
||||||
// or
|
// or
|
||||||
// (or clauses…)
|
// (or clauses…)
|
||||||
// We don't yet handle source vars.
|
// We don't yet handle source vars.
|
||||||
Where::or_join_clause(),
|
try(Where::or_join_clause()),
|
||||||
Where::or_clause(),
|
try(Where::or_clause()),
|
||||||
]).parse_stream(input)
|
|
||||||
|
try(Where::pred()),
|
||||||
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, clauses, Vec<WhereClause>, input, {
|
def_parser!(Where, clauses, Vec<WhereClause>, {
|
||||||
// Right now we only support patterns and predicates. See #239 for more.
|
// Right now we only support patterns and predicates. See #239 for more.
|
||||||
(many1::<Vec<WhereClause>, _>(Where::clause()))
|
(many1::<Vec<WhereClause>, _>(Where::clause()))
|
||||||
.skip(eof())
|
|
||||||
.parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pub struct Find<I>(::std::marker::PhantomData<fn(I) -> I>);
|
pub struct Find;
|
||||||
|
|
||||||
def_value_parser_fn!(Find, period, (), input, {
|
/// TODO: extract macro for matching these `PlainSymbol` instances.
|
||||||
matches_plain_symbol!(".", input)
|
def_parser!(Find, period, edn::ValueAndSpan, {
|
||||||
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
|
s.0.as_str() == "."
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, ellipsis, (), input, {
|
def_parser!(Find, ellipsis, edn::ValueAndSpan, {
|
||||||
matches_plain_symbol!("...", input)
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
|
s.0.as_str() == "..."
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find_scalar, FindSpec, input, {
|
def_parser!(Find, find_scalar, FindSpec, {
|
||||||
Query::variable()
|
Query::variable()
|
||||||
|
.map(|var| FindSpec::FindScalar(Element::Variable(var)))
|
||||||
.skip(Find::period())
|
.skip(Find::period())
|
||||||
.skip(eof())
|
.skip(eof())
|
||||||
.map(|var| FindSpec::FindScalar(Element::Variable(var)))
|
|
||||||
.parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find_coll, FindSpec, input, {
|
def_parser!(Find, find_coll, FindSpec, {
|
||||||
satisfy_unwrap!(edn::Value::Vector, y, {
|
vector()
|
||||||
let mut p = Query::variable()
|
.of(Query::variable()
|
||||||
.skip(Find::ellipsis())
|
.map(|var| FindSpec::FindColl(Element::Variable(var)))
|
||||||
.skip(eof())
|
.skip(Find::ellipsis()))
|
||||||
.map(|var| FindSpec::FindColl(Element::Variable(var)));
|
|
||||||
let r: ParseResult<FindSpec, _> = p.parse_lazy(&y[..]).into();
|
|
||||||
Query::to_parsed_value(r)
|
|
||||||
})
|
|
||||||
.parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, elements, Vec<Element>, input, {
|
def_parser!(Find, elements, Vec<Element>, {
|
||||||
many1::<Vec<Variable>, _>(Query::variable()).skip(eof())
|
many1::<Vec<Element>, _>(Query::variable().map(Element::Variable))
|
||||||
.map(|vars| {
|
|
||||||
vars.into_iter()
|
|
||||||
.map(Element::Variable)
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find_rel, FindSpec, input, {
|
def_parser!(Find, find_rel, FindSpec, {
|
||||||
Find::elements().map(FindSpec::FindRel).parse_stream(input)
|
Find::elements().map(FindSpec::FindRel)
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find_tuple, FindSpec, input, {
|
def_parser!(Find, find_tuple, FindSpec, {
|
||||||
satisfy_unwrap!(edn::Value::Vector, y, {
|
vector()
|
||||||
let r: ParseResult<FindSpec, _> =
|
.of(Find::elements().map(FindSpec::FindTuple))
|
||||||
Find::elements().map(FindSpec::FindTuple).parse_lazy(&y[..]).into();
|
|
||||||
Query::to_parsed_value(r)
|
|
||||||
})
|
|
||||||
.parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find, FindSpec, input, {
|
/// Parse a stream values into one of four find specs.
|
||||||
// Any one of the four specs might apply, so we combine them with `choice`.
|
///
|
||||||
// Our parsers consume input, so we need to wrap them in `try` so that they
|
/// `:find` must be an array of plain var symbols (?foo), pull expressions, and aggregates. For now
|
||||||
// operate independently.
|
/// we only support variables and the annotations necessary to declare which flavor of :find we
|
||||||
choice::<[&mut Parser<Input = I, Output = FindSpec>; 4], _>
|
/// want:
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// `?x ?y ?z ` = FindRel
|
||||||
|
/// `[?x ...] ` = FindColl
|
||||||
|
/// `?x . ` = FindScalar
|
||||||
|
/// `[?x ?y ?z]` = FindTuple
|
||||||
|
def_parser!(Find, spec, FindSpec, {
|
||||||
|
// Any one of the four specs might apply, so we combine them with `choice`. Our parsers consume
|
||||||
|
// input, so we need to wrap them in `try` so that they operate independently.
|
||||||
|
choice::<[&mut Parser<Input = _, Output = FindSpec>; 4], _>
|
||||||
([&mut try(Find::find_scalar()),
|
([&mut try(Find::find_scalar()),
|
||||||
&mut try(Find::find_coll()),
|
&mut try(Find::find_coll()),
|
||||||
&mut try(Find::find_tuple()),
|
&mut try(Find::find_tuple()),
|
||||||
&mut try(Find::find_rel())])
|
&mut try(Find::find_rel())])
|
||||||
.parse_stream(input)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Parse a sequence of values into one of four find specs.
|
/// TODO: extract macro for matching these `Keyword` instances.
|
||||||
//
|
def_parser!(Find, literal_find, edn::ValueAndSpan, {
|
||||||
// `:find` must be an array of plain var symbols (?foo), pull expressions, and aggregates.
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
// For now we only support variables and the annotations necessary to declare which
|
if let edn::SpannedValue::Keyword(ref s) = v.inner {
|
||||||
// flavor of :find we want:
|
s.0.as_str() == "find"
|
||||||
//
|
} else {
|
||||||
//
|
false
|
||||||
// `?x ?y ?z ` = FindRel
|
}
|
||||||
// `[?x ...] ` = FindColl
|
})
|
||||||
// `?x . ` = FindScalar
|
});
|
||||||
// `[?x ?y ?z]` = FindTuple
|
|
||||||
//
|
def_parser!(Find, literal_with, edn::ValueAndSpan, {
|
||||||
#[allow(dead_code)]
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
pub fn find_seq_to_find_spec(find: &[edn::Value]) -> FindParseResult {
|
if let edn::SpannedValue::Keyword(ref s) = v.inner {
|
||||||
Find::find()
|
s.0.as_str() == "with"
|
||||||
.parse(find)
|
} else {
|
||||||
.map(|x| x.0)
|
false
|
||||||
.map_err::<ValueParseError, _>(|e| e.translate_position(find).into())
|
}
|
||||||
.map_err(|e| Error::from_kind(ErrorKind::FindParseError(e)))
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
def_parser!(Find, literal_where, edn::ValueAndSpan, {
|
||||||
|
satisfy(|v: edn::ValueAndSpan| {
|
||||||
|
if let edn::SpannedValue::Keyword(ref s) = v.inner {
|
||||||
|
s.0.as_str() == "where"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Express something close to a builder pattern for a `FindQuery`.
|
||||||
|
enum FindQueryPart {
|
||||||
|
FindSpec(FindSpec),
|
||||||
|
With(Vec<Variable>),
|
||||||
|
WhereClauses(Vec<WhereClause>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
/// This is awkward, but will do for now. We use `keyword_map()` to optionally accept vector find
|
||||||
pub fn clause_seq_to_patterns(clauses: &[edn::Value]) -> WhereParseResult {
|
/// queries, then we use `FindQueryPart` to collect parts that have heterogeneous types; and then we
|
||||||
Where::clauses()
|
/// construct a `FindQuery` from them.
|
||||||
.parse(clauses)
|
def_parser!(Find, query, FindQuery, {
|
||||||
|
let p_find_spec = Find::literal_find()
|
||||||
|
.with(vector().of(Find::spec().map(FindQueryPart::FindSpec)));
|
||||||
|
|
||||||
|
let p_with_vars = Find::literal_with()
|
||||||
|
.with(vector().of(many(Query::variable()).map(FindQueryPart::With)));
|
||||||
|
|
||||||
|
let p_where_clauses = Find::literal_where()
|
||||||
|
.with(vector().of(Where::clauses().map(FindQueryPart::WhereClauses))).expected(":where clauses");
|
||||||
|
|
||||||
|
(or(map(), keyword_map()))
|
||||||
|
.of(many(choice::<[&mut Parser<Input = ValueStream, Output = FindQueryPart>; 3], _>([
|
||||||
|
&mut try(p_find_spec),
|
||||||
|
&mut try(p_with_vars),
|
||||||
|
&mut try(p_where_clauses),
|
||||||
|
])))
|
||||||
|
.and_then(|parts: Vec<FindQueryPart>| -> std::result::Result<FindQuery, combine::primitives::Error<edn::ValueAndSpan, edn::ValueAndSpan>> {
|
||||||
|
let mut find_spec = None;
|
||||||
|
let mut with_vars = None;
|
||||||
|
let mut where_clauses = None;
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
match part {
|
||||||
|
FindQueryPart::FindSpec(x) => find_spec = Some(x),
|
||||||
|
FindQueryPart::With(x) => with_vars = Some(x),
|
||||||
|
FindQueryPart::WhereClauses(x) => where_clauses = Some(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
where_clauses: where_clauses.ok_or(combine::primitives::Error::Unexpected("expected :where".into()))?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn parse_find_string(string: &str) -> Result<FindQuery> {
|
||||||
|
let expr = edn::parse::value(string)?;
|
||||||
|
Find::query()
|
||||||
|
.parse(expr.into_atom_stream())
|
||||||
.map(|x| x.0)
|
.map(|x| x.0)
|
||||||
.map_err::<ValueParseError, _>(|e| e.translate_position(clauses).into())
|
.map_err(|e| Error::from_kind(ErrorKind::FindParseError(e)))
|
||||||
.map_err(|e| Error::from_kind(ErrorKind::WhereParseError(e)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -441,10 +482,10 @@ mod test {
|
||||||
let a = edn::NamespacedKeyword::new("foo", "bar");
|
let a = edn::NamespacedKeyword::new("foo", "bar");
|
||||||
let v = OrderedFloat(99.9);
|
let v = OrderedFloat(99.9);
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
let input = edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
||||||
edn::Value::NamespacedKeyword(a.clone()),
|
edn::Value::NamespacedKeyword(a.clone()),
|
||||||
edn::Value::Float(v.clone()),
|
edn::Value::Float(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())));
|
||||||
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
||||||
source: None,
|
source: None,
|
||||||
entity: PatternNonValuePlace::Placeholder,
|
entity: PatternNonValuePlace::Placeholder,
|
||||||
|
@ -461,11 +502,11 @@ mod test {
|
||||||
let a = edn::PlainSymbol::new("?a");
|
let a = edn::PlainSymbol::new("?a");
|
||||||
let v = edn::PlainSymbol::new("?v");
|
let v = edn::PlainSymbol::new("?v");
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(s.clone()),
|
let input = edn::Value::Vector(vec!(edn::Value::PlainSymbol(s.clone()),
|
||||||
edn::Value::PlainSymbol(e.clone()),
|
edn::Value::PlainSymbol(e.clone()),
|
||||||
edn::Value::PlainSymbol(a.clone()),
|
edn::Value::PlainSymbol(a.clone()),
|
||||||
edn::Value::PlainSymbol(v.clone()),
|
edn::Value::PlainSymbol(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())));
|
||||||
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
||||||
source: Some(SrcVar::NamedSrc("x".to_string())),
|
source: Some(SrcVar::NamedSrc("x".to_string())),
|
||||||
entity: PatternNonValuePlace::Variable(variable(e)),
|
entity: PatternNonValuePlace::Variable(variable(e)),
|
||||||
|
@ -481,13 +522,13 @@ mod test {
|
||||||
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
||||||
let v = OrderedFloat(99.9);
|
let v = OrderedFloat(99.9);
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
let input = edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
||||||
edn::Value::NamespacedKeyword(a.clone()),
|
edn::Value::NamespacedKeyword(a.clone()),
|
||||||
edn::Value::Float(v.clone()),
|
edn::Value::Float(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())));
|
||||||
|
|
||||||
let mut par = Where::pattern();
|
let mut par = Where::pattern();
|
||||||
let result = par.parse(&input[..]);
|
let result = par.parse(input.with_spans().into_atom_stream());
|
||||||
assert!(matches!(result, Err(_)), "Expected a parse error.");
|
assert!(matches!(result, Err(_)), "Expected a parse error.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,10 +538,10 @@ mod test {
|
||||||
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
||||||
let v = edn::PlainSymbol::new("?v");
|
let v = edn::PlainSymbol::new("?v");
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
let input = edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
||||||
edn::Value::NamespacedKeyword(a.clone()),
|
edn::Value::NamespacedKeyword(a.clone()),
|
||||||
edn::Value::PlainSymbol(v.clone()),
|
edn::Value::PlainSymbol(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())));
|
||||||
|
|
||||||
// Note that the attribute is no longer reversed, and the entity and value have
|
// Note that the attribute is no longer reversed, and the entity and value have
|
||||||
// switched places.
|
// switched places.
|
||||||
|
@ -516,7 +557,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rule_vars() {
|
fn test_rule_vars() {
|
||||||
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())]);
|
vec![variable(e.clone())]);
|
||||||
}
|
}
|
||||||
|
@ -527,11 +568,11 @@ mod test {
|
||||||
let e = edn::PlainSymbol::new("?e");
|
let e = edn::PlainSymbol::new("?e");
|
||||||
let a = edn::PlainSymbol::new("?a");
|
let a = edn::PlainSymbol::new("?a");
|
||||||
let v = edn::PlainSymbol::new("?v");
|
let v = edn::PlainSymbol::new("?v");
|
||||||
let input = [edn::Value::List(
|
let input = edn::Value::List(
|
||||||
vec![edn::Value::PlainSymbol(oj),
|
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(a.clone()),
|
||||||
edn::Value::PlainSymbol(v.clone())])].into_iter().collect())];
|
edn::Value::PlainSymbol(v.clone())])].into_iter().collect());
|
||||||
assert_parses_to!(Where::or_clause, input,
|
assert_parses_to!(Where::or_clause, input,
|
||||||
WhereClause::OrJoin(
|
WhereClause::OrJoin(
|
||||||
OrJoin {
|
OrJoin {
|
||||||
|
@ -553,12 +594,12 @@ mod test {
|
||||||
let e = edn::PlainSymbol::new("?e");
|
let e = edn::PlainSymbol::new("?e");
|
||||||
let a = edn::PlainSymbol::new("?a");
|
let a = edn::PlainSymbol::new("?a");
|
||||||
let v = edn::PlainSymbol::new("?v");
|
let v = edn::PlainSymbol::new("?v");
|
||||||
let input = [edn::Value::List(
|
let input = edn::Value::List(
|
||||||
vec![edn::Value::PlainSymbol(oj),
|
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::Vector(vec![edn::Value::PlainSymbol(e.clone()),
|
edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()),
|
||||||
edn::Value::PlainSymbol(a.clone()),
|
edn::Value::PlainSymbol(a.clone()),
|
||||||
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 {
|
OrJoin {
|
||||||
|
@ -577,16 +618,16 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_sp_variable() {
|
fn test_find_sp_variable() {
|
||||||
let sym = edn::PlainSymbol::new("?x");
|
let sym = edn::PlainSymbol::new("?x");
|
||||||
let input = [edn::Value::PlainSymbol(sym.clone())];
|
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(sym.clone())]);
|
||||||
assert_parses_to!(Query::variable, input, variable(sym));
|
assert_parses_to!(|| vector().of(Query::variable()), input, variable(sym));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_scalar() {
|
fn test_find_scalar() {
|
||||||
let sym = edn::PlainSymbol::new("?x");
|
let sym = edn::PlainSymbol::new("?x");
|
||||||
let period = edn::PlainSymbol::new(".");
|
let period = edn::PlainSymbol::new(".");
|
||||||
let input = [edn::Value::PlainSymbol(sym.clone()), edn::Value::PlainSymbol(period.clone())];
|
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(sym.clone()), edn::Value::PlainSymbol(period.clone())]);
|
||||||
assert_parses_to!(Find::find_scalar,
|
assert_parses_to!(|| vector().of(Find::find_scalar()),
|
||||||
input,
|
input,
|
||||||
FindSpec::FindScalar(Element::Variable(variable(sym))));
|
FindSpec::FindScalar(Element::Variable(variable(sym))));
|
||||||
}
|
}
|
||||||
|
@ -595,8 +636,8 @@ mod test {
|
||||||
fn test_find_coll() {
|
fn test_find_coll() {
|
||||||
let sym = edn::PlainSymbol::new("?x");
|
let sym = edn::PlainSymbol::new("?x");
|
||||||
let period = edn::PlainSymbol::new("...");
|
let period = edn::PlainSymbol::new("...");
|
||||||
let input = [edn::Value::Vector(vec![edn::Value::PlainSymbol(sym.clone()),
|
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(sym.clone()),
|
||||||
edn::Value::PlainSymbol(period.clone())])];
|
edn::Value::PlainSymbol(period.clone())]);
|
||||||
assert_parses_to!(Find::find_coll,
|
assert_parses_to!(Find::find_coll,
|
||||||
input,
|
input,
|
||||||
FindSpec::FindColl(Element::Variable(variable(sym))));
|
FindSpec::FindColl(Element::Variable(variable(sym))));
|
||||||
|
@ -606,8 +647,8 @@ mod test {
|
||||||
fn test_find_rel() {
|
fn test_find_rel() {
|
||||||
let vx = edn::PlainSymbol::new("?x");
|
let vx = edn::PlainSymbol::new("?x");
|
||||||
let vy = edn::PlainSymbol::new("?y");
|
let vy = edn::PlainSymbol::new("?y");
|
||||||
let input = [edn::Value::PlainSymbol(vx.clone()), edn::Value::PlainSymbol(vy.clone())];
|
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(vx.clone()), edn::Value::PlainSymbol(vy.clone())]);
|
||||||
assert_parses_to!(Find::find_rel,
|
assert_parses_to!(|| vector().of(Find::find_rel()),
|
||||||
input,
|
input,
|
||||||
FindSpec::FindRel(vec![Element::Variable(variable(vx)),
|
FindSpec::FindRel(vec![Element::Variable(variable(vx)),
|
||||||
Element::Variable(variable(vy))]));
|
Element::Variable(variable(vy))]));
|
||||||
|
@ -617,37 +658,11 @@ mod test {
|
||||||
fn test_find_tuple() {
|
fn test_find_tuple() {
|
||||||
let vx = edn::PlainSymbol::new("?x");
|
let vx = edn::PlainSymbol::new("?x");
|
||||||
let vy = edn::PlainSymbol::new("?y");
|
let vy = edn::PlainSymbol::new("?y");
|
||||||
let input = [edn::Value::Vector(vec![edn::Value::PlainSymbol(vx.clone()),
|
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(vx.clone()),
|
||||||
edn::Value::PlainSymbol(vy.clone())])];
|
edn::Value::PlainSymbol(vy.clone())]);
|
||||||
assert_parses_to!(Find::find_tuple,
|
assert_parses_to!(Find::find_tuple,
|
||||||
input,
|
input,
|
||||||
FindSpec::FindTuple(vec![Element::Variable(variable(vx)),
|
FindSpec::FindTuple(vec![Element::Variable(variable(vx)),
|
||||||
Element::Variable(variable(vy))]));
|
Element::Variable(variable(vy))]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_processing() {
|
|
||||||
let vx = edn::PlainSymbol::new("?x");
|
|
||||||
let vy = edn::PlainSymbol::new("?y");
|
|
||||||
let ellipsis = edn::PlainSymbol::new("...");
|
|
||||||
let period = edn::PlainSymbol::new(".");
|
|
||||||
|
|
||||||
let scalar = [edn::Value::PlainSymbol(vx.clone()), edn::Value::PlainSymbol(period.clone())];
|
|
||||||
let tuple = [edn::Value::Vector(vec![edn::Value::PlainSymbol(vx.clone()),
|
|
||||||
edn::Value::PlainSymbol(vy.clone())])];
|
|
||||||
let coll = [edn::Value::Vector(vec![edn::Value::PlainSymbol(vx.clone()),
|
|
||||||
edn::Value::PlainSymbol(ellipsis.clone())])];
|
|
||||||
let rel = [edn::Value::PlainSymbol(vx.clone()), edn::Value::PlainSymbol(vy.clone())];
|
|
||||||
|
|
||||||
assert_eq!(FindSpec::FindScalar(Element::Variable(variable(vx.clone()))),
|
|
||||||
find_seq_to_find_spec(&scalar).unwrap());
|
|
||||||
assert_eq!(FindSpec::FindTuple(vec![Element::Variable(variable(vx.clone())),
|
|
||||||
Element::Variable(variable(vy.clone()))]),
|
|
||||||
find_seq_to_find_spec(&tuple).unwrap());
|
|
||||||
assert_eq!(FindSpec::FindColl(Element::Variable(variable(vx.clone()))),
|
|
||||||
find_seq_to_find_spec(&coll).unwrap());
|
|
||||||
assert_eq!(FindSpec::FindRel(vec![Element::Variable(variable(vx.clone())),
|
|
||||||
Element::Variable(variable(vy.clone()))]),
|
|
||||||
find_seq_to_find_spec(&rel).unwrap());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
// Copyright 2016 Mozilla
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License. You may obtain a copy of the
|
|
||||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
extern crate edn;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
/// Take a slice of EDN values, as would be extracted from an
|
|
||||||
/// `edn::Value::Vector`, and turn it into a map.
|
|
||||||
///
|
|
||||||
/// The slice must consist of subsequences of an initial plain
|
|
||||||
/// keyword, followed by one or more non-plain-keyword values.
|
|
||||||
///
|
|
||||||
/// The plain keywords are used as keys into the resulting map.
|
|
||||||
/// The values are accumulated into vectors.
|
|
||||||
///
|
|
||||||
/// Invalid input causes this function to return `None`.
|
|
||||||
///
|
|
||||||
/// TODO: this function can be generalized to take an arbitrary
|
|
||||||
/// destructuring/break function, yielding a map with a custom
|
|
||||||
/// key type and splitting in the right places.
|
|
||||||
pub fn vec_to_keyword_map(vec: &[edn::Value]) -> Option<BTreeMap<edn::Keyword, Vec<edn::Value>>> {
|
|
||||||
let mut m = BTreeMap::new();
|
|
||||||
|
|
||||||
if vec.is_empty() {
|
|
||||||
return Some(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
if vec.len() == 1 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn something like
|
|
||||||
//
|
|
||||||
// `[:foo 1 2 3 :bar 4 5 6]`
|
|
||||||
//
|
|
||||||
// into
|
|
||||||
//
|
|
||||||
// `Some((:foo, [1 2 3]))`
|
|
||||||
fn step(slice: &[edn::Value]) -> Option<(edn::Keyword, Vec<edn::Value>)> {
|
|
||||||
// [:foo 1 2 3 :bar] is invalid: nothing follows `:bar`.
|
|
||||||
if slice.len() < 2 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The first item must be a keyword.
|
|
||||||
if let edn::Value::Keyword(ref k) = slice[0] {
|
|
||||||
|
|
||||||
// The second can't be: [:foo :bar 1 2 3] is invalid.
|
|
||||||
if slice[1].is_keyword() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accumulate items until we reach the next keyword.
|
|
||||||
let mut acc = Vec::new();
|
|
||||||
for v in &slice[1..] {
|
|
||||||
if v.is_keyword() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
acc.push(v.clone());
|
|
||||||
}
|
|
||||||
return Some((k.clone(), acc));
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut bits = vec;
|
|
||||||
while !bits.is_empty() {
|
|
||||||
match step(bits) {
|
|
||||||
Some((k, v)) => {
|
|
||||||
bits = &bits[(v.len() + 1)..];
|
|
||||||
|
|
||||||
// Duplicate keys aren't allowed.
|
|
||||||
if m.contains_key(&k) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
m.insert(k, v);
|
|
||||||
},
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Some(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vec_to_keyword_map() {
|
|
||||||
let foo = edn::symbols::Keyword("foo".to_string());
|
|
||||||
let bar = edn::symbols::Keyword("bar".to_string());
|
|
||||||
let baz = edn::symbols::Keyword("baz".to_string());
|
|
||||||
|
|
||||||
// [:foo 1 2 3 :bar 4]
|
|
||||||
let input = vec!(edn::Value::Keyword(foo.clone()),
|
|
||||||
edn::Value::Integer(1),
|
|
||||||
edn::Value::Integer(2),
|
|
||||||
edn::Value::Integer(3),
|
|
||||||
edn::Value::Keyword(bar.clone()),
|
|
||||||
edn::Value::Integer(4));
|
|
||||||
|
|
||||||
let m = vec_to_keyword_map(&input).unwrap();
|
|
||||||
|
|
||||||
assert!(m.contains_key(&foo));
|
|
||||||
assert!(m.contains_key(&bar));
|
|
||||||
assert!(!m.contains_key(&baz));
|
|
||||||
|
|
||||||
let onetwothree = vec!(edn::Value::Integer(1),
|
|
||||||
edn::Value::Integer(2),
|
|
||||||
edn::Value::Integer(3));
|
|
||||||
let four = vec!(edn::Value::Integer(4));
|
|
||||||
|
|
||||||
assert_eq!(m.get(&foo).unwrap(), &onetwothree);
|
|
||||||
assert_eq!(m.get(&bar).unwrap(), &four);
|
|
||||||
|
|
||||||
// Trailing keywords aren't allowed.
|
|
||||||
assert_eq!(None,
|
|
||||||
vec_to_keyword_map(&vec!(edn::Value::Keyword(foo.clone()))));
|
|
||||||
assert_eq!(None,
|
|
||||||
vec_to_keyword_map(&vec!(edn::Value::Keyword(foo.clone()),
|
|
||||||
edn::Value::Integer(2),
|
|
||||||
edn::Value::Keyword(bar.clone()))));
|
|
||||||
|
|
||||||
// Duplicate keywords aren't allowed.
|
|
||||||
assert_eq!(None,
|
|
||||||
vec_to_keyword_map(&vec!(edn::Value::Keyword(foo.clone()),
|
|
||||||
edn::Value::Integer(2),
|
|
||||||
edn::Value::Keyword(foo.clone()),
|
|
||||||
edn::Value::Integer(1))));
|
|
||||||
|
|
||||||
// Starting with anything but a keyword isn't allowed.
|
|
||||||
assert_eq!(None,
|
|
||||||
vec_to_keyword_map(&vec!(edn::Value::Integer(2),
|
|
||||||
edn::Value::Keyword(foo.clone()),
|
|
||||||
edn::Value::Integer(1))));
|
|
||||||
|
|
||||||
// Consecutive keywords aren't allowed.
|
|
||||||
assert_eq!(None,
|
|
||||||
vec_to_keyword_map(&vec!(edn::Value::Keyword(foo.clone()),
|
|
||||||
edn::Value::Keyword(bar.clone()),
|
|
||||||
edn::Value::Integer(1))));
|
|
||||||
|
|
||||||
// Empty lists return an empty map.
|
|
||||||
assert_eq!(BTreeMap::new(), vec_to_keyword_map(&vec!()).unwrap());
|
|
||||||
}
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ fn can_parse_simple_or() {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_parse_unit_or_join() {
|
fn can_parse_unit_or_join() {
|
||||||
let s = "[:find ?x . :where (or-join [?x] [?x _ 15])]";
|
let s = "[:find ?x . :where (or-join [?x] [?x _ 15])]";
|
||||||
let p = parse_find_string(s).unwrap();
|
let p = parse_find_string(s).expect("to be able to parse find");
|
||||||
|
|
||||||
assert_eq!(p.find_spec,
|
assert_eq!(p.find_spec,
|
||||||
FindSpec::FindScalar(Element::Variable(Variable::from_valid_name("?x"))));
|
FindSpec::FindScalar(Element::Variable(Variable::from_valid_name("?x"))));
|
||||||
|
|
|
@ -67,15 +67,15 @@ impl Variable {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromValue<T> {
|
pub trait FromValue<T> {
|
||||||
fn from_value(v: &edn::Value) -> Option<T>;
|
fn from_value(v: edn::ValueAndSpan) -> Option<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the provided EDN value is a PlainSymbol beginning with '?', return
|
/// If the provided EDN value is a PlainSymbol beginning with '?', return
|
||||||
/// it wrapped in a Variable. If not, return None.
|
/// it wrapped in a Variable. If not, return None.
|
||||||
/// TODO: intern strings. #398.
|
/// TODO: intern strings. #398.
|
||||||
impl FromValue<Variable> for Variable {
|
impl FromValue<Variable> for Variable {
|
||||||
fn from_value(v: &edn::Value) -> Option<Variable> {
|
fn from_value(v: edn::ValueAndSpan) -> Option<Variable> {
|
||||||
if let edn::Value::PlainSymbol(ref s) = *v {
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
Variable::from_symbol(s)
|
Variable::from_symbol(s)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -112,8 +112,8 @@ impl fmt::Debug for Variable {
|
||||||
pub struct PredicateFn(pub PlainSymbol);
|
pub struct PredicateFn(pub PlainSymbol);
|
||||||
|
|
||||||
impl FromValue<PredicateFn> for PredicateFn {
|
impl FromValue<PredicateFn> for PredicateFn {
|
||||||
fn from_value(v: &edn::Value) -> Option<PredicateFn> {
|
fn from_value(v: edn::ValueAndSpan) -> Option<PredicateFn> {
|
||||||
if let edn::Value::PlainSymbol(ref s) = *v {
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
PredicateFn::from_symbol(s)
|
PredicateFn::from_symbol(s)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -135,8 +135,8 @@ pub enum SrcVar {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue<SrcVar> for SrcVar {
|
impl FromValue<SrcVar> for SrcVar {
|
||||||
fn from_value(v: &edn::Value) -> Option<SrcVar> {
|
fn from_value(v: edn::ValueAndSpan) -> Option<SrcVar> {
|
||||||
if let edn::Value::PlainSymbol(ref s) = *v {
|
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
|
||||||
SrcVar::from_symbol(s)
|
SrcVar::from_symbol(s)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -184,16 +184,17 @@ pub enum FnArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue<FnArg> for FnArg {
|
impl FromValue<FnArg> for FnArg {
|
||||||
fn from_value(v: &edn::Value) -> Option<FnArg> {
|
fn from_value(v: edn::ValueAndSpan) -> Option<FnArg> {
|
||||||
// TODO: support SrcVars.
|
// TODO: support SrcVars.
|
||||||
Variable::from_value(v)
|
Variable::from_value(v.clone()) // TODO: don't clone!
|
||||||
.and_then(|v| Some(FnArg::Variable(v)))
|
.and_then(|v| Some(FnArg::Variable(v)))
|
||||||
.or_else(||
|
.or_else(|| {
|
||||||
match v {
|
println!("from_value {}", v.inner);
|
||||||
&edn::Value::Integer(i) => Some(FnArg::EntidOrInteger(i)),
|
match v.inner {
|
||||||
&edn::Value::Float(f) => Some(FnArg::Constant(NonIntegerConstant::Float(f))),
|
edn::SpannedValue::Integer(i) => Some(FnArg::EntidOrInteger(i)),
|
||||||
|
edn::SpannedValue::Float(f) => Some(FnArg::Constant(NonIntegerConstant::Float(f))),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
})
|
}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,14 +235,14 @@ impl PatternNonValuePlace {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
|
impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
|
||||||
fn from_value(v: &edn::Value) -> Option<PatternNonValuePlace> {
|
fn from_value(v: edn::ValueAndSpan) -> Option<PatternNonValuePlace> {
|
||||||
match v {
|
match v.inner {
|
||||||
&edn::Value::Integer(x) => if x >= 0 {
|
edn::SpannedValue::Integer(x) => if x >= 0 {
|
||||||
Some(PatternNonValuePlace::Entid(x))
|
Some(PatternNonValuePlace::Entid(x))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
&edn::Value::PlainSymbol(ref x) => if x.0.as_str() == "_" {
|
edn::SpannedValue::PlainSymbol(ref x) => if x.0.as_str() == "_" {
|
||||||
Some(PatternNonValuePlace::Placeholder)
|
Some(PatternNonValuePlace::Placeholder)
|
||||||
} else {
|
} else {
|
||||||
if let Some(v) = Variable::from_symbol(x) {
|
if let Some(v) = Variable::from_symbol(x) {
|
||||||
|
@ -250,7 +251,7 @@ impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&edn::Value::NamespacedKeyword(ref x) =>
|
edn::SpannedValue::NamespacedKeyword(ref x) =>
|
||||||
Some(PatternNonValuePlace::Ident(Rc::new(x.clone()))),
|
Some(PatternNonValuePlace::Ident(Rc::new(x.clone()))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -276,23 +277,23 @@ pub enum PatternValuePlace {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue<PatternValuePlace> for PatternValuePlace {
|
impl FromValue<PatternValuePlace> for PatternValuePlace {
|
||||||
fn from_value(v: &edn::Value) -> Option<PatternValuePlace> {
|
fn from_value(v: edn::ValueAndSpan) -> Option<PatternValuePlace> {
|
||||||
match v {
|
match v.inner {
|
||||||
&edn::Value::Integer(x) =>
|
edn::SpannedValue::Integer(x) =>
|
||||||
Some(PatternValuePlace::EntidOrInteger(x)),
|
Some(PatternValuePlace::EntidOrInteger(x)),
|
||||||
&edn::Value::PlainSymbol(ref x) if x.0.as_str() == "_" =>
|
edn::SpannedValue::PlainSymbol(ref x) if x.0.as_str() == "_" =>
|
||||||
Some(PatternValuePlace::Placeholder),
|
Some(PatternValuePlace::Placeholder),
|
||||||
&edn::Value::PlainSymbol(ref x) =>
|
edn::SpannedValue::PlainSymbol(ref x) =>
|
||||||
Variable::from_symbol(x).map(PatternValuePlace::Variable),
|
Variable::from_symbol(x).map(PatternValuePlace::Variable),
|
||||||
&edn::Value::NamespacedKeyword(ref x) =>
|
edn::SpannedValue::NamespacedKeyword(ref x) =>
|
||||||
Some(PatternValuePlace::IdentOrKeyword(Rc::new(x.clone()))),
|
Some(PatternValuePlace::IdentOrKeyword(Rc::new(x.clone()))),
|
||||||
&edn::Value::Boolean(x) =>
|
edn::SpannedValue::Boolean(x) =>
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::Boolean(x))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::Boolean(x))),
|
||||||
&edn::Value::Float(x) =>
|
edn::SpannedValue::Float(x) =>
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::Float(x))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::Float(x))),
|
||||||
&edn::Value::BigInteger(ref x) =>
|
edn::SpannedValue::BigInteger(ref x) =>
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::BigInteger(x.clone()))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::BigInteger(x.clone()))),
|
||||||
&edn::Value::Text(ref x) =>
|
edn::SpannedValue::Text(ref x) =>
|
||||||
// TODO: intern strings. #398.
|
// TODO: intern strings. #398.
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::Text(Rc::new(x.clone())))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::Text(Rc::new(x.clone())))),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -685,4 +686,4 @@ impl ContainsVariables for Pattern {
|
||||||
acc_ref(acc, v)
|
acc_ref(acc, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue