Lower parsing complexity for binary values and idioms (#2475)
This commit is contained in:
parent
b350f052a7
commit
76b962eb6e
4 changed files with 83 additions and 44 deletions
|
@ -50,7 +50,7 @@ impl Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Augment an existing expression
|
/// Augment an existing expression
|
||||||
fn augment(mut self, l: Value, o: Operator) -> Self {
|
pub(crate) fn augment(mut self, l: Value, o: Operator) -> Self {
|
||||||
match &mut self {
|
match &mut self {
|
||||||
Self::Binary {
|
Self::Binary {
|
||||||
l: left,
|
l: left,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::err::Error;
|
||||||
use crate::sql::common::commas;
|
use crate::sql::common::commas;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::fmt::{fmt_separated_by, Fmt};
|
use crate::sql::fmt::{fmt_separated_by, Fmt};
|
||||||
use crate::sql::part::{all, field, first, graph, index, last, part, start, Part};
|
use crate::sql::part::{all, field, first, graph, index, last, part, Part};
|
||||||
use crate::sql::part::{flatten, Next};
|
use crate::sql::part::{flatten, Next};
|
||||||
use crate::sql::paths::{ID, IN, META, OUT};
|
use crate::sql::paths::{ID, IN, META, OUT};
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -210,8 +210,21 @@ pub fn plain(i: &str) -> IResult<&str, Idiom> {
|
||||||
Ok((i, Idiom::from(v)))
|
Ok((i, Idiom::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A complex idiom with graph or many parts
|
/// Reparse a value which might part of an idiom.
|
||||||
pub fn multi(i: &str) -> IResult<&str, Idiom> {
|
pub fn reparse_idiom_start(start: Value, i: &str) -> IResult<&str, Value> {
|
||||||
|
if start.can_start_idiom() {
|
||||||
|
if let (i, Some(mut parts)) = opt(many1(part))(i)? {
|
||||||
|
let start = Part::Start(start);
|
||||||
|
parts.insert(0, start);
|
||||||
|
let v = Value::from(Idiom::from(parts));
|
||||||
|
return Ok((i, v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((i, start))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A complex idiom with graph or many parts excluding idioms which start with a value.
|
||||||
|
pub fn multi_without_start(i: &str) -> IResult<&str, Idiom> {
|
||||||
alt((
|
alt((
|
||||||
|i| {
|
|i| {
|
||||||
let (i, p) = graph(i)?;
|
let (i, p) = graph(i)?;
|
||||||
|
@ -220,7 +233,7 @@ pub fn multi(i: &str) -> IResult<&str, Idiom> {
|
||||||
Ok((i, Idiom::from(v)))
|
Ok((i, Idiom::from(v)))
|
||||||
},
|
},
|
||||||
|i| {
|
|i| {
|
||||||
let (i, p) = alt((first, start))(i)?;
|
let (i, p) = first(i)?;
|
||||||
let (i, mut v) = many1(part)(i)?;
|
let (i, mut v) = many1(part)(i)?;
|
||||||
v.insert(0, p);
|
v.insert(0, p);
|
||||||
Ok((i, Idiom::from(v)))
|
Ok((i, Idiom::from(v)))
|
||||||
|
@ -239,7 +252,21 @@ pub fn path(i: &str) -> IResult<&str, Idiom> {
|
||||||
/// A full complex idiom with any number of parts
|
/// A full complex idiom with any number of parts
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn idiom(i: &str) -> IResult<&str, Idiom> {
|
pub fn idiom(i: &str) -> IResult<&str, Idiom> {
|
||||||
alt((plain, multi))(i)
|
use nom::combinator::fail;
|
||||||
|
|
||||||
|
use crate::sql::value::value;
|
||||||
|
|
||||||
|
alt((
|
||||||
|
plain,
|
||||||
|
alt((multi_without_start, |i| {
|
||||||
|
let (i, v) = value(i)?;
|
||||||
|
let (i, v) = reparse_idiom_start(v, i)?;
|
||||||
|
if let Value::Idiom(x) = v {
|
||||||
|
return Ok((i, x));
|
||||||
|
}
|
||||||
|
fail(i)
|
||||||
|
})),
|
||||||
|
))(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -217,11 +217,6 @@ pub fn value(i: &str) -> IResult<&str, Part> {
|
||||||
Ok((i, Part::Value(v)))
|
Ok((i, Part::Value(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(i: &str) -> IResult<&str, Part> {
|
|
||||||
let (i, v) = value::start(i)?;
|
|
||||||
Ok((i, Part::Start(v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn graph(i: &str) -> IResult<&str, Part> {
|
pub fn graph(i: &str) -> IResult<&str, Part> {
|
||||||
let (i, v) = graph::graph(i)?;
|
let (i, v) = graph::graph(i)?;
|
||||||
Ok((i, Part::Graph(v)))
|
Ok((i, Part::Graph(v)))
|
||||||
|
|
|
@ -20,11 +20,11 @@ use crate::sql::ending::keyword;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::expression::{binary, unary, Expression};
|
use crate::sql::expression::{binary, unary, Expression};
|
||||||
use crate::sql::fmt::{Fmt, Pretty};
|
use crate::sql::fmt::{Fmt, Pretty};
|
||||||
use crate::sql::function::{self, function, Function};
|
use crate::sql::function::{function, Function};
|
||||||
use crate::sql::future::{future, Future};
|
use crate::sql::future::{future, Future};
|
||||||
use crate::sql::geometry::{geometry, Geometry};
|
use crate::sql::geometry::{geometry, Geometry};
|
||||||
use crate::sql::id::{Gen, Id};
|
use crate::sql::id::{Gen, Id};
|
||||||
use crate::sql::idiom::{self, Idiom};
|
use crate::sql::idiom::{self, reparse_idiom_start, Idiom};
|
||||||
use crate::sql::kind::Kind;
|
use crate::sql::kind::Kind;
|
||||||
use crate::sql::model::{model, Model};
|
use crate::sql::model::{model, Model};
|
||||||
use crate::sql::number::decimal_is_integer;
|
use crate::sql::number::decimal_is_integer;
|
||||||
|
@ -40,7 +40,7 @@ use crate::sql::subquery::{subquery, Subquery};
|
||||||
use crate::sql::table::{table, Table};
|
use crate::sql::table::{table, Table};
|
||||||
use crate::sql::thing::{thing, Thing};
|
use crate::sql::thing::{thing, Thing};
|
||||||
use crate::sql::uuid::{uuid as unique, Uuid};
|
use crate::sql::uuid::{uuid as unique, Uuid};
|
||||||
use crate::sql::Query;
|
use crate::sql::{operator, Query};
|
||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use derive::Store;
|
use derive::Store;
|
||||||
|
@ -1044,6 +1044,25 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns if this value can be the start of a idiom production.
|
||||||
|
pub fn can_start_idiom(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Value::Function(x) => !x.is_script(),
|
||||||
|
Value::Subquery(_)
|
||||||
|
| Value::Constant(_)
|
||||||
|
| Value::Datetime(_)
|
||||||
|
| Value::Duration(_)
|
||||||
|
| Value::Uuid(_)
|
||||||
|
| Value::Number(_)
|
||||||
|
| Value::Object(_)
|
||||||
|
| Value::Array(_)
|
||||||
|
| Value::Param(_)
|
||||||
|
| Value::Edges(_)
|
||||||
|
| Value::Thing(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to convert this Value into a set of JSONPatch operations
|
/// Try to convert this Value into a set of JSONPatch operations
|
||||||
pub fn to_operations(&self) -> Result<Vec<Operation>, Error> {
|
pub fn to_operations(&self) -> Result<Vec<Operation>, Error> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -2709,12 +2728,27 @@ impl TryNeg for Value {
|
||||||
|
|
||||||
/// Parse any `Value` including expressions
|
/// Parse any `Value` including expressions
|
||||||
pub fn value(i: &str) -> IResult<&str, Value> {
|
pub fn value(i: &str) -> IResult<&str, Value> {
|
||||||
alt((map(binary, Value::from), single))(i)
|
let (i, start) = single(i)?;
|
||||||
|
let (i, expr_tail) = opt(|i| {
|
||||||
|
let (i, o) = operator::binary(i)?;
|
||||||
|
let (i, r) = value(i)?;
|
||||||
|
Ok((i, (o, r)))
|
||||||
|
})(i)?;
|
||||||
|
let v = if let Some((o, r)) = expr_tail {
|
||||||
|
let expr = match r {
|
||||||
|
Value::Expression(r) => r.augment(start, o),
|
||||||
|
_ => Expression::new(start, o, r),
|
||||||
|
};
|
||||||
|
Value::from(expr)
|
||||||
|
} else {
|
||||||
|
start
|
||||||
|
};
|
||||||
|
Ok((i, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse any `Value` excluding binary expressions
|
/// Parse any `Value` excluding binary expressions
|
||||||
pub fn single(i: &str) -> IResult<&str, Value> {
|
pub fn single(i: &str) -> IResult<&str, Value> {
|
||||||
alt((
|
let (i, v) = alt((
|
||||||
alt((
|
alt((
|
||||||
terminated(
|
terminated(
|
||||||
alt((
|
alt((
|
||||||
|
@ -2725,7 +2759,7 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
||||||
)),
|
)),
|
||||||
keyword,
|
keyword,
|
||||||
),
|
),
|
||||||
map(idiom::multi, Value::from),
|
map(idiom::multi_without_start, Value::from),
|
||||||
)),
|
)),
|
||||||
alt((
|
alt((
|
||||||
map(cast, Value::from),
|
map(cast, Value::from),
|
||||||
|
@ -2753,11 +2787,12 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
||||||
map(strand, Value::from),
|
map(strand, Value::from),
|
||||||
map(idiom::path, Value::from),
|
map(idiom::path, Value::from),
|
||||||
)),
|
)),
|
||||||
))(i)
|
))(i)?;
|
||||||
|
reparse_idiom_start(v, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(i: &str) -> IResult<&str, Value> {
|
pub fn select(i: &str) -> IResult<&str, Value> {
|
||||||
alt((
|
let (i, v) = alt((
|
||||||
alt((
|
alt((
|
||||||
map(unary, Value::from),
|
map(unary, Value::from),
|
||||||
map(binary, Value::from),
|
map(binary, Value::from),
|
||||||
|
@ -2765,7 +2800,7 @@ pub fn select(i: &str) -> IResult<&str, Value> {
|
||||||
map(tag_no_case("NULL"), |_| Value::Null),
|
map(tag_no_case("NULL"), |_| Value::Null),
|
||||||
map(tag_no_case("true"), |_| Value::Bool(true)),
|
map(tag_no_case("true"), |_| Value::Bool(true)),
|
||||||
map(tag_no_case("false"), |_| Value::Bool(false)),
|
map(tag_no_case("false"), |_| Value::Bool(false)),
|
||||||
map(idiom::multi, Value::from),
|
map(idiom::multi_without_start, Value::from),
|
||||||
)),
|
)),
|
||||||
alt((
|
alt((
|
||||||
map(cast, Value::from),
|
map(cast, Value::from),
|
||||||
|
@ -2790,33 +2825,14 @@ pub fn select(i: &str) -> IResult<&str, Value> {
|
||||||
map(table, Value::from),
|
map(table, Value::from),
|
||||||
map(strand, Value::from),
|
map(strand, Value::from),
|
||||||
)),
|
)),
|
||||||
))(i)
|
))(i)?;
|
||||||
}
|
reparse_idiom_start(v, i)
|
||||||
|
|
||||||
/// Used as the starting part of a complex Idiom
|
|
||||||
pub fn start(i: &str) -> IResult<&str, Value> {
|
|
||||||
alt((
|
|
||||||
map(function::normal, Value::from),
|
|
||||||
map(function::custom, Value::from),
|
|
||||||
map(subquery, Value::from),
|
|
||||||
map(constant, Value::from),
|
|
||||||
map(datetime, Value::from),
|
|
||||||
map(duration, Value::from),
|
|
||||||
map(unique, Value::from),
|
|
||||||
map(number, Value::from),
|
|
||||||
map(strand, Value::from),
|
|
||||||
map(object, Value::from),
|
|
||||||
map(array, Value::from),
|
|
||||||
map(param, Value::from),
|
|
||||||
map(edges, Value::from),
|
|
||||||
map(thing, Value::from),
|
|
||||||
))(i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used in CREATE, UPDATE, and DELETE clauses
|
/// Used in CREATE, UPDATE, and DELETE clauses
|
||||||
pub fn what(i: &str) -> IResult<&str, Value> {
|
pub fn what(i: &str) -> IResult<&str, Value> {
|
||||||
alt((
|
let (i, v) = alt((
|
||||||
map(idiom::multi, Value::from),
|
map(idiom::multi_without_start, Value::from),
|
||||||
map(function, Value::from),
|
map(function, Value::from),
|
||||||
map(subquery, Value::from),
|
map(subquery, Value::from),
|
||||||
map(constant, Value::from),
|
map(constant, Value::from),
|
||||||
|
@ -2830,7 +2846,8 @@ pub fn what(i: &str) -> IResult<&str, Value> {
|
||||||
map(range, Value::from),
|
map(range, Value::from),
|
||||||
map(thing, Value::from),
|
map(thing, Value::from),
|
||||||
map(table, Value::from),
|
map(table, Value::from),
|
||||||
))(i)
|
))(i)?;
|
||||||
|
reparse_idiom_start(v, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to parse any simple JSON-like value
|
/// Used to parse any simple JSON-like value
|
||||||
|
|
Loading…
Reference in a new issue