diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp index e6d97ee5f..42d57cfe4 100644 --- a/src/query/frontend/ast/ast.hpp +++ b/src/query/frontend/ast/ast.hpp @@ -14,10 +14,14 @@ namespace query { class AstTreeStorage; -class Tree : public ::utils::Visitable { +class Tree : public ::utils::Visitable, + ::utils::Visitable> { friend class AstTreeStorage; public: + using ::utils::Visitable::Accept; + using ::utils::Visitable>::Accept; + int uid() const { return uid_; } protected: @@ -63,6 +67,7 @@ class OrOperator : public BinaryOperator { friend class AstTreeStorage; public: + DEFVISITABLE(TreeVisitor); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); DEFVISITABLE(HierarchicalTreeVisitor); TypedValue value_; @@ -433,6 +460,7 @@ class ListLiteral : public BaseLiteral { public: const std::vector elements_; + DEFVISITABLE(TreeVisitor); 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); DEFVISITABLE(HierarchicalTreeVisitor); std::string name_; bool user_declared_ = true; @@ -465,6 +494,7 @@ class PropertyLookup : public Expression { friend class AstTreeStorage; public: + DEFVISITABLE(TreeVisitor); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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 patterns_; + DEFVISITABLE(TreeVisitor); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); bool Accept(HierarchicalTreeVisitor &visitor) override { if (visitor.PreVisit(*this)) { named_expression_->Accept(visitor); diff --git a/src/query/frontend/ast/ast_visitor.hpp b/src/query/frontend/ast/ast_visitor.hpp index 06e7d60eb..8a4fc38de 100644 --- a/src/query/frontend/ast/ast_visitor.hpp +++ b/src/query/frontend/ast/ast_visitor.hpp @@ -77,4 +77,17 @@ class HierarchicalTreeVisitor : public TreeCompositeVisitor, using TreeLeafVisitor::Visit; }; +template +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 diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index c43e24576..a87dc9139 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -16,7 +16,7 @@ namespace query { -class ExpressionEvaluator : public HierarchicalTreeVisitor { +class ExpressionEvaluator : public TreeVisitor { 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::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()) { + TypedValue Visit(FilterAndOperator &op) override { + auto value1 = op.expression1_->Accept(*this); + if (value1.IsNull() || !value1.Value()) { // 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>(); 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()) { - 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(); const auto &list = _list.Value>(); @@ -164,20 +159,18 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor { index = static_cast(list.size()) + index; } if (index >= static_cast(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::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>(); auto normalise_bound = [&](int64_t bound) { @@ -213,131 +205,105 @@ class ExpressionEvaluator : public HierarchicalTreeVisitor { auto lower_bound = normalise_bound(_lower_bound.Value()); auto upper_bound = normalise_bound(_upper_bound.Value()); if (upper_bound <= lower_bound) { - result_stack_.emplace_back(std::vector()); - return true; + return std::vector(); } - result_stack_.emplace_back(std::vector( - list.begin() + lower_bound, list.begin() + upper_bound)); - return true; + return std::vector(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().PropsAt( - property_lookup.property_)); - break; - case TypedValue::Type::Edge: { - result_stack_.emplace_back( - expression_result.Value().PropsAt( - property_lookup.property_)); - break; - } + return expression_result.Value().PropsAt( + property_lookup.property_); + case TypedValue::Type::Edge: + return expression_result.Value().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(); 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().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 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 arguments; - for (int i = 0; i < static_cast(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 result_stack_; }; -} + +} // namespace query diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index a3483cc6c..b835da410 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -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()) continue; return true; } @@ -444,8 +440,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { std::vector 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 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 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>(); diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp index c57f2a127..85f291f88 100644 --- a/tests/unit/query_expression_evaluator.cpp +++ b/tests/unit/query_expression_evaluator.cpp @@ -44,8 +44,7 @@ TypedValue EvaluateFunction(const std::string &function_name, } auto *op = storage.Create(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(storage.Create(true), storage.Create(false)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), true); op = storage.Create(storage.Create(true), storage.Create(true)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), true); } TEST(ExpressionEvaluator, XorOperator) { @@ -68,12 +67,12 @@ TEST(ExpressionEvaluator, XorOperator) { auto *op = storage.Create(storage.Create(true), storage.Create(false)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), true); op = storage.Create(storage.Create(true), storage.Create(true)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), false); } TEST(ExpressionEvaluator, AndOperator) { @@ -82,12 +81,12 @@ TEST(ExpressionEvaluator, AndOperator) { auto *op = storage.Create(storage.Create(true), storage.Create(true)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), true); op = storage.Create(storage.Create(false), storage.Create(true)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), false); } TEST(ExpressionEvaluator, FilterAndOperator) { @@ -97,22 +96,22 @@ TEST(ExpressionEvaluator, FilterAndOperator) { auto *op = storage.Create( storage.Create(true), storage.Create(true)); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), true); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), true); } { auto *op = storage.Create( storage.Create(false), storage.Create(5)); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), false); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), false); } { auto *op = storage.Create( storage.Create(TypedValue::Null), storage.Create(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( storage.Create(2), storage.Create(3)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), 5); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), 5); } TEST(ExpressionEvaluator, SubtractionOperator) { @@ -130,8 +129,8 @@ TEST(ExpressionEvaluator, SubtractionOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create( storage.Create(2), storage.Create(3)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), -1); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), -1); } TEST(ExpressionEvaluator, MultiplicationOperator) { @@ -139,8 +138,8 @@ TEST(ExpressionEvaluator, MultiplicationOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create( storage.Create(2), storage.Create(3)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), 6); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), 6); } TEST(ExpressionEvaluator, DivisionOperator) { @@ -149,8 +148,8 @@ TEST(ExpressionEvaluator, DivisionOperator) { auto *op = storage.Create(storage.Create(50), storage.Create(10)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), 5); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), 5); } TEST(ExpressionEvaluator, ModOperator) { @@ -158,8 +157,8 @@ TEST(ExpressionEvaluator, ModOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create(storage.Create(65), storage.Create(10)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), 5); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), 5); } TEST(ExpressionEvaluator, EqualOperator) { @@ -168,16 +167,16 @@ TEST(ExpressionEvaluator, EqualOperator) { auto *op = storage.Create(storage.Create(10), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), false); op = storage.Create(storage.Create(15), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), true); op = storage.Create(storage.Create(20), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val3 = op->Accept(eval.eval); + ASSERT_EQ(val3.Value(), false); } TEST(ExpressionEvaluator, NotEqualOperator) { @@ -186,16 +185,16 @@ TEST(ExpressionEvaluator, NotEqualOperator) { auto *op = storage.Create(storage.Create(10), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), true); op = storage.Create(storage.Create(15), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), false); op = storage.Create(storage.Create(20), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val3 = op->Accept(eval.eval); + ASSERT_EQ(val3.Value(), true); } TEST(ExpressionEvaluator, LessOperator) { @@ -203,16 +202,16 @@ TEST(ExpressionEvaluator, LessOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create(storage.Create(10), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), true); op = storage.Create(storage.Create(15), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), false); op = storage.Create(storage.Create(20), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val3 = op->Accept(eval.eval); + ASSERT_EQ(val3.Value(), false); } TEST(ExpressionEvaluator, GreaterOperator) { @@ -221,16 +220,16 @@ TEST(ExpressionEvaluator, GreaterOperator) { auto *op = storage.Create(storage.Create(10), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), false); op = storage.Create(storage.Create(15), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), false); op = storage.Create(storage.Create(20), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val3 = op->Accept(eval.eval); + ASSERT_EQ(val3.Value(), true); } TEST(ExpressionEvaluator, LessEqualOperator) { @@ -239,16 +238,16 @@ TEST(ExpressionEvaluator, LessEqualOperator) { auto *op = storage.Create(storage.Create(10), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), true); op = storage.Create(storage.Create(15), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), true); op = storage.Create(storage.Create(20), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val3 = op->Accept(eval.eval); + ASSERT_EQ(val3.Value(), false); } TEST(ExpressionEvaluator, GreaterEqualOperator) { @@ -257,18 +256,18 @@ TEST(ExpressionEvaluator, GreaterEqualOperator) { auto *op = storage.Create( storage.Create(10), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), false); op = storage.Create( storage.Create(15), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), true); op = storage.Create( storage.Create(20), storage.Create(15)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val3 = op->Accept(eval.eval); + ASSERT_EQ(val3.Value(), true); } TEST(ExpressionEvaluator, InListOperator) { @@ -281,15 +280,15 @@ TEST(ExpressionEvaluator, InListOperator) { // Element exists in list. auto *op = storage.Create( storage.Create(2), list_literal); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), true); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), true); } { // Element doesn't exist in list. auto *op = storage.Create( storage.Create("x"), list_literal); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), false); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), false); } { auto *list_literal = storage.Create(std::vector{ @@ -299,16 +298,16 @@ TEST(ExpressionEvaluator, InListOperator) { // Element doesn't exist in list with null element. auto *op = storage.Create( storage.Create("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( storage.Create("x"), storage.Create(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( list_literal, storage.Create(2)); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), 3); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), 3); } { // Out of bounds indexing. auto *op = storage.Create( list_literal, storage.Create(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( list_literal, storage.Create(-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( list_literal, storage.Create(-2)); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), 3); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), 3); } { // Indexing with one operator being null. auto *op = storage.Create( storage.Create(TypedValue::Null), storage.Create(-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( list_literal, storage.Create(2), storage.Create(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( list_literal, storage.Create(2), storage.Create(-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( list_literal, storage.Create(2), storage.Create(-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( list_literal, storage.Create(-100), storage.Create(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( list_literal, nullptr, storage.Create(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( list_literal, storage.Create(-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( storage.Create(TypedValue::Null), storage.Create(-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( list_literal, storage.Create(-2), storage.Create(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(storage.Create(false)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), true); } TEST(ExpressionEvaluator, UnaryPlusOperator) { @@ -471,8 +470,8 @@ TEST(ExpressionEvaluator, UnaryPlusOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create(storage.Create(5)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), 5); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), 5); } TEST(ExpressionEvaluator, UnaryMinusOperator) { @@ -480,8 +479,8 @@ TEST(ExpressionEvaluator, UnaryMinusOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create(storage.Create(5)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), -5); + auto value = op->Accept(eval.eval); + ASSERT_EQ(value.Value(), -5); } TEST(ExpressionEvaluator, IsNullOperator) { @@ -489,12 +488,12 @@ TEST(ExpressionEvaluator, IsNullOperator) { NoContextExpressionEvaluator eval; auto *op = storage.Create(storage.Create(1)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), false); + auto val1 = op->Accept(eval.eval); + ASSERT_EQ(val1.Value(), false); op = storage.Create( storage.Create(TypedValue::Null)); - op->Accept(eval.eval); - ASSERT_EQ(eval.eval.PopBack().Value(), true); + auto val2 = op->Accept(eval.eval); + ASSERT_EQ(val2.Value(), true); } TEST(ExpressionEvaluator, PropertyLookup) { @@ -510,20 +509,20 @@ TEST(ExpressionEvaluator, PropertyLookup) { eval.frame[node_symbol] = v1; { auto *op = storage.Create(identifier, dba->property("age")); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), 10); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), 10); } { auto *op = storage.Create(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(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( identifier, std::vector{dba->label("DOG"), dba->label("ANIMAL")}); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), true); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), true); } { auto *op = storage.Create( identifier, std::vector{ dba->label("DOG"), dba->label("BAD_DOG"), dba->label("ANIMAL")}); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), false); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), false); } { eval.frame[node_symbol] = TypedValue::Null; @@ -561,8 +560,8 @@ TEST(ExpressionEvaluator, LabelsTest) { identifier, std::vector{ 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{ dba->edge_type("TYPE0"), dba->edge_type("TYPE1"), dba->edge_type("TYPE2")}); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), true); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), true); } { auto *op = storage.Create( identifier, std::vector{ dba->edge_type("TYPE0"), dba->edge_type("TYPE2")}); - op->Accept(eval.eval); - EXPECT_EQ(eval.eval.PopBack().Value(), false); + auto value = op->Accept(eval.eval); + EXPECT_EQ(value.Value(), false); } { eval.frame[edge_symbol] = TypedValue::Null; auto *op = storage.Create( identifier, std::vector{ 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(), 1); + auto value = aggr->Accept(eval); + EXPECT_EQ(value.Value(), 1); } TEST(ExpressionEvaluator, ListLiteral) { @@ -626,8 +625,7 @@ TEST(ExpressionEvaluator, ListLiteral) { std::vector{storage.Create(1), storage.Create("bla"), storage.Create(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>(); ASSERT_EQ(3, result_elems.size());