Refactor ExpressionEvaluator to classic visitor

Reviewers: florijan, mislav.bradac, buda

Reviewed By: mislav.bradac

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D368
This commit is contained in:
Teon Banek 2017-05-16 10:55:02 +02:00
parent f74ba586b2
commit 23ab2b41a3
5 changed files with 318 additions and 304 deletions

View File

@ -14,10 +14,14 @@ namespace query {
class AstTreeStorage;
class Tree : public ::utils::Visitable<HierarchicalTreeVisitor> {
class Tree : public ::utils::Visitable<HierarchicalTreeVisitor>,
::utils::Visitable<TreeVisitor<TypedValue>> {
friend class AstTreeStorage;
public:
using ::utils::Visitable<HierarchicalTreeVisitor>::Accept;
using ::utils::Visitable<TreeVisitor<TypedValue>>::Accept;
int uid() const { return uid_; }
protected:
@ -63,6 +67,7 @@ class OrOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -78,6 +83,7 @@ class XorOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -93,6 +99,7 @@ class AndOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -112,6 +119,7 @@ class FilterAndOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -127,6 +135,7 @@ class AdditionOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -142,6 +151,7 @@ class SubtractionOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -157,6 +167,7 @@ class MultiplicationOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -172,6 +183,7 @@ class DivisionOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -187,6 +199,7 @@ class ModOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -202,6 +215,7 @@ class NotEqualOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -217,6 +231,7 @@ class EqualOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -232,6 +247,7 @@ class LessOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -247,6 +263,7 @@ class GreaterOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -262,6 +279,7 @@ class LessEqualOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -277,6 +295,7 @@ class GreaterEqualOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -292,6 +311,7 @@ class InListOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -307,6 +327,7 @@ class ListIndexingOperator : public BinaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -322,6 +343,7 @@ class ListSlicingOperator : public Expression {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = list_->Accept(visitor);
@ -352,6 +374,7 @@ class NotOperator : public UnaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -367,6 +390,7 @@ class UnaryPlusOperator : public UnaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -382,6 +406,7 @@ class UnaryMinusOperator : public UnaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -397,6 +422,7 @@ class IsNullOperator : public UnaryOperator {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -419,6 +445,7 @@ class PrimitiveLiteral : public BaseLiteral {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(HierarchicalTreeVisitor);
TypedValue value_;
@ -433,6 +460,7 @@ class ListLiteral : public BaseLiteral {
public:
const std::vector<Expression *> elements_;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto expr_ptr : elements_)
@ -451,6 +479,7 @@ class Identifier : public Expression {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(HierarchicalTreeVisitor);
std::string name_;
bool user_declared_ = true;
@ -465,6 +494,7 @@ class PropertyLookup : public Expression {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -492,6 +522,7 @@ class LabelsTest : public Expression {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -512,6 +543,7 @@ class EdgeTypeTest : public Expression {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -535,6 +567,7 @@ class Function : public Expression {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto *argument : arguments_) {
@ -567,6 +600,7 @@ class Aggregation : public UnaryOperator {
static const constexpr char *const kSum = "SUM";
static const constexpr char *const kAvg = "AVG";
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
if (expression_) {
@ -590,6 +624,7 @@ class NamedExpression : public Tree {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -623,6 +658,7 @@ class NodeAtom : public PatternAtom {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor);
@ -647,6 +683,7 @@ class EdgeAtom : public PatternAtom {
// necessarily go from left to right
enum class Direction { LEFT, RIGHT, BOTH };
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor);
@ -676,6 +713,7 @@ class Pattern : public Tree {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &part : atoms_) {
@ -695,6 +733,7 @@ class Query : public Tree {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &clause : clauses_) {
@ -715,6 +754,7 @@ class Create : public Clause {
public:
Create(int uid) : Clause(uid) {}
std::vector<Pattern *> patterns_;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &pattern : patterns_) {
@ -729,6 +769,7 @@ class Where : public Tree {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -746,6 +787,7 @@ class Match : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;
@ -795,6 +837,7 @@ class Return : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;
@ -828,6 +871,7 @@ class With : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;
@ -863,6 +907,7 @@ class Delete : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &expr : expressions_) {
@ -882,6 +927,7 @@ class SetProperty : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
property_lookup_->Accept(visitor) && expression_->Accept(visitor);
@ -903,6 +949,7 @@ class SetProperties : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor) && expression_->Accept(visitor);
@ -927,6 +974,7 @@ class SetLabels : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor);
@ -947,6 +995,7 @@ class RemoveProperty : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
property_lookup_->Accept(visitor);
@ -965,6 +1014,7 @@ class RemoveLabels : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor);
@ -985,6 +1035,7 @@ class Merge : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = pattern_->Accept(visitor);
@ -1020,6 +1071,7 @@ class Unwind : public Clause {
friend class AstTreeStorage;
public:
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
named_expression_->Accept(visitor);

View File

@ -77,4 +77,17 @@ class HierarchicalTreeVisitor : public TreeCompositeVisitor,
using TreeLeafVisitor::Visit;
};
template <typename TResult>
using TreeVisitor = ::utils::Visitor<
TResult, Query, NamedExpression, OrOperator, XorOperator, AndOperator,
FilterAndOperator, NotOperator, AdditionOperator, SubtractionOperator,
MultiplicationOperator, DivisionOperator, ModOperator, NotEqualOperator,
EqualOperator, LessOperator, GreaterOperator, LessEqualOperator,
GreaterEqualOperator, InListOperator, ListIndexingOperator,
ListSlicingOperator, UnaryPlusOperator, UnaryMinusOperator, IsNullOperator,
ListLiteral, PropertyLookup, LabelsTest, EdgeTypeTest, Aggregation,
Function, Create, Match, Return, With, Pattern, NodeAtom, EdgeAtom, Delete,
Where, SetProperty, SetProperties, SetLabels, RemoveProperty, RemoveLabels,
Merge, Unwind, Identifier, PrimitiveLiteral>;
} // namespace query

View File

@ -16,7 +16,7 @@
namespace query {
class ExpressionEvaluator : public HierarchicalTreeVisitor {
class ExpressionEvaluator : public TreeVisitor<TypedValue> {
public:
ExpressionEvaluator(Frame &frame, const SymbolTable &symbol_table,
GraphDbAccessor &db_accessor,
@ -26,50 +26,56 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
db_accessor_(db_accessor),
graph_view_(graph_view) {}
/**
* Removes and returns the last value from the result stack.
* Consumers of this function are PostVisit functions for
* expressions that consume subexpressions, as well as top
* level expression consumers.
*/
auto PopBack() {
debug_assert(result_stack_.size() > 0, "Result stack empty");
auto last = result_stack_.back();
result_stack_.pop_back();
return last;
using TreeVisitor<TypedValue>::Visit;
#define BLOCK_VISIT(TREE_TYPE) \
TypedValue Visit(TREE_TYPE &) override { \
permanent_fail("ExpressionEvaluator should not visit " #TREE_TYPE); \
}
using HierarchicalTreeVisitor::PreVisit;
using typename HierarchicalTreeVisitor::ReturnType;
using HierarchicalTreeVisitor::Visit;
using HierarchicalTreeVisitor::PostVisit;
BLOCK_VISIT(Query);
BLOCK_VISIT(Create);
BLOCK_VISIT(Match);
BLOCK_VISIT(Return);
BLOCK_VISIT(With);
BLOCK_VISIT(Pattern);
BLOCK_VISIT(NodeAtom);
BLOCK_VISIT(EdgeAtom);
BLOCK_VISIT(Delete);
BLOCK_VISIT(Where);
BLOCK_VISIT(SetProperty);
BLOCK_VISIT(SetProperties);
BLOCK_VISIT(SetLabels);
BLOCK_VISIT(RemoveProperty);
BLOCK_VISIT(RemoveLabels);
BLOCK_VISIT(Merge);
BLOCK_VISIT(Unwind);
bool PostVisit(NamedExpression &named_expression) override {
auto symbol = symbol_table_.at(named_expression);
frame_[symbol] = PopBack();
return true;
#undef BLOCK_VISIT
TypedValue Visit(NamedExpression &named_expression) override {
const auto &symbol = symbol_table_.at(named_expression);
auto value = named_expression.expression_->Accept(*this);
frame_[symbol] = value;
return value;
}
ReturnType Visit(Identifier &ident) override {
TypedValue Visit(Identifier &ident) override {
auto value = frame_[symbol_table_.at(ident)];
SwitchAccessors(value);
result_stack_.emplace_back(std::move(value));
return true;
return value;
}
#define BINARY_OPERATOR_VISITOR(OP_NODE, CPP_OP) \
bool PostVisit(OP_NODE &) override { \
auto expression2 = PopBack(); \
auto expression1 = PopBack(); \
result_stack_.push_back(expression1 CPP_OP expression2); \
return true; \
#define BINARY_OPERATOR_VISITOR(OP_NODE, CPP_OP) \
TypedValue Visit(OP_NODE &op) override { \
auto val1 = op.expression1_->Accept(*this); \
auto val2 = op.expression2_->Accept(*this); \
return val1 CPP_OP val2; \
}
#define UNARY_OPERATOR_VISITOR(OP_NODE, CPP_OP) \
bool PostVisit(OP_NODE &) override { \
auto expression = PopBack(); \
result_stack_.push_back(CPP_OP expression); \
return true; \
#define UNARY_OPERATOR_VISITOR(OP_NODE, CPP_OP) \
TypedValue Visit(OP_NODE &op) override { \
return CPP_OP op.expression_->Accept(*this); \
}
BINARY_OPERATOR_VISITOR(OrOperator, ||);
@ -94,34 +100,27 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
#undef BINARY_OPERATOR_VISITOR
#undef UNARY_OPERATOR_VISITOR
bool PreVisit(FilterAndOperator &op) override {
op.expression1_->Accept(*this);
auto expression1 = PopBack();
if (expression1.IsNull() || !expression1.Value<bool>()) {
TypedValue Visit(FilterAndOperator &op) override {
auto value1 = op.expression1_->Accept(*this);
if (value1.IsNull() || !value1.Value<bool>()) {
// If first expression is null or false, don't execute the second one.
result_stack_.emplace_back(expression1);
return false;
return value1;
}
op.expression2_->Accept(*this);
auto expression2 = PopBack();
result_stack_.emplace_back(expression2);
return false;
return op.expression2_->Accept(*this);
}
bool PostVisit(InListOperator &) override {
auto _list = PopBack();
auto literal = PopBack();
TypedValue Visit(InListOperator &in_list) override {
auto literal = in_list.expression1_->Accept(*this);
auto _list = in_list.expression2_->Accept(*this);
if (_list.IsNull()) {
result_stack_.emplace_back(TypedValue::Null);
return true;
return TypedValue::Null;
}
// Exceptions have higher priority than returning null.
// We need to convert list to its type before checking if literal is null,
// because conversion will throw exception if list conversion fails.
auto list = _list.Value<std::vector<TypedValue>>();
if (literal.IsNull()) {
result_stack_.emplace_back(TypedValue::Null);
return true;
return TypedValue::Null;
}
auto has_null = false;
for (const auto &element : list) {
@ -129,34 +128,30 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
if (result.IsNull()) {
has_null = true;
} else if (result.Value<bool>()) {
result_stack_.emplace_back(true);
return true;
}
}
if (has_null) {
result_stack_.emplace_back(TypedValue::Null);
} else {
result_stack_.emplace_back(false);
return TypedValue::Null;
}
return true;
return false;
}
bool PostVisit(ListIndexingOperator &) override {
TypedValue Visit(ListIndexingOperator &list_indexing) override {
// TODO: implement this for maps
auto _index = PopBack();
if (_index.type() != TypedValue::Type::Int &&
_index.type() != TypedValue::Type::Null) {
throw TypedValueException("Incompatible type in list lookup");
}
auto _list = PopBack();
auto _list = list_indexing.expression1_->Accept(*this);
if (_list.type() != TypedValue::Type::List &&
_list.type() != TypedValue::Type::Null) {
throw TypedValueException("Incompatible type in list lookup");
}
auto _index = list_indexing.expression2_->Accept(*this);
if (_index.type() != TypedValue::Type::Int &&
_index.type() != TypedValue::Type::Null) {
throw TypedValueException("Incompatible type in list lookup");
}
if (_index.type() == TypedValue::Type::Null ||
_list.type() == TypedValue::Type::Null) {
result_stack_.emplace_back(TypedValue::Null);
return true;
return TypedValue::Null;
}
auto index = _index.Value<int64_t>();
const auto &list = _list.Value<std::vector<TypedValue>>();
@ -164,20 +159,18 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
index = static_cast<int64_t>(list.size()) + index;
}
if (index >= static_cast<int64_t>(list.size()) || index < 0) {
result_stack_.emplace_back(TypedValue::Null);
return true;
return TypedValue::Null;
}
result_stack_.emplace_back(list[index]);
return true;
return list[index];
}
bool PostVisit(ListSlicingOperator &op) override {
TypedValue Visit(ListSlicingOperator &op) override {
// If some type is null we can't return null, because throwing exception on
// illegal type has higher priority.
auto is_null = false;
auto get_bound = [&](bool is_defined, int64_t default_value) {
if (is_defined) {
auto bound = PopBack();
auto get_bound = [&](Expression *bound_expr, int64_t default_value) {
if (bound_expr) {
auto bound = bound_expr->Accept(*this);
if (bound.type() == TypedValue::Type::Null) {
is_null = true;
} else if (bound.type() != TypedValue::Type::Int) {
@ -191,7 +184,7 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
get_bound(op.upper_bound_, std::numeric_limits<int64_t>::max());
auto _lower_bound = get_bound(op.lower_bound_, 0);
auto _list = PopBack();
auto _list = op.list_->Accept(*this);
if (_list.type() == TypedValue::Type::Null) {
is_null = true;
} else if (_list.type() != TypedValue::Type::List) {
@ -199,8 +192,7 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
}
if (is_null) {
result_stack_.emplace_back(TypedValue::Null);
return true;
return TypedValue::Null;
}
const auto &list = _list.Value<std::vector<TypedValue>>();
auto normalise_bound = [&](int64_t bound) {
@ -213,131 +205,105 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
auto lower_bound = normalise_bound(_lower_bound.Value<int64_t>());
auto upper_bound = normalise_bound(_upper_bound.Value<int64_t>());
if (upper_bound <= lower_bound) {
result_stack_.emplace_back(std::vector<TypedValue>());
return true;
return std::vector<TypedValue>();
}
result_stack_.emplace_back(std::vector<TypedValue>(
list.begin() + lower_bound, list.begin() + upper_bound));
return true;
return std::vector<TypedValue>(list.begin() + lower_bound,
list.begin() + upper_bound);
}
bool PostVisit(IsNullOperator &) override {
auto expression = PopBack();
result_stack_.push_back(TypedValue(expression.IsNull()));
return true;
TypedValue Visit(IsNullOperator &is_null) override {
auto value = is_null.expression_->Accept(*this);
return value.IsNull();
}
bool PostVisit(PropertyLookup &property_lookup) override {
auto expression_result = PopBack();
TypedValue Visit(PropertyLookup &property_lookup) override {
auto expression_result = property_lookup.expression_->Accept(*this);
switch (expression_result.type()) {
case TypedValue::Type::Null:
result_stack_.emplace_back(TypedValue::Null);
break;
return TypedValue::Null;
case TypedValue::Type::Vertex:
result_stack_.emplace_back(
expression_result.Value<VertexAccessor>().PropsAt(
property_lookup.property_));
break;
case TypedValue::Type::Edge: {
result_stack_.emplace_back(
expression_result.Value<EdgeAccessor>().PropsAt(
property_lookup.property_));
break;
}
return expression_result.Value<VertexAccessor>().PropsAt(
property_lookup.property_);
case TypedValue::Type::Edge:
return expression_result.Value<EdgeAccessor>().PropsAt(
property_lookup.property_);
case TypedValue::Type::Map:
// TODO implement me
throw utils::NotYetImplemented();
break;
throw utils::NotYetImplemented(
"Not yet implemented property lookup on map");
default:
throw TypedValueException(
"Expected Node, Edge or Map for property lookup");
}
return true;
}
bool PostVisit(LabelsTest &labels_test) override {
auto expression_result = PopBack();
TypedValue Visit(LabelsTest &labels_test) override {
auto expression_result = labels_test.expression_->Accept(*this);
switch (expression_result.type()) {
case TypedValue::Type::Null:
result_stack_.emplace_back(TypedValue::Null);
break;
return TypedValue::Null;
case TypedValue::Type::Vertex: {
auto vertex = expression_result.Value<VertexAccessor>();
for (const auto label : labels_test.labels_) {
if (!vertex.has_label(label)) {
result_stack_.emplace_back(false);
return true;
return false;
}
}
result_stack_.emplace_back(true);
break;
return true;
}
default:
throw TypedValueException("Expected Node in labels test");
}
return true;
}
bool PostVisit(EdgeTypeTest &edge_type_test) override {
auto expression_result = PopBack();
TypedValue Visit(EdgeTypeTest &edge_type_test) override {
auto expression_result = edge_type_test.expression_->Accept(*this);
switch (expression_result.type()) {
case TypedValue::Type::Null:
result_stack_.emplace_back(TypedValue::Null);
break;
return TypedValue::Null;
case TypedValue::Type::Edge: {
auto real_edge_type =
expression_result.Value<EdgeAccessor>().edge_type();
for (const auto edge_type : edge_type_test.edge_types_) {
if (edge_type == real_edge_type) {
result_stack_.emplace_back(true);
return true;
}
}
result_stack_.emplace_back(false);
break;
return false;
}
default:
throw TypedValueException("Expected Edge in edge type test");
}
return true;
}
ReturnType Visit(PrimitiveLiteral &literal) override {
TypedValue Visit(PrimitiveLiteral &literal) override {
// TODO: no need to evaluate constants, we can write it to frame in one
// of the previous phases.
result_stack_.push_back(literal.value_);
return true;
return literal.value_;
}
bool PostVisit(ListLiteral &literal) override {
TypedValue Visit(ListLiteral &literal) override {
std::vector<TypedValue> result;
result.reserve(literal.elements_.size());
for (size_t i = 0; i < literal.elements_.size(); i++)
result.emplace_back(PopBack());
std::reverse(result.begin(), result.end());
result_stack_.emplace_back(std::move(result));
return true;
for (const auto &expression : literal.elements_)
result.emplace_back(expression->Accept(*this));
return result;
}
bool PreVisit(Aggregation &aggregation) override {
TypedValue Visit(Aggregation &aggregation) override {
auto value = frame_[symbol_table_.at(aggregation)];
// Aggregation is probably always simple type, but let's switch accessor
// just to be sure.
SwitchAccessors(value);
result_stack_.emplace_back(std::move(value));
// Prevent evaluation of expressions inside the aggregation.
return false;
return value;
}
bool PostVisit(Function &function) override {
TypedValue Visit(Function &function) override {
std::vector<TypedValue> arguments;
for (int i = 0; i < static_cast<int>(function.arguments_.size()); ++i) {
arguments.push_back(PopBack());
for (const auto &argument : function.arguments_) {
arguments.emplace_back(argument->Accept(*this));
}
reverse(arguments.begin(), arguments.end());
result_stack_.emplace_back(function.function_(arguments, db_accessor_));
return true;
return function.function_(arguments, db_accessor_);
}
private:
@ -394,6 +360,6 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor {
GraphDbAccessor &db_accessor_;
// which switching approach should be used when evaluating
const GraphView graph_view_;
std::list<TypedValue> result_stack_;
};
}
} // namespace query

View File

@ -66,8 +66,7 @@ void CreateNode::CreateNodeCursor::Create(Frame &frame,
// setting properties on new nodes.
ExpressionEvaluator evaluator(frame, symbol_table, db_, GraphView::NEW);
for (auto &kv : self_.node_atom_->properties_) {
kv.second->Accept(evaluator);
new_node.PropsSet(kv.first, evaluator.PopBack());
new_node.PropsSet(kv.first, kv.second->Accept(evaluator));
}
frame[symbol_table.at(*self_.node_atom_->identifier_)] = new_node;
}
@ -142,8 +141,7 @@ VertexAccessor &CreateExpand::CreateExpandCursor::OtherVertex(
auto node = db_.insert_vertex();
for (auto label : self_.node_atom_->labels_) node.add_label(label);
for (auto kv : self_.node_atom_->properties_) {
kv.second->Accept(evaluator);
node.PropsSet(kv.first, evaluator.PopBack());
node.PropsSet(kv.first, kv.second->Accept(evaluator));
}
auto symbol = symbol_table.at(*self_.node_atom_->identifier_);
frame[symbol] = node;
@ -157,8 +155,7 @@ void CreateExpand::CreateExpandCursor::CreateEdge(
EdgeAccessor edge =
db_.insert_edge(from, to, self_.edge_atom_->edge_types_[0]);
for (auto kv : self_.edge_atom_->properties_) {
kv.second->Accept(evaluator);
edge.PropsSet(kv.first, evaluator.PopBack());
edge.PropsSet(kv.first, kv.second->Accept(evaluator));
}
frame[symbol_table.at(*self_.edge_atom_->identifier_)] = edge;
}
@ -369,8 +366,7 @@ bool Filter::FilterCursor::Pull(Frame &frame, const SymbolTable &symbol_table) {
// and edges.
ExpressionEvaluator evaluator(frame, symbol_table, db_, GraphView::OLD);
while (input_cursor_->Pull(frame, symbol_table)) {
self_.expression_->Accept(evaluator);
TypedValue result = evaluator.PopBack();
TypedValue result = self_.expression_->Accept(evaluator);
if (result.IsNull() || !result.Value<bool>()) continue;
return true;
}
@ -444,8 +440,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, const SymbolTable &symbol_table) {
std::vector<TypedValue> expression_results;
expression_results.reserve(self_.expressions_.size());
for (Expression *expression : self_.expressions_) {
expression->Accept(evaluator);
expression_results.emplace_back(evaluator.PopBack());
expression_results.emplace_back(expression->Accept(evaluator));
}
// delete edges first
@ -503,10 +498,8 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame,
// Set, just like Create needs to see the latest changes.
ExpressionEvaluator evaluator(frame, symbol_table, db_, GraphView::NEW);
self_.lhs_->expression_->Accept(evaluator);
TypedValue lhs = evaluator.PopBack();
self_.rhs_->Accept(evaluator);
TypedValue rhs = evaluator.PopBack();
TypedValue lhs = self_.lhs_->expression_->Accept(evaluator);
TypedValue rhs = self_.rhs_->Accept(evaluator);
// TODO the following code uses implicit TypedValue to PropertyValue
// conversion which throws a TypedValueException if impossible
@ -551,8 +544,7 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame,
// Set, just like Create needs to see the latest changes.
ExpressionEvaluator evaluator(frame, symbol_table, db_, GraphView::NEW);
self_.rhs_->Accept(evaluator);
TypedValue rhs = evaluator.PopBack();
TypedValue rhs = self_.rhs_->Accept(evaluator);
switch (lhs.type()) {
case TypedValue::Type::Vertex:
@ -657,8 +649,7 @@ bool RemoveProperty::RemovePropertyCursor::Pull(
// Remove, just like Delete needs to see the latest changes.
ExpressionEvaluator evaluator(frame, symbol_table, db_, GraphView::NEW);
self_.lhs_->expression_->Accept(evaluator);
TypedValue lhs = evaluator.PopBack();
TypedValue lhs = self_.lhs_->expression_->Accept(evaluator);
switch (lhs.type()) {
case TypedValue::Type::Vertex:
@ -910,8 +901,7 @@ void Aggregate::AggregateCursor::ProcessOne(Frame &frame,
// create the group-by list of values
std::list<TypedValue> group_by;
for (Expression *expression : self_.group_by_) {
expression->Accept(evaluator);
group_by.emplace_back(evaluator.PopBack());
group_by.emplace_back(expression->Accept(evaluator));
}
AggregationValue &agg_value = aggregation_[group_by];
@ -961,8 +951,7 @@ void Aggregate::AggregateCursor::Update(
continue;
}
input_expr_ptr->Accept(evaluator);
TypedValue input_value = evaluator.PopBack();
TypedValue input_value = input_expr_ptr->Accept(evaluator);
// Aggregations skip Null input values.
if (input_value.IsNull()) continue;
@ -1086,8 +1075,7 @@ bool Skip::SkipCursor::Pull(Frame &frame, const SymbolTable &symbol_table) {
// first successful pull from the input
// evaluate the skip expression
ExpressionEvaluator evaluator(frame, symbol_table, db_);
self_.expression_->Accept(evaluator);
TypedValue to_skip = evaluator.PopBack();
TypedValue to_skip = self_.expression_->Accept(evaluator);
if (to_skip.type() != TypedValue::Type::Int)
throw QueryRuntimeException("Result of SKIP expression must be an int");
@ -1134,8 +1122,7 @@ bool Limit::LimitCursor::Pull(Frame &frame, const SymbolTable &symbol_table) {
// is not allowed to contain any identifiers
if (limit_ == -1) {
ExpressionEvaluator evaluator(frame, symbol_table, db_);
self_.expression_->Accept(evaluator);
TypedValue limit = evaluator.PopBack();
TypedValue limit = self_.expression_->Accept(evaluator);
if (limit.type() != TypedValue::Type::Int)
throw QueryRuntimeException("Result of LIMIT expression must be an int");
@ -1194,8 +1181,7 @@ bool OrderBy::OrderByCursor::Pull(Frame &frame,
// collect the order_by elements
std::list<TypedValue> order_by;
for (auto expression_ptr : self_.order_by_) {
expression_ptr->Accept(evaluator);
order_by.emplace_back(evaluator.PopBack());
order_by.emplace_back(expression_ptr->Accept(evaluator));
}
// collect the output elements
@ -1456,8 +1442,7 @@ bool Unwind::UnwindCursor::Pull(Frame &frame, const SymbolTable &symbol_table) {
// successful pull from input, initialize value and iterator
ExpressionEvaluator evaluator(frame, symbol_table, db_);
self_.input_expression_->Accept(evaluator);
TypedValue input_value = evaluator.PopBack();
TypedValue input_value = self_.input_expression_->Accept(evaluator);
if (input_value.type() != TypedValue::Type::List)
throw QueryRuntimeException("UNWIND only accepts list values");
input_value_ = input_value.Value<std::vector<TypedValue>>();

View File

@ -44,8 +44,7 @@ TypedValue EvaluateFunction(const std::string &function_name,
}
auto *op =
storage.Create<Function>(NameToFunction(function_name), expressions);
op->Accept(eval.eval);
return eval.eval.PopBack();
return op->Accept(eval.eval);
}
TEST(ExpressionEvaluator, OrOperator) {
@ -54,12 +53,12 @@ TEST(ExpressionEvaluator, OrOperator) {
auto *op =
storage.Create<OrOperator>(storage.Create<PrimitiveLiteral>(true),
storage.Create<PrimitiveLiteral>(false));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), true);
op = storage.Create<OrOperator>(storage.Create<PrimitiveLiteral>(true),
storage.Create<PrimitiveLiteral>(true));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), true);
}
TEST(ExpressionEvaluator, XorOperator) {
@ -68,12 +67,12 @@ TEST(ExpressionEvaluator, XorOperator) {
auto *op =
storage.Create<XorOperator>(storage.Create<PrimitiveLiteral>(true),
storage.Create<PrimitiveLiteral>(false));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), true);
op = storage.Create<XorOperator>(storage.Create<PrimitiveLiteral>(true),
storage.Create<PrimitiveLiteral>(true));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), false);
}
TEST(ExpressionEvaluator, AndOperator) {
@ -82,12 +81,12 @@ TEST(ExpressionEvaluator, AndOperator) {
auto *op =
storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(true),
storage.Create<PrimitiveLiteral>(true));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), true);
op = storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(false),
storage.Create<PrimitiveLiteral>(true));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), false);
}
TEST(ExpressionEvaluator, FilterAndOperator) {
@ -97,22 +96,22 @@ TEST(ExpressionEvaluator, FilterAndOperator) {
auto *op = storage.Create<FilterAndOperator>(
storage.Create<PrimitiveLiteral>(true),
storage.Create<PrimitiveLiteral>(true));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), true);
}
{
auto *op = storage.Create<FilterAndOperator>(
storage.Create<PrimitiveLiteral>(false),
storage.Create<PrimitiveLiteral>(5));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), false);
}
{
auto *op = storage.Create<FilterAndOperator>(
storage.Create<PrimitiveLiteral>(TypedValue::Null),
storage.Create<PrimitiveLiteral>(5));
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
}
@ -121,8 +120,8 @@ TEST(ExpressionEvaluator, AdditionOperator) {
NoContextExpressionEvaluator eval;
auto *op = storage.Create<AdditionOperator>(
storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), 5);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), 5);
}
TEST(ExpressionEvaluator, SubtractionOperator) {
@ -130,8 +129,8 @@ TEST(ExpressionEvaluator, SubtractionOperator) {
NoContextExpressionEvaluator eval;
auto *op = storage.Create<SubtractionOperator>(
storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), -1);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), -1);
}
TEST(ExpressionEvaluator, MultiplicationOperator) {
@ -139,8 +138,8 @@ TEST(ExpressionEvaluator, MultiplicationOperator) {
NoContextExpressionEvaluator eval;
auto *op = storage.Create<MultiplicationOperator>(
storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), 6);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), 6);
}
TEST(ExpressionEvaluator, DivisionOperator) {
@ -149,8 +148,8 @@ TEST(ExpressionEvaluator, DivisionOperator) {
auto *op =
storage.Create<DivisionOperator>(storage.Create<PrimitiveLiteral>(50),
storage.Create<PrimitiveLiteral>(10));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), 5);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), 5);
}
TEST(ExpressionEvaluator, ModOperator) {
@ -158,8 +157,8 @@ TEST(ExpressionEvaluator, ModOperator) {
NoContextExpressionEvaluator eval;
auto *op = storage.Create<ModOperator>(storage.Create<PrimitiveLiteral>(65),
storage.Create<PrimitiveLiteral>(10));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), 5);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), 5);
}
TEST(ExpressionEvaluator, EqualOperator) {
@ -168,16 +167,16 @@ TEST(ExpressionEvaluator, EqualOperator) {
auto *op =
storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(10),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), false);
op = storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(15),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), true);
op = storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(20),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val3 = op->Accept(eval.eval);
ASSERT_EQ(val3.Value<bool>(), false);
}
TEST(ExpressionEvaluator, NotEqualOperator) {
@ -186,16 +185,16 @@ TEST(ExpressionEvaluator, NotEqualOperator) {
auto *op =
storage.Create<NotEqualOperator>(storage.Create<PrimitiveLiteral>(10),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), true);
op = storage.Create<NotEqualOperator>(storage.Create<PrimitiveLiteral>(15),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), false);
op = storage.Create<NotEqualOperator>(storage.Create<PrimitiveLiteral>(20),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val3 = op->Accept(eval.eval);
ASSERT_EQ(val3.Value<bool>(), true);
}
TEST(ExpressionEvaluator, LessOperator) {
@ -203,16 +202,16 @@ TEST(ExpressionEvaluator, LessOperator) {
NoContextExpressionEvaluator eval;
auto *op = storage.Create<LessOperator>(storage.Create<PrimitiveLiteral>(10),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), true);
op = storage.Create<LessOperator>(storage.Create<PrimitiveLiteral>(15),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), false);
op = storage.Create<LessOperator>(storage.Create<PrimitiveLiteral>(20),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val3 = op->Accept(eval.eval);
ASSERT_EQ(val3.Value<bool>(), false);
}
TEST(ExpressionEvaluator, GreaterOperator) {
@ -221,16 +220,16 @@ TEST(ExpressionEvaluator, GreaterOperator) {
auto *op =
storage.Create<GreaterOperator>(storage.Create<PrimitiveLiteral>(10),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), false);
op = storage.Create<GreaterOperator>(storage.Create<PrimitiveLiteral>(15),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), false);
op = storage.Create<GreaterOperator>(storage.Create<PrimitiveLiteral>(20),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val3 = op->Accept(eval.eval);
ASSERT_EQ(val3.Value<bool>(), true);
}
TEST(ExpressionEvaluator, LessEqualOperator) {
@ -239,16 +238,16 @@ TEST(ExpressionEvaluator, LessEqualOperator) {
auto *op =
storage.Create<LessEqualOperator>(storage.Create<PrimitiveLiteral>(10),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), true);
op = storage.Create<LessEqualOperator>(storage.Create<PrimitiveLiteral>(15),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), true);
op = storage.Create<LessEqualOperator>(storage.Create<PrimitiveLiteral>(20),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val3 = op->Accept(eval.eval);
ASSERT_EQ(val3.Value<bool>(), false);
}
TEST(ExpressionEvaluator, GreaterEqualOperator) {
@ -257,18 +256,18 @@ TEST(ExpressionEvaluator, GreaterEqualOperator) {
auto *op = storage.Create<GreaterEqualOperator>(
storage.Create<PrimitiveLiteral>(10),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), false);
op = storage.Create<GreaterEqualOperator>(
storage.Create<PrimitiveLiteral>(15),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), true);
op = storage.Create<GreaterEqualOperator>(
storage.Create<PrimitiveLiteral>(20),
storage.Create<PrimitiveLiteral>(15));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val3 = op->Accept(eval.eval);
ASSERT_EQ(val3.Value<bool>(), true);
}
TEST(ExpressionEvaluator, InListOperator) {
@ -281,15 +280,15 @@ TEST(ExpressionEvaluator, InListOperator) {
// Element exists in list.
auto *op = storage.Create<InListOperator>(
storage.Create<PrimitiveLiteral>(2), list_literal);
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), true);
}
{
// Element doesn't exist in list.
auto *op = storage.Create<InListOperator>(
storage.Create<PrimitiveLiteral>("x"), list_literal);
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), false);
}
{
auto *list_literal = storage.Create<ListLiteral>(std::vector<Expression *>{
@ -299,16 +298,16 @@ TEST(ExpressionEvaluator, InListOperator) {
// Element doesn't exist in list with null element.
auto *op = storage.Create<InListOperator>(
storage.Create<PrimitiveLiteral>("x"), list_literal);
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
{
// Null list.
auto *op = storage.Create<InListOperator>(
storage.Create<PrimitiveLiteral>("x"),
storage.Create<PrimitiveLiteral>(TypedValue::Null));
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
}
@ -323,37 +322,37 @@ TEST(ExpressionEvaluator, ListIndexingOperator) {
// Legal indexing.
auto *op = storage.Create<ListIndexingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(2));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<int64_t>(), 3);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<int64_t>(), 3);
}
{
// Out of bounds indexing.
auto *op = storage.Create<ListIndexingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(4));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().type(), TypedValue::Type::Null);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.type(), TypedValue::Type::Null);
}
{
// Out of bounds indexing with negative bound.
auto *op = storage.Create<ListIndexingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(-100));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().type(), TypedValue::Type::Null);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.type(), TypedValue::Type::Null);
}
{
// Legal indexing with negative index.
auto *op = storage.Create<ListIndexingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(-2));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<int64_t>(), 3);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<int64_t>(), 3);
}
{
// Indexing with one operator being null.
auto *op = storage.Create<ListIndexingOperator>(
storage.Create<PrimitiveLiteral>(TypedValue::Null),
storage.Create<PrimitiveLiteral>(-2));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().type(), TypedValue::Type::Null);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.type(), TypedValue::Type::Null);
}
{
// Indexing with incompatible type.
@ -384,46 +383,46 @@ TEST(ExpressionEvaluator, ListSlicingOperator) {
auto *op = storage.Create<ListSlicingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(2),
storage.Create<PrimitiveLiteral>(4));
op->Accept(eval.eval);
EXPECT_THAT(extract_ints(eval.eval.PopBack()), ElementsAre(3, 4));
auto value = op->Accept(eval.eval);
EXPECT_THAT(extract_ints(value), ElementsAre(3, 4));
}
{
// Legal slicing with negative bound.
auto *op = storage.Create<ListSlicingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(2),
storage.Create<PrimitiveLiteral>(-1));
op->Accept(eval.eval);
EXPECT_THAT(extract_ints(eval.eval.PopBack()), ElementsAre(3));
auto value = op->Accept(eval.eval);
EXPECT_THAT(extract_ints(value), ElementsAre(3));
}
{
// Lower bound larger than upper bound.
auto *op = storage.Create<ListSlicingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(2),
storage.Create<PrimitiveLiteral>(-4));
op->Accept(eval.eval);
EXPECT_THAT(extract_ints(eval.eval.PopBack()), ElementsAre());
auto value = op->Accept(eval.eval);
EXPECT_THAT(extract_ints(value), ElementsAre());
}
{
// Bounds ouf or range.
auto *op = storage.Create<ListSlicingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(-100),
storage.Create<PrimitiveLiteral>(10));
op->Accept(eval.eval);
EXPECT_THAT(extract_ints(eval.eval.PopBack()), ElementsAre(1, 2, 3, 4));
auto value = op->Accept(eval.eval);
EXPECT_THAT(extract_ints(value), ElementsAre(1, 2, 3, 4));
}
{
// Lower bound undefined.
auto *op = storage.Create<ListSlicingOperator>(
list_literal, nullptr, storage.Create<PrimitiveLiteral>(3));
op->Accept(eval.eval);
EXPECT_THAT(extract_ints(eval.eval.PopBack()), ElementsAre(1, 2, 3));
auto value = op->Accept(eval.eval);
EXPECT_THAT(extract_ints(value), ElementsAre(1, 2, 3));
}
{
// Upper bound undefined.
auto *op = storage.Create<ListSlicingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(-2), nullptr);
op->Accept(eval.eval);
EXPECT_THAT(extract_ints(eval.eval.PopBack()), ElementsAre(3, 4));
auto value = op->Accept(eval.eval);
EXPECT_THAT(extract_ints(value), ElementsAre(3, 4));
}
{
// Bound of illegal type and null value bound.
@ -444,16 +443,16 @@ TEST(ExpressionEvaluator, ListSlicingOperator) {
auto *op = storage.Create<ListSlicingOperator>(
storage.Create<PrimitiveLiteral>(TypedValue::Null),
storage.Create<PrimitiveLiteral>(-2), nullptr);
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().type(), TypedValue::Type::Null);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.type(), TypedValue::Type::Null);
}
{
// Null value index.
auto *op = storage.Create<ListSlicingOperator>(
list_literal, storage.Create<PrimitiveLiteral>(-2),
storage.Create<PrimitiveLiteral>(TypedValue::Null));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().type(), TypedValue::Type::Null);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.type(), TypedValue::Type::Null);
}
}
@ -462,8 +461,8 @@ TEST(ExpressionEvaluator, NotOperator) {
NoContextExpressionEvaluator eval;
auto *op =
storage.Create<NotOperator>(storage.Create<PrimitiveLiteral>(false));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<bool>(), true);
}
TEST(ExpressionEvaluator, UnaryPlusOperator) {
@ -471,8 +470,8 @@ TEST(ExpressionEvaluator, UnaryPlusOperator) {
NoContextExpressionEvaluator eval;
auto *op =
storage.Create<UnaryPlusOperator>(storage.Create<PrimitiveLiteral>(5));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), 5);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), 5);
}
TEST(ExpressionEvaluator, UnaryMinusOperator) {
@ -480,8 +479,8 @@ TEST(ExpressionEvaluator, UnaryMinusOperator) {
NoContextExpressionEvaluator eval;
auto *op =
storage.Create<UnaryMinusOperator>(storage.Create<PrimitiveLiteral>(5));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), -5);
auto value = op->Accept(eval.eval);
ASSERT_EQ(value.Value<int64_t>(), -5);
}
TEST(ExpressionEvaluator, IsNullOperator) {
@ -489,12 +488,12 @@ TEST(ExpressionEvaluator, IsNullOperator) {
NoContextExpressionEvaluator eval;
auto *op =
storage.Create<IsNullOperator>(storage.Create<PrimitiveLiteral>(1));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto val1 = op->Accept(eval.eval);
ASSERT_EQ(val1.Value<bool>(), false);
op = storage.Create<IsNullOperator>(
storage.Create<PrimitiveLiteral>(TypedValue::Null));
op->Accept(eval.eval);
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto val2 = op->Accept(eval.eval);
ASSERT_EQ(val2.Value<bool>(), true);
}
TEST(ExpressionEvaluator, PropertyLookup) {
@ -510,20 +509,20 @@ TEST(ExpressionEvaluator, PropertyLookup) {
eval.frame[node_symbol] = v1;
{
auto *op = storage.Create<PropertyLookup>(identifier, dba->property("age"));
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<int64_t>(), 10);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<int64_t>(), 10);
}
{
auto *op =
storage.Create<PropertyLookup>(identifier, dba->property("height"));
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
{
eval.frame[node_symbol] = TypedValue::Null;
auto *op = storage.Create<PropertyLookup>(identifier, dba->property("age"));
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
}
@ -544,16 +543,16 @@ TEST(ExpressionEvaluator, LabelsTest) {
auto *op = storage.Create<LabelsTest>(
identifier, std::vector<GraphDbTypes::Label>{dba->label("DOG"),
dba->label("ANIMAL")});
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), true);
}
{
auto *op = storage.Create<LabelsTest>(
identifier,
std::vector<GraphDbTypes::Label>{
dba->label("DOG"), dba->label("BAD_DOG"), dba->label("ANIMAL")});
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), false);
}
{
eval.frame[node_symbol] = TypedValue::Null;
@ -561,8 +560,8 @@ TEST(ExpressionEvaluator, LabelsTest) {
identifier,
std::vector<GraphDbTypes::Label>{
dba->label("DOG"), dba->label("BAD_DOG"), dba->label("ANIMAL")});
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
}
@ -583,23 +582,23 @@ TEST(ExpressionEvaluator, EdgeTypeTest) {
identifier, std::vector<GraphDbTypes::EdgeType>{
dba->edge_type("TYPE0"), dba->edge_type("TYPE1"),
dba->edge_type("TYPE2")});
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), true);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), true);
}
{
auto *op = storage.Create<EdgeTypeTest>(
identifier, std::vector<GraphDbTypes::EdgeType>{
dba->edge_type("TYPE0"), dba->edge_type("TYPE2")});
op->Accept(eval.eval);
EXPECT_EQ(eval.eval.PopBack().Value<bool>(), false);
auto value = op->Accept(eval.eval);
EXPECT_EQ(value.Value<bool>(), false);
}
{
eval.frame[edge_symbol] = TypedValue::Null;
auto *op = storage.Create<EdgeTypeTest>(
identifier, std::vector<GraphDbTypes::EdgeType>{
dba->edge_type("TYPE0"), dba->edge_type("TYPE2")});
op->Accept(eval.eval);
EXPECT_TRUE(eval.eval.PopBack().IsNull());
auto value = op->Accept(eval.eval);
EXPECT_TRUE(value.IsNull());
}
}
@ -615,8 +614,8 @@ TEST(ExpressionEvaluator, Aggregation) {
Dbms dbms;
auto dba = dbms.active();
ExpressionEvaluator eval{frame, symbol_table, *dba};
aggr->Accept(eval);
EXPECT_EQ(eval.PopBack().Value<int64_t>(), 1);
auto value = aggr->Accept(eval);
EXPECT_EQ(value.Value<int64_t>(), 1);
}
TEST(ExpressionEvaluator, ListLiteral) {
@ -626,8 +625,7 @@ TEST(ExpressionEvaluator, ListLiteral) {
std::vector<Expression *>{storage.Create<PrimitiveLiteral>(1),
storage.Create<PrimitiveLiteral>("bla"),
storage.Create<PrimitiveLiteral>(true)});
list_literal->Accept(eval.eval);
TypedValue result = eval.eval.PopBack();
TypedValue result = list_literal->Accept(eval.eval);
ASSERT_EQ(result.type(), TypedValue::Type::List);
auto &result_elems = result.Value<std::vector<TypedValue>>();
ASSERT_EQ(3, result_elems.size());