code cleanup, bugfixes
This commit is contained in:
parent
d8c89c7098
commit
c776290df8
|
@ -100,25 +100,26 @@ struct pred : seq< and_pred, star< or_ext > > {};
|
||||||
struct ParserState
|
struct ParserState
|
||||||
{
|
{
|
||||||
std::vector<Predicate *> predicate_stack;
|
std::vector<Predicate *> predicate_stack;
|
||||||
Predicate *current() { return predicate_stack.back(); }
|
Predicate ¤t() {
|
||||||
|
return *predicate_stack.back();
|
||||||
|
}
|
||||||
bool negate_next;
|
bool negate_next;
|
||||||
|
|
||||||
void addExpression(Expression exp)
|
void addExpression(Expression exp)
|
||||||
{
|
{
|
||||||
if (current()->type == Predicate::Type::Comparison) {
|
if (current().type == Predicate::Type::Comparison) {
|
||||||
current()->sub_expressions.emplace_back(std::move(exp));
|
current().cmpr.expr[1] = std::move(exp);
|
||||||
predicate_stack.pop_back();
|
predicate_stack.pop_back();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Predicate p;
|
Predicate p(Predicate::Type::Comparison);
|
||||||
p.type = Predicate::Type::Comparison;
|
p.cmpr.expr[0] = std::move(exp);
|
||||||
p.sub_expressions.emplace_back(std::move(exp));
|
|
||||||
if (negate_next) {
|
if (negate_next) {
|
||||||
p.negate = true;
|
p.negate = true;
|
||||||
negate_next = false;
|
negate_next = false;
|
||||||
}
|
}
|
||||||
current()->sub_predicates.emplace_back(std::move(p));
|
current().cpnd.sub_predicates.emplace_back(std::move(p));
|
||||||
predicate_stack.push_back(¤t()->sub_predicates.back());
|
predicate_stack.push_back(¤t().cpnd.sub_predicates.back());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -134,24 +135,24 @@ template<> struct action< and_ext >
|
||||||
std::cout << "<and>" << in.string() << std::endl;
|
std::cout << "<and>" << in.string() << std::endl;
|
||||||
|
|
||||||
// if we were put into an OR group we need to rearrange
|
// if we were put into an OR group we need to rearrange
|
||||||
auto current = state.current();
|
auto ¤t = state.current();
|
||||||
if (current->type == Predicate::Type::Or) {
|
if (current.type == Predicate::Type::Or) {
|
||||||
auto &sub_preds = state.current()->sub_predicates;
|
auto &sub_preds = state.current().cpnd.sub_predicates;
|
||||||
auto second_last = sub_preds[sub_preds.size()-2];
|
auto &second_last = sub_preds[sub_preds.size()-2];
|
||||||
if (second_last.type == Predicate::Type::And) {
|
if (second_last.type == Predicate::Type::And) {
|
||||||
// if we are in an OR group and second to last predicate group is
|
// if we are in an OR group and second to last predicate group is
|
||||||
// an AND group then move the last predicate inside
|
// an AND group then move the last predicate inside
|
||||||
second_last.sub_predicates.push_back(sub_preds.back());
|
second_last.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));
|
||||||
sub_preds.pop_back();
|
sub_preds.pop_back();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// otherwise combine last two into a new AND group
|
// otherwise combine last two into a new AND group
|
||||||
Predicate pred;
|
Predicate pred(Predicate::Type::And);
|
||||||
pred.type = Predicate::Type::And;
|
pred.cpnd.sub_predicates.emplace_back(std::move(second_last));
|
||||||
pred.sub_predicates = { second_last, sub_preds.back() };
|
pred.cpnd.sub_predicates.emplace_back(std::move(sub_preds.back()));
|
||||||
sub_preds.pop_back();
|
sub_preds.pop_back();
|
||||||
sub_preds.pop_back();
|
sub_preds.pop_back();
|
||||||
sub_preds.push_back(pred);
|
sub_preds.push_back(std::move(pred));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,27 +165,27 @@ template<> struct action< or_ext >
|
||||||
std::cout << "<or>" << in.string() << std::endl;
|
std::cout << "<or>" << in.string() << std::endl;
|
||||||
|
|
||||||
// if already an OR group do nothing
|
// if already an OR group do nothing
|
||||||
auto current = state.current();
|
auto ¤t = state.current();
|
||||||
if (current->type == Predicate::Type::Or) {
|
if (current.type == Predicate::Type::Or) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if only two predicates in the group, then convert to OR
|
// if only two predicates in the group, then convert to OR
|
||||||
auto &sub_preds = state.current()->sub_predicates;
|
auto &sub_preds = state.current().cpnd.sub_predicates;
|
||||||
if (sub_preds.size()) {
|
if (sub_preds.size()) {
|
||||||
current->type = Predicate::Type::Or;
|
current.type = Predicate::Type::Or;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// split the current group into to groups which are ORed together
|
// split the current group into to groups which are ORed together
|
||||||
Predicate pred1, pred2;
|
Predicate pred1(Predicate::Type::And), pred2(Predicate::Type::And);
|
||||||
pred1.type = Predicate::Type::And;
|
pred1.cpnd.sub_predicates.insert(sub_preds.begin(), sub_preds.back());
|
||||||
pred2.type = Predicate::Type::And;
|
pred2.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));
|
||||||
pred1.sub_predicates.insert(sub_preds.begin(), sub_preds.back());
|
|
||||||
pred2.sub_predicates.push_back(sub_preds.back());
|
|
||||||
|
|
||||||
current->type = Predicate::Type::Or;
|
current.type = Predicate::Type::Or;
|
||||||
sub_preds = { pred1, pred2 };
|
sub_preds.clear();
|
||||||
|
sub_preds.emplace_back(std::move(pred1));
|
||||||
|
sub_preds.emplace_back(std::move(pred2));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -249,9 +250,8 @@ template<> struct action< true_pred >
|
||||||
static void apply( const input & in, ParserState & state )
|
static void apply( const input & in, ParserState & state )
|
||||||
{
|
{
|
||||||
std::cout << in.string() << std::endl;
|
std::cout << in.string() << std::endl;
|
||||||
Predicate pred;
|
Predicate pred(Predicate::Type::True);
|
||||||
pred.type = Predicate::Type::True;
|
state.current().cpnd.sub_predicates.push_back(std::move(pred));
|
||||||
state.current()->sub_predicates.push_back(std::move(pred));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -260,9 +260,8 @@ template<> struct action< false_pred >
|
||||||
static void apply( const input & in, ParserState & state )
|
static void apply( const input & in, ParserState & state )
|
||||||
{
|
{
|
||||||
std::cout << in.string() << std::endl;
|
std::cout << in.string() << std::endl;
|
||||||
Predicate pred;
|
Predicate pred(Predicate::Type::False);
|
||||||
pred.type = Predicate::Type::False;
|
state.current().cpnd.sub_predicates.push_back(std::move(pred));
|
||||||
state.current()->sub_predicates.push_back(std::move(pred));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,7 +269,7 @@ template<> struct action< false_pred >
|
||||||
template<> struct action< rule > { \
|
template<> struct action< rule > { \
|
||||||
static void apply( const input & in, ParserState & state ) { \
|
static void apply( const input & in, ParserState & state ) { \
|
||||||
std::cout << in.string() << std::endl; \
|
std::cout << in.string() << std::endl; \
|
||||||
state.current()->op = oper; }};
|
state.current().cmpr.op = oper; }};
|
||||||
|
|
||||||
OPERATOR_ACTION(eq, Predicate::Operator::Equal)
|
OPERATOR_ACTION(eq, Predicate::Operator::Equal)
|
||||||
OPERATOR_ACTION(noteq, Predicate::Operator::NotEqual)
|
OPERATOR_ACTION(noteq, Predicate::Operator::NotEqual)
|
||||||
|
@ -289,15 +288,14 @@ template<> struct action< one< '(' > >
|
||||||
{
|
{
|
||||||
std::cout << "<begin_group>" << std::endl;
|
std::cout << "<begin_group>" << std::endl;
|
||||||
|
|
||||||
Predicate group;
|
Predicate group(Predicate::Type::And);
|
||||||
group.type = Predicate::Type::And;
|
|
||||||
if (state.negate_next) {
|
if (state.negate_next) {
|
||||||
group.negate = true;
|
group.negate = true;
|
||||||
state.negate_next = false;
|
state.negate_next = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.current()->sub_predicates.emplace_back(std::move(group));
|
state.current().cpnd.sub_predicates.emplace_back(std::move(group));
|
||||||
state.predicate_stack.push_back(&state.current()->sub_predicates.back());
|
state.predicate_stack.push_back(&state.current().cpnd.sub_predicates.back());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,21 +324,19 @@ Predicate parse(const std::string &query)
|
||||||
analyze< pred >();
|
analyze< pred >();
|
||||||
const std::string source = "user query";
|
const std::string source = "user query";
|
||||||
|
|
||||||
Predicate out_predicate;
|
Predicate out_predicate(Predicate::Type::And);
|
||||||
out_predicate.type = Predicate::Type::And;
|
|
||||||
|
|
||||||
ParserState state;
|
ParserState state;
|
||||||
state.predicate_stack.push_back(&out_predicate);
|
state.predicate_stack.push_back(&out_predicate);
|
||||||
|
|
||||||
pegtl::parse< must< pred, eof >, action >(query, source, state);
|
pegtl::parse< must< pred, eof >, action >(query, source, state);
|
||||||
if (out_predicate.type == Predicate::Type::And && out_predicate.sub_predicates.size() == 1) {
|
if (out_predicate.type == Predicate::Type::And && out_predicate.cpnd.sub_predicates.size() == 1) {
|
||||||
return out_predicate.sub_predicates.back();
|
return std::move(out_predicate.cpnd.sub_predicates.back());
|
||||||
}
|
}
|
||||||
return out_predicate;
|
return std::move(out_predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// check a precondition and throw an exception if it is not met
|
// check a precondition and throw an exception if it is not met
|
||||||
// this should be used iff the condition being false indicates a bug in the caller
|
// this should be used iff the condition being false indicates a bug in the caller
|
||||||
// of the function checking its preconditions
|
// of the function checking its preconditions
|
||||||
|
@ -618,14 +614,15 @@ template <typename... T>
|
||||||
void add_comparison_to_query(Query &query, Predicate &pred, Schema &schema, ObjectSchema &object_schema)
|
void add_comparison_to_query(Query &query, Predicate &pred, Schema &schema, ObjectSchema &object_schema)
|
||||||
{
|
{
|
||||||
std::vector<size_t> indexes;
|
std::vector<size_t> indexes;
|
||||||
auto t0 = pred.sub_expressions[0].type, t1 = pred.sub_expressions[1].type;
|
Predicate::Comparison &cmpr = pred.cmpr;
|
||||||
|
auto t0 = cmpr.expr[0].type, t1 = cmpr.expr[1].type;
|
||||||
if (t0 == Expression::Type::KeyPath && t1 != Expression::Type::KeyPath) {
|
if (t0 == Expression::Type::KeyPath && t1 != Expression::Type::KeyPath) {
|
||||||
Property *prop = get_property_from_key_path(schema, object_schema, pred.sub_expressions[0].s, indexes);
|
Property *prop = get_property_from_key_path(schema, object_schema, cmpr.expr[0].s, indexes);
|
||||||
do_add_comparison_to_query(query, schema, object_schema, prop, pred.op, indexes, prop->table_column, pred.sub_expressions[1].s);
|
do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, prop->table_column, cmpr.expr[1].s);
|
||||||
}
|
}
|
||||||
else if (t0 != Expression::Type::KeyPath && t1 == Expression::Type::KeyPath) {
|
else if (t0 != Expression::Type::KeyPath && t1 == Expression::Type::KeyPath) {
|
||||||
Property *prop = get_property_from_key_path(schema, object_schema, pred.sub_expressions[1].s, indexes);
|
Property *prop = get_property_from_key_path(schema, object_schema, cmpr.expr[1].s, indexes);
|
||||||
do_add_comparison_to_query(query, schema, object_schema, prop, pred.op, indexes, pred.sub_expressions[0].s, prop->table_column);
|
do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, cmpr.expr[0].s, prop->table_column);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
||||||
|
@ -641,10 +638,10 @@ void update_query_with_predicate(Query &query, Predicate &pred, Schema &schema,
|
||||||
switch (pred.type) {
|
switch (pred.type) {
|
||||||
case Predicate::Type::And:
|
case Predicate::Type::And:
|
||||||
query.group();
|
query.group();
|
||||||
for (auto &sub : pred.sub_predicates) {
|
for (auto &sub : pred.cpnd.sub_predicates) {
|
||||||
update_query_with_predicate(query, sub, schema, object_schema);
|
update_query_with_predicate(query, sub, schema, object_schema);
|
||||||
}
|
}
|
||||||
if (!pred.sub_predicates.size()) {
|
if (!pred.cpnd.sub_predicates.size()) {
|
||||||
query.and_query(new TrueExpression);
|
query.and_query(new TrueExpression);
|
||||||
}
|
}
|
||||||
query.end_group();
|
query.end_group();
|
||||||
|
@ -652,11 +649,11 @@ void update_query_with_predicate(Query &query, Predicate &pred, Schema &schema,
|
||||||
|
|
||||||
case Predicate::Type::Or:
|
case Predicate::Type::Or:
|
||||||
query.group();
|
query.group();
|
||||||
for (auto &sub : pred.sub_predicates) {
|
for (auto &sub : pred.cpnd.sub_predicates) {
|
||||||
query.Or();
|
query.Or();
|
||||||
update_query_with_predicate(query, sub, schema, object_schema);
|
update_query_with_predicate(query, sub, schema, object_schema);
|
||||||
}
|
}
|
||||||
if (!pred.sub_predicates.size()) {
|
if (!pred.cpnd.sub_predicates.size()) {
|
||||||
query.and_query(new FalseExpression);
|
query.and_query(new FalseExpression);
|
||||||
}
|
}
|
||||||
query.end_group();
|
query.end_group();
|
||||||
|
|
|
@ -29,33 +29,21 @@ namespace realm {
|
||||||
namespace parser {
|
namespace parser {
|
||||||
struct Expression
|
struct Expression
|
||||||
{
|
{
|
||||||
enum class Type
|
enum class Type { Number, String, KeyPath } type;
|
||||||
{
|
|
||||||
Number,
|
|
||||||
String,
|
|
||||||
KeyPath,
|
|
||||||
};
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Predicate
|
struct Predicate
|
||||||
{
|
{
|
||||||
enum class Type
|
enum class Type {
|
||||||
{
|
|
||||||
None,
|
|
||||||
Comparison,
|
Comparison,
|
||||||
Or,
|
Or,
|
||||||
And,
|
And,
|
||||||
True,
|
True,
|
||||||
False,
|
False
|
||||||
};
|
} type = Type::And;
|
||||||
Type type = Type::None;
|
|
||||||
|
|
||||||
// for comparison
|
enum class Operator {
|
||||||
enum class Operator
|
|
||||||
{
|
|
||||||
None,
|
None,
|
||||||
Equal,
|
Equal,
|
||||||
NotEqual,
|
NotEqual,
|
||||||
|
@ -65,15 +53,25 @@ namespace realm {
|
||||||
GreaterThanOrEqual,
|
GreaterThanOrEqual,
|
||||||
BeginsWith,
|
BeginsWith,
|
||||||
EndsWith,
|
EndsWith,
|
||||||
Contains,
|
Contains
|
||||||
};
|
};
|
||||||
Operator op = Operator::None;
|
|
||||||
std::vector<Expression> sub_expressions;
|
|
||||||
|
|
||||||
// for compounds
|
struct Comparison {
|
||||||
std::vector<Predicate> sub_predicates;
|
Operator op = Operator::None;
|
||||||
|
Expression expr[2];
|
||||||
|
~Comparison() {}
|
||||||
|
};
|
||||||
|
|
||||||
bool negate;
|
struct Compound {
|
||||||
|
std::vector<Predicate> sub_predicates;
|
||||||
|
};
|
||||||
|
|
||||||
|
Comparison cmpr;
|
||||||
|
Compound cpnd;
|
||||||
|
|
||||||
|
bool negate = false;
|
||||||
|
|
||||||
|
Predicate(Type t) : type(t) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Predicate parse(const std::string &query);
|
Predicate parse(const std::string &query);
|
||||||
|
|
Loading…
Reference in New Issue