Part 3: Use value_and_span apparatus in query-parser/.

This commit is contained in:
Nick Alexander 2017-03-28 18:04:59 -07:00
parent e947a32c59
commit ff136b2546
6 changed files with 346 additions and 749 deletions

View file

@ -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)],
}),
]);
}
}

View file

@ -21,19 +21,12 @@ extern crate edn;
#[macro_use]
extern crate mentat_parser_utils;
mod util;
mod parse;
pub mod find;
pub use find::{
parse_find,
parse_find_string,
};
pub use parse::{
Error,
ErrorKind,
QueryParseResult,
Result,
ResultExt,
parse_find_string,
};

View file

@ -13,14 +13,27 @@ extern crate edn;
extern crate mentat_parser_utils;
extern crate mentat_query;
use self::combine::{eof, many, many1, optional, parser, satisfy_map, Parser, ParseResult, Stream};
use self::combine::combinator::{choice, try};
use std; // To refer to std::result::Result.
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::{
ResultParser,
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::{
Element,
FindQuery,
@ -50,17 +63,17 @@ error_chain! {
}
errors {
NotAVariableError(value: edn::Value) {
NotAVariableError(value: edn::ValueAndSpan) {
description("not a variable")
display("not a variable: '{}'", value)
}
FindParseError(e: ValueParseError) {
FindParseError(e: combine::ParseError<ValueStream>) {
description(":find parse error")
display(":find parse error")
}
WhereParseError(e: ValueParseError) {
WhereParseError(e: combine::ParseError<ValueStream>) {
description(":where parse error")
display(":where parse error")
}
@ -83,321 +96,349 @@ error_chain! {
}
}
pub type WhereParseResult = Result<Vec<WhereClause>>;
pub type FindParseResult = Result<FindSpec>;
pub type QueryParseResult = Result<FindQuery>;
pub struct Query;
pub struct Query<I>(::std::marker::PhantomData<fn(I) -> I>);
def_parser!(Query, variable, Variable, {
satisfy_map(Variable::from_value)
});
impl<I> Query<I>
where I: Stream<Item = edn::Value>
{
fn to_parsed_value<T>(r: ParseResult<T, I>) -> Option<T> {
r.ok().map(|x| x.0)
}
}
def_parser!(Query, source_var, SrcVar, {
satisfy_map(SrcVar::from_value)
});
// TODO: interning.
def_value_satisfy_parser_fn!(Query, variable, Variable, Variable::from_value);
def_value_satisfy_parser_fn!(Query, source_var, SrcVar, SrcVar::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);
def_parser!(Query, predicate_fn, PredicateFn, {
satisfy_map(PredicateFn::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,
pattern_value_place,
PatternValuePlace,
PatternValuePlace::from_value);
def_value_satisfy_parser_fn!(Where,
pattern_non_value_place,
PatternNonValuePlace,
PatternNonValuePlace::from_value);
def_parser!(Query, arguments, Vec<FnArg>, {
(many::<Vec<FnArg>, _>(Query::fn_arg()))
});
fn seq<T: Into<Option<edn::Value>>>(x: T) -> Option<Vec<edn::Value>> {
match x.into() {
Some(edn::Value::List(items)) => Some(items.into_iter().collect()),
Some(edn::Value::Vector(items)) => Some(items),
_ => None,
}
}
pub struct Where;
/// Take a vector Value containing one vector Value, and return the `Vec` inside the inner vector.
/// Also accepts an inner list, returning it as a `Vec`.
fn unwrap_nested(x: edn::Value) -> Option<Vec<edn::Value>> {
match x {
edn::Value::Vector(mut v) => {
seq(v.pop())
def_parser!(Where, pattern_value_place, PatternValuePlace, {
satisfy_map(PatternValuePlace::from_value)
});
def_parser!(Where, pattern_non_value_place, PatternNonValuePlace, {
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, {
matches_plain_symbol!("or", input)
def_parser!(Where, or, edn::ValueAndSpan, {
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, {
matches_plain_symbol!("or-join", input)
def_parser!(Where, or_join, edn::ValueAndSpan, {
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, {
satisfy_map(|x: edn::Value| {
seq(x).and_then(|items| {
let mut p = many1(Query::variable()).skip(eof());
Query::to_parsed_value(p.parse_lazy(&items[..]).into())
})}).parse_stream(input)
def_parser!(Where, rule_vars, Vec<Variable>, {
seq()
.of(many1(Query::variable()))
});
def_value_parser_fn!(Where, or_pattern_clause, OrWhereClause, input, {
Where::clause().map(|clause| OrWhereClause::Clause(clause)).parse_stream(input)
def_parser!(Where, or_pattern_clause, OrWhereClause, {
Where::clause().map(|clause| OrWhereClause::Clause(clause))
});
def_value_parser_fn!(Where, or_and_clause, OrWhereClause, input, {
satisfy_map(|x: edn::Value| {
seq(x).and_then(|items| {
let mut p = Where::and()
.with(many1(Where::clause()))
.skip(eof())
.map(OrWhereClause::And);
let r: ParseResult<OrWhereClause, _> = p.parse_lazy(&items[..]).into();
Query::to_parsed_value(r)
})
}).parse_stream(input)
def_parser!(Where, or_and_clause, OrWhereClause, {
seq()
.of(Where::and()
.with(many1(Where::clause()))
.map(OrWhereClause::And))
});
def_value_parser_fn!(Where, or_where_clause, OrWhereClause, input, {
choice([Where::or_pattern_clause(), Where::or_and_clause()]).parse_stream(input)
def_parser!(Where, or_where_clause, OrWhereClause, {
choice([Where::or_pattern_clause(), Where::or_and_clause()])
});
def_value_parser_fn!(Where, or_clause, WhereClause, input, {
satisfy_map(|x: edn::Value| {
seq(x).and_then(|items| {
let mut p = Where::or()
.with(many1(Where::or_where_clause()))
.skip(eof())
.map(|clauses| {
WhereClause::OrJoin(
OrJoin {
unify_vars: UnifyVars::Implicit,
clauses: clauses,
})
});
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
Query::to_parsed_value(r)
})
}).parse_stream(input)
def_parser!(Where, or_clause, WhereClause, {
seq()
.of(Where::or()
.with(many1(Where::or_where_clause()))
.map(|clauses| {
WhereClause::OrJoin(
OrJoin {
unify_vars: UnifyVars::Implicit,
clauses: clauses,
})
}))
});
def_value_parser_fn!(Where, or_join_clause, WhereClause, input, {
satisfy_map(|x: edn::Value| {
seq(x).and_then(|items| {
let mut p = Where::or_join()
.with(Where::rule_vars())
.and(many1(Where::or_where_clause()))
.skip(eof())
.map(|(vars, clauses)| {
WhereClause::OrJoin(
OrJoin {
unify_vars: UnifyVars::Explicit(vars),
clauses: clauses,
})
});
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
Query::to_parsed_value(r)
})
}).parse_stream(input)
def_parser!(Where, or_join_clause, WhereClause, {
seq()
.of(Where::or_join()
.with(Where::rule_vars())
.and(many1(Where::or_where_clause()))
.map(|(vars, clauses)| {
WhereClause::OrJoin(
OrJoin {
unify_vars: UnifyVars::Explicit(vars),
clauses: clauses,
})
}))
});
/// A vector containing just a parenthesized filter expression.
def_value_parser_fn!(Where, pred, WhereClause, input, {
satisfy_map(|x: edn::Value| {
// Accept either a list or a vector here:
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
unwrap_nested(x).and_then(|items| {
let mut p = (Query::predicate_fn(), Query::arguments())
.skip(eof())
.map(|(f, args)| {
WhereClause::Pred(
Predicate {
operator: f.0,
args: args,
})
});
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
Query::to_parsed_value(r)
})
}).parse_stream(input)
def_parser!(Where, pred, WhereClause, {
// Accept either a nested list or a nested vector here:
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
vector()
.of(seq()
.of((Query::predicate_fn(), Query::arguments())
.map(|(f, args)| {
WhereClause::Pred(
Predicate {
operator: f.0,
args: args,
})
})))
});
def_value_parser_fn!(Where, pattern, WhereClause, input, {
satisfy_map(|x: edn::Value| {
if let edn::Value::Vector(y) = x {
def_parser!(Where, pattern, WhereClause, {
vector()
.of(
// While *technically* Datomic allows you to have a query like:
// [:find … :where [[?x]]]
// We don't -- we require at least e, a.
let mut p = (optional(Query::source_var()), // src
Where::pattern_non_value_place(), // e
Where::pattern_non_value_place(), // a
optional(Where::pattern_value_place()), // v
optional(Where::pattern_non_value_place())) // tx
.skip(eof())
.map(|(src, e, a, v, tx)| {
let v = v.unwrap_or(PatternValuePlace::Placeholder);
let tx = tx.unwrap_or(PatternNonValuePlace::Placeholder);
(optional(Query::source_var()), // src
Where::pattern_non_value_place(), // e
Where::pattern_non_value_place(), // a
optional(Where::pattern_value_place()), // v
optional(Where::pattern_non_value_place())) // tx
.and_then(|(src, e, a, v, tx)| {
let v = v.unwrap_or(PatternValuePlace::Placeholder);
let tx = tx.unwrap_or(PatternNonValuePlace::Placeholder);
// Pattern::new takes care of reversal of reversed
// attributes: [?x :foo/_bar ?y] turns into
// [?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
//
// ```edn
// [?x :foo/_reversed 23.4]
// ```
//
// because
//
// ```edn
// [23.4 :foo/reversed ?x]
// ```
//
// is nonsense. That leaves us with nested optionals; we unwrap them here.
let r: ParseResult<Option<WhereClause>, _> = p.parse_lazy(&y[..]).into();
let v: Option<Option<WhereClause>> = Query::to_parsed_value(r);
v.unwrap_or(None)
} else {
None
}
}).parse_stream(input)
// Pattern::new takes care of reversal of reversed
// attributes: [?x :foo/_bar ?y] turns into
// [?y :foo/bar ?x].
//
// 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]
// ```
//
// because
//
// ```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)
.map(WhereClause::Pattern)
.ok_or(combine::primitives::Error::Expected("pattern".into()))
}))
});
def_value_parser_fn!(Query, arguments, Vec<FnArg>, input, {
(many::<Vec<FnArg>, _>(Query::fn_arg()))
.skip(eof())
.parse_stream(input)
});
def_value_parser_fn!(Where, clause, WhereClause, input, {
choice([Where::pattern(),
Where::pred(),
def_parser!(Where, clause, WhereClause, {
choice([try(Where::pattern()),
// It's either
// (or-join [vars] clauses…)
// or
// (or clauses…)
// We don't yet handle source vars.
Where::or_join_clause(),
Where::or_clause(),
]).parse_stream(input)
try(Where::or_join_clause()),
try(Where::or_clause()),
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.
(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, {
matches_plain_symbol!(".", input)
/// TODO: extract macro for matching these `PlainSymbol` instances.
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, {
matches_plain_symbol!("...", input)
def_parser!(Find, ellipsis, 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, find_scalar, FindSpec, input, {
def_parser!(Find, find_scalar, FindSpec, {
Query::variable()
.map(|var| FindSpec::FindScalar(Element::Variable(var)))
.skip(Find::period())
.skip(eof())
.map(|var| FindSpec::FindScalar(Element::Variable(var)))
.parse_stream(input)
});
def_value_parser_fn!(Find, find_coll, FindSpec, input, {
satisfy_unwrap!(edn::Value::Vector, y, {
let mut p = Query::variable()
.skip(Find::ellipsis())
.skip(eof())
.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_parser!(Find, find_coll, FindSpec, {
vector()
.of(Query::variable()
.map(|var| FindSpec::FindColl(Element::Variable(var)))
.skip(Find::ellipsis()))
});
def_value_parser_fn!(Find, elements, Vec<Element>, input, {
many1::<Vec<Variable>, _>(Query::variable()).skip(eof())
.map(|vars| {
vars.into_iter()
.map(Element::Variable)
.collect()
})
.parse_stream(input)
def_parser!(Find, elements, Vec<Element>, {
many1::<Vec<Element>, _>(Query::variable().map(Element::Variable))
});
def_value_parser_fn!(Find, find_rel, FindSpec, input, {
Find::elements().map(FindSpec::FindRel).parse_stream(input)
def_parser!(Find, find_rel, FindSpec, {
Find::elements().map(FindSpec::FindRel)
});
def_value_parser_fn!(Find, find_tuple, FindSpec, input, {
satisfy_unwrap!(edn::Value::Vector, y, {
let r: ParseResult<FindSpec, _> =
Find::elements().map(FindSpec::FindTuple).parse_lazy(&y[..]).into();
Query::to_parsed_value(r)
})
.parse_stream(input)
def_parser!(Find, find_tuple, FindSpec, {
vector()
.of(Find::elements().map(FindSpec::FindTuple))
});
def_value_parser_fn!(Find, find, FindSpec, input, {
// 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 = I, Output = FindSpec>; 4], _>
/// Parse a stream values into one of four find specs.
///
/// `: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
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_coll()),
&mut try(Find::find_tuple()),
&mut try(Find::find_rel())])
.parse_stream(input)
});
// Parse a sequence of values into one of four find specs.
//
// `: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
//
#[allow(dead_code)]
pub fn find_seq_to_find_spec(find: &[edn::Value]) -> FindParseResult {
Find::find()
.parse(find)
.map(|x| x.0)
.map_err::<ValueParseError, _>(|e| e.translate_position(find).into())
.map_err(|e| Error::from_kind(ErrorKind::FindParseError(e)))
/// TODO: extract macro for matching these `Keyword` instances.
def_parser!(Find, literal_find, edn::ValueAndSpan, {
satisfy(|v: edn::ValueAndSpan| {
if let edn::SpannedValue::Keyword(ref s) = v.inner {
s.0.as_str() == "find"
} else {
false
}
})
});
def_parser!(Find, literal_with, edn::ValueAndSpan, {
satisfy(|v: edn::ValueAndSpan| {
if let edn::SpannedValue::Keyword(ref s) = v.inner {
s.0.as_str() == "with"
} else {
false
}
})
});
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)]
pub fn clause_seq_to_patterns(clauses: &[edn::Value]) -> WhereParseResult {
Where::clauses()
.parse(clauses)
/// 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.
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_err::<ValueParseError, _>(|e| e.translate_position(clauses).into())
.map_err(|e| Error::from_kind(ErrorKind::WhereParseError(e)))
.map_err(|e| Error::from_kind(ErrorKind::FindParseError(e)))
}
#[cfg(test)]
@ -441,10 +482,10 @@ mod test {
let a = edn::NamespacedKeyword::new("foo", "bar");
let v = OrderedFloat(99.9);
let tx = edn::PlainSymbol::new("?tx");
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
edn::Value::NamespacedKeyword(a.clone()),
edn::Value::Float(v.clone()),
edn::Value::PlainSymbol(tx.clone())))];
let input = edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
edn::Value::NamespacedKeyword(a.clone()),
edn::Value::Float(v.clone()),
edn::Value::PlainSymbol(tx.clone())));
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
source: None,
entity: PatternNonValuePlace::Placeholder,
@ -461,11 +502,11 @@ mod test {
let a = edn::PlainSymbol::new("?a");
let v = edn::PlainSymbol::new("?v");
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(a.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 {
source: Some(SrcVar::NamedSrc("x".to_string())),
entity: PatternNonValuePlace::Variable(variable(e)),
@ -481,13 +522,13 @@ mod test {
let a = edn::NamespacedKeyword::new("foo", "_bar");
let v = OrderedFloat(99.9);
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::Float(v.clone()),
edn::Value::PlainSymbol(tx.clone())))];
edn::Value::PlainSymbol(tx.clone())));
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.");
}
@ -497,10 +538,10 @@ mod test {
let a = edn::NamespacedKeyword::new("foo", "_bar");
let v = edn::PlainSymbol::new("?v");
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::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
// switched places.
@ -516,7 +557,7 @@ mod test {
#[test]
fn test_rule_vars() {
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,
vec![variable(e.clone())]);
}
@ -527,11 +568,11 @@ mod test {
let e = edn::PlainSymbol::new("?e");
let a = edn::PlainSymbol::new("?a");
let v = edn::PlainSymbol::new("?v");
let input = [edn::Value::List(
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())];
edn::Value::PlainSymbol(v.clone())])].into_iter().collect());
assert_parses_to!(Where::or_clause, input,
WhereClause::OrJoin(
OrJoin {
@ -553,12 +594,12 @@ mod test {
let e = edn::PlainSymbol::new("?e");
let a = edn::PlainSymbol::new("?a");
let v = edn::PlainSymbol::new("?v");
let input = [edn::Value::List(
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())];
edn::Value::PlainSymbol(v.clone())])].into_iter().collect());
assert_parses_to!(Where::or_join_clause, input,
WhereClause::OrJoin(
OrJoin {
@ -577,16 +618,16 @@ mod test {
#[test]
fn test_find_sp_variable() {
let sym = edn::PlainSymbol::new("?x");
let input = [edn::Value::PlainSymbol(sym.clone())];
assert_parses_to!(Query::variable, input, variable(sym));
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(sym.clone())]);
assert_parses_to!(|| vector().of(Query::variable()), input, variable(sym));
}
#[test]
fn test_find_scalar() {
let sym = edn::PlainSymbol::new("?x");
let period = edn::PlainSymbol::new(".");
let input = [edn::Value::PlainSymbol(sym.clone()), edn::Value::PlainSymbol(period.clone())];
assert_parses_to!(Find::find_scalar,
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(sym.clone()), edn::Value::PlainSymbol(period.clone())]);
assert_parses_to!(|| vector().of(Find::find_scalar()),
input,
FindSpec::FindScalar(Element::Variable(variable(sym))));
}
@ -595,8 +636,8 @@ mod test {
fn test_find_coll() {
let sym = edn::PlainSymbol::new("?x");
let period = edn::PlainSymbol::new("...");
let input = [edn::Value::Vector(vec![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_coll,
input,
FindSpec::FindColl(Element::Variable(variable(sym))));
@ -606,8 +647,8 @@ mod test {
fn test_find_rel() {
let vx = edn::PlainSymbol::new("?x");
let vy = edn::PlainSymbol::new("?y");
let input = [edn::Value::PlainSymbol(vx.clone()), edn::Value::PlainSymbol(vy.clone())];
assert_parses_to!(Find::find_rel,
let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(vx.clone()), edn::Value::PlainSymbol(vy.clone())]);
assert_parses_to!(|| vector().of(Find::find_rel()),
input,
FindSpec::FindRel(vec![Element::Variable(variable(vx)),
Element::Variable(variable(vy))]));
@ -617,37 +658,11 @@ mod test {
fn test_find_tuple() {
let vx = edn::PlainSymbol::new("?x");
let vy = edn::PlainSymbol::new("?y");
let input = [edn::Value::Vector(vec![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_tuple,
input,
FindSpec::FindTuple(vec![Element::Variable(variable(vx)),
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());
}
}

View file

@ -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());
}

View file

@ -97,7 +97,7 @@ fn can_parse_simple_or() {
#[test]
fn can_parse_unit_or_join() {
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,
FindSpec::FindScalar(Element::Variable(Variable::from_valid_name("?x"))));

View file

@ -67,15 +67,15 @@ impl Variable {
}
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
/// it wrapped in a Variable. If not, return None.
/// TODO: intern strings. #398.
impl FromValue<Variable> for Variable {
fn from_value(v: &edn::Value) -> Option<Variable> {
if let edn::Value::PlainSymbol(ref s) = *v {
fn from_value(v: edn::ValueAndSpan) -> Option<Variable> {
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
Variable::from_symbol(s)
} else {
None
@ -112,8 +112,8 @@ impl fmt::Debug for Variable {
pub struct PredicateFn(pub PlainSymbol);
impl FromValue<PredicateFn> for PredicateFn {
fn from_value(v: &edn::Value) -> Option<PredicateFn> {
if let edn::Value::PlainSymbol(ref s) = *v {
fn from_value(v: edn::ValueAndSpan) -> Option<PredicateFn> {
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
PredicateFn::from_symbol(s)
} else {
None
@ -135,8 +135,8 @@ pub enum SrcVar {
}
impl FromValue<SrcVar> for SrcVar {
fn from_value(v: &edn::Value) -> Option<SrcVar> {
if let edn::Value::PlainSymbol(ref s) = *v {
fn from_value(v: edn::ValueAndSpan) -> Option<SrcVar> {
if let edn::SpannedValue::PlainSymbol(ref s) = v.inner {
SrcVar::from_symbol(s)
} else {
None
@ -184,16 +184,17 @@ pub enum 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.
Variable::from_value(v)
Variable::from_value(v.clone()) // TODO: don't clone!
.and_then(|v| Some(FnArg::Variable(v)))
.or_else(||
match v {
&edn::Value::Integer(i) => Some(FnArg::EntidOrInteger(i)),
&edn::Value::Float(f) => Some(FnArg::Constant(NonIntegerConstant::Float(f))),
.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!(),
})
}})
}
}
@ -234,14 +235,14 @@ impl PatternNonValuePlace {
}
impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
fn from_value(v: &edn::Value) -> Option<PatternNonValuePlace> {
match v {
&edn::Value::Integer(x) => if x >= 0 {
fn from_value(v: edn::ValueAndSpan) -> Option<PatternNonValuePlace> {
match v.inner {
edn::SpannedValue::Integer(x) => if x >= 0 {
Some(PatternNonValuePlace::Entid(x))
} else {
None
},
&edn::Value::PlainSymbol(ref x) => if x.0.as_str() == "_" {
edn::SpannedValue::PlainSymbol(ref x) => if x.0.as_str() == "_" {
Some(PatternNonValuePlace::Placeholder)
} else {
if let Some(v) = Variable::from_symbol(x) {
@ -250,7 +251,7 @@ impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
None
}
},
&edn::Value::NamespacedKeyword(ref x) =>
edn::SpannedValue::NamespacedKeyword(ref x) =>
Some(PatternNonValuePlace::Ident(Rc::new(x.clone()))),
_ => None,
}
@ -276,23 +277,23 @@ pub enum PatternValuePlace {
}
impl FromValue<PatternValuePlace> for PatternValuePlace {
fn from_value(v: &edn::Value) -> Option<PatternValuePlace> {
match v {
&edn::Value::Integer(x) =>
fn from_value(v: edn::ValueAndSpan) -> Option<PatternValuePlace> {
match v.inner {
edn::SpannedValue::Integer(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),
&edn::Value::PlainSymbol(ref x) =>
edn::SpannedValue::PlainSymbol(ref x) =>
Variable::from_symbol(x).map(PatternValuePlace::Variable),
&edn::Value::NamespacedKeyword(ref x) =>
edn::SpannedValue::NamespacedKeyword(ref x) =>
Some(PatternValuePlace::IdentOrKeyword(Rc::new(x.clone()))),
&edn::Value::Boolean(x) =>
edn::SpannedValue::Boolean(x) =>
Some(PatternValuePlace::Constant(NonIntegerConstant::Boolean(x))),
&edn::Value::Float(x) =>
edn::SpannedValue::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()))),
&edn::Value::Text(ref x) =>
edn::SpannedValue::Text(ref x) =>
// TODO: intern strings. #398.
Some(PatternValuePlace::Constant(NonIntegerConstant::Text(Rc::new(x.clone())))),
_ => None,