Replace TreeVisitor with ExpressionVisitor

Summary:
This is the initial step in making the visitors more granular in what
they visit.

Also add ignoring multiple inheritance in LCP and update LCP docs.

Reviewers: mtomic, llugovic

Reviewed By: mtomic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1704
This commit is contained in:
Teon Banek 2018-10-29 13:31:27 +01:00
parent 50b2646765
commit 218384786d
5 changed files with 99 additions and 112 deletions

View File

@ -481,8 +481,24 @@ Proto, we simply enumerate all derived types inside the union of a base type.
Multiple inheritance is a different beast and as such is not directly
supported.
Most form of inheritance should actually be a simple composition, and we can
treat parent classes as being composed inside our derived type.
One way to use multiple inheritance is only to implement the interface of pure
virtual classes without any members (i.e. interface classes). In such a case,
you do not want to serialize any other base class except the primary one. To
let LCP know that is the case, use `:ignore-other-base-classes t`. LCP will
only try to serialize the base class that is the first (leftmost) in the list
of super classes.
```lisp
(lcp:define-class derived (primary-base some-interface other-interface)
...
(:serialize :capnp :ignore-other-base-classes t))
```
Another form of multiple inheritance is reusing some common code. In
actuality, this is a very bad code practice and should be replaced with
composition. If it would take too long to fix such code to use composition
proper, we can tell LCP to treat such inheritance as if they are indeed
composed. This is done via `:inherit-compose` option.
For example:

View File

@ -339,7 +339,9 @@ CPP-TYPE has no namespace, return an empty string."
(type-args nil :read-only t)
;; In case of multiple inheritance, list of classes which should be handled
;; as a composition.
(inherit-compose nil :read-only t))
(inherit-compose nil :read-only t)
;; In case of multiple inheritance, pretend we only inherit the 1st base class.
(ignore-other-base-classes nil :type boolean :read-only t))
(defclass cpp-class (cpp-type)
((structp :type boolean :initarg :structp :initform nil
@ -658,8 +660,16 @@ Cap'n Proto schema."
(declare (type (or symbol cpp-class) cpp-class))
(let ((class-name (if (symbolp cpp-class) cpp-class (cpp-type-base-name cpp-class))))
(remove-if (lambda (subclass)
(member class-name
(capnp-opts-inherit-compose (cpp-class-capnp-opts subclass))))
(let ((capnp-opts (cpp-class-capnp-opts subclass)))
(or
;; Remove if we are a parent that should be ignored (not
;; the 1st in the list).
(and (capnp-opts-ignore-other-base-classes capnp-opts)
(not (eq class-name (car (cpp-class-super-classes subclass)))))
;; Remove if we are a parent that should be treated as
;; composition.
(member class-name
(capnp-opts-inherit-compose (cpp-class-capnp-opts subclass))))))
(direct-subclasses-of cpp-class))))
(defun capnp-union-and-compose-parents (cpp-class)
@ -668,17 +678,23 @@ secondary value contains parents which are modeled as being composed inside
CPP-CLASS."
(declare (type (or symbol cpp-class) cpp-class))
(let* ((class (if (symbolp cpp-class) (find-cpp-class cpp-class) cpp-class))
(capnp-opts (cpp-class-capnp-opts class))
union compose)
(capnp-opts (cpp-class-capnp-opts class)))
(when (not capnp-opts)
(error "Class ~A should be marked for capnp serialization,
or its derived classes set as :CAPNP :BASE T" (cpp-type-base-name class)))
(when (not (capnp-opts-base capnp-opts))
(dolist (parent (cpp-class-super-classes class))
(if (member parent (capnp-opts-inherit-compose capnp-opts))
(push parent compose)
(push parent union))))
(values union compose)))
(if (capnp-opts-ignore-other-base-classes capnp-opts)
;; Since we are ignoring multiple inheritance, return the 1st class
;; (as union parent).
(list (car (cpp-class-super-classes class)))
;; We aren't ignoring multiple inheritance, collect union and
;; compose parents.
(let (union compose)
(dolist (parent (cpp-class-super-classes class))
(if (member parent (capnp-opts-inherit-compose capnp-opts))
(push parent compose)
(push parent union)))
(values union compose))))))
(defun capnp-union-parents-rec (cpp-class)
"Return a list of all parent clases recursively for CPP-CLASS that should be

View File

@ -150,8 +150,7 @@ class AstStorage {
};
cpp<#
(lcp:define-class tree ("::utils::Visitable<HierarchicalTreeVisitor>"
"::utils::Visitable<TreeVisitor<TypedValue>>")
(lcp:define-class tree ("::utils::Visitable<HierarchicalTreeVisitor>")
((uid :int32_t :scope :public))
(:abstractp t)
(:public
@ -159,7 +158,6 @@ cpp<#
Tree() = default;
using ::utils::Visitable<HierarchicalTreeVisitor>::Accept;
using ::utils::Visitable<TreeVisitor<TypedValue>>::Accept;
virtual Tree *Clone(AstStorage &storage) const = 0;
cpp<#)
@ -187,11 +185,18 @@ cpp<#
saved_uids->push_back(self.uid_);
cpp<#)))
(lcp:define-class expression (tree)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Expressions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(lcp:define-class expression (tree "::utils::Visitable<ExpressionVisitor<TypedValue>>")
()
(:abstractp t)
(:public
#>cpp
using ::utils::Visitable<ExpressionVisitor<TypedValue>>::Accept;
using Tree::Accept;
Expression() = default;
Expression *Clone(AstStorage &storage) const override = 0;
@ -204,7 +209,7 @@ cpp<#
#>cpp
friend class AstStorage;
cpp<#)
(:serialize :capnp))
(:serialize :capnp :ignore-other-base-classes t))
(lcp:define-class where (tree)
((expression "Expression *" :initval "nullptr" :scope :public
@ -215,7 +220,6 @@ cpp<#
#>cpp
Where() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -304,7 +308,7 @@ cpp<#
(:public
(let ((cpp-name (lcp::cpp-type-name ',op)))
#>cpp
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
@ -335,7 +339,7 @@ cpp<#
(:public
(let ((cpp-name (lcp::cpp-type-name ',op)))
#>cpp
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -377,7 +381,7 @@ cpp<#
return op_strings[static_cast<int>(op)];
}
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
if (expression1_) expression1_->Accept(visitor);
@ -432,7 +436,7 @@ cpp<#
#>cpp
ListSlicingOperator() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = list_->Accept(visitor);
@ -486,7 +490,7 @@ cpp<#
#>cpp
IfOperator() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
condition_->Accept(visitor) && then_expression_->Accept(visitor) &&
@ -551,7 +555,7 @@ cpp<#
#>cpp
PrimitiveLiteral() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
DEFVISITABLE(HierarchicalTreeVisitor);
PrimitiveLiteral *Clone(AstStorage &storage) const override {
@ -583,7 +587,7 @@ cpp<#
#>cpp
ListLiteral() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto expr_ptr : elements_)
@ -622,7 +626,7 @@ cpp<#
#>cpp
MapLiteral() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto pair : elements_)
@ -659,7 +663,7 @@ cpp<#
#>cpp
Identifier() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
DEFVISITABLE(HierarchicalTreeVisitor);
Identifier *Clone(AstStorage &storage) const override {
@ -689,7 +693,7 @@ cpp<#
#>cpp
PropertyLookup() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -739,7 +743,7 @@ cpp<#
#>cpp
LabelsTest() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -781,7 +785,7 @@ cpp<#
#>cpp
Function() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto *argument : arguments_) {
@ -848,7 +852,7 @@ cpp<#
#>cpp
Reduce() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
accumulator_->Accept(visitor) && initializer_->Accept(visitor) &&
@ -893,7 +897,7 @@ cpp<#
#>cpp
Coalesce() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto *expr : expressions_) {
@ -942,7 +946,7 @@ cpp<#
#>cpp
Extract() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor) && list_->Accept(visitor) &&
@ -989,7 +993,7 @@ cpp<#
#>cpp
All() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor) && list_expression_->Accept(visitor) &&
@ -1019,9 +1023,9 @@ cpp<#
cpp<#)
(:serialize :capnp))
;;;; TODO: This is pretty much copy pasted from All. Consider merging Reduce,
;;;; All, Any and Single into something like a higher-order function call which
;;;; takes a list argument and a function which is applied on list elements.
;; TODO: This is pretty much copy pasted from All. Consider merging Reduce,
;; All, Any and Single into something like a higher-order function call which
;; takes a list argument and a function which is applied on list elements.
(lcp:define-class single (expression)
((identifier "Identifier *" :initval "nullptr" :scope :public
:capnp-type "Tree" :capnp-init nil
@ -1039,7 +1043,7 @@ cpp<#
#>cpp
Single() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor) && list_expression_->Accept(visitor) &&
@ -1076,7 +1080,7 @@ cpp<#
#>cpp
ParameterLookup() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
DEFVISITABLE(HierarchicalTreeVisitor);
ParameterLookup *Clone(AstStorage &storage) const override {
@ -1095,7 +1099,7 @@ cpp<#
cpp<#)
(:serialize :capnp))
(lcp:define-class named-expression (tree)
(lcp:define-class named-expression (tree "::utils::Visitable<ExpressionVisitor<TypedValue>>")
((name "std::string" :scope :public)
(expression "Expression *" :initval "nullptr" :scope :public
:capnp-type "Tree" :capnp-init nil
@ -1105,9 +1109,11 @@ cpp<#
:documentation "This field contains token position of first token in named expression used to create name_. If NamedExpression object is not created from query or it is aliased leave this value at -1."))
(:public
#>cpp
using ::utils::Visitable<ExpressionVisitor<TypedValue>>::Accept;
NamedExpression() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression_->Accept(visitor);
@ -1137,7 +1143,11 @@ cpp<#
#>cpp
friend class AstStorage;
cpp<#)
(:serialize :capnp))
(:serialize :capnp :ignore-other-base-classes t))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; END Expressions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(lcp:define-class pattern-atom (tree)
((identifier "Identifier *" :initval "nullptr" :scope :public
@ -1178,7 +1188,6 @@ cpp<#
:scope :public))
(:public
#>cpp
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = identifier_->Accept(visitor);
@ -1273,7 +1282,6 @@ cpp<#
:load-args '((storage "AstStorage *")
(loaded-uids "std::vector<int32_t> *"))))
#>cpp
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = identifier_->Accept(visitor);
@ -1366,7 +1374,6 @@ cpp<#
#>cpp
Pattern() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = identifier_->Accept(visitor);
@ -1427,7 +1434,6 @@ cpp<#
#>cpp
SingleQuery() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &clause : clauses_) {
@ -1467,7 +1473,6 @@ cpp<#
#>cpp
CypherUnion() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
single_query_->Accept(visitor);
@ -1534,7 +1539,6 @@ cpp<#
#>cpp
CypherQuery() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool should_continue = single_query_->Accept(visitor);
@ -1576,7 +1580,6 @@ cpp<#
#>cpp
ExplainQuery() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
cypher_query_->Accept(visitor);
@ -1614,7 +1617,6 @@ cpp<#
#>cpp
IndexQuery() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
DEFVISITABLE(HierarchicalTreeVisitor);
IndexQuery *Clone(AstStorage &storage) const override {
@ -1644,7 +1646,6 @@ cpp<#
#>cpp
Create() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &pattern : patterns_) {
@ -1689,7 +1690,6 @@ cpp<#
#>cpp
Match() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;
@ -1799,7 +1799,6 @@ cpp<#
#>cpp
Return() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;
@ -1850,7 +1849,6 @@ cpp<#
#>cpp
With() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;
@ -1905,7 +1903,6 @@ cpp<#
#>cpp
Delete() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
for (auto &expr : expressions_) {
@ -1949,7 +1946,6 @@ cpp<#
#>cpp
SetProperty() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
property_lookup_->Accept(visitor) && expression_->Accept(visitor);
@ -1990,7 +1986,6 @@ cpp<#
#>cpp
SetProperties() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor) && expression_->Accept(visitor);
@ -2035,7 +2030,6 @@ cpp<#
#>cpp
SetLabels() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor);
@ -2069,7 +2063,6 @@ cpp<#
#>cpp
RemoveProperty() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
property_lookup_->Accept(visitor);
@ -2109,7 +2102,6 @@ cpp<#
#>cpp
RemoveLabels() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
identifier_->Accept(visitor);
@ -2153,7 +2145,6 @@ cpp<#
#>cpp
Merge() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = pattern_->Accept(visitor);
@ -2214,7 +2205,6 @@ cpp<#
#>cpp
Unwind() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
named_expression_->Accept(visitor);
@ -2266,7 +2256,6 @@ cpp<#
#>cpp
AuthQuery() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
if (password_) password_->Accept(visitor);
@ -2346,7 +2335,6 @@ cpp<#
#>cpp
StreamQuery() = default;
DEFVISITABLE(TreeVisitor<TypedValue>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
bool cont = true;

View File

@ -92,19 +92,18 @@ class HierarchicalTreeVisitor : public TreeCompositeVisitor,
using typename TreeLeafVisitor::ReturnType;
};
template <typename TResult>
using TreeVisitor = ::utils::Visitor<
TResult, CypherQuery, ExplainQuery, SingleQuery, CypherUnion,
NamedExpression, OrOperator, XorOperator, AndOperator, NotOperator,
AdditionOperator, SubtractionOperator, MultiplicationOperator,
DivisionOperator, ModOperator, NotEqualOperator, EqualOperator,
LessOperator, GreaterOperator, LessEqualOperator, GreaterEqualOperator,
InListOperator, SubscriptOperator, ListSlicingOperator, IfOperator,
UnaryPlusOperator, UnaryMinusOperator, IsNullOperator, ListLiteral,
MapLiteral, PropertyLookup, LabelsTest, Aggregation, Function, Reduce,
Coalesce, Extract, All, Single, ParameterLookup, Create, Match, Return,
With, Pattern, NodeAtom, EdgeAtom, Delete, Where, SetProperty,
SetProperties, SetLabels, RemoveProperty, RemoveLabels, Merge, Unwind,
Identifier, PrimitiveLiteral, IndexQuery, AuthQuery, StreamQuery>;
template <class TResult>
class ExpressionVisitor
: public ::utils::Visitor<
TResult, NamedExpression, OrOperator, XorOperator, AndOperator,
NotOperator, AdditionOperator, SubtractionOperator,
MultiplicationOperator, DivisionOperator, ModOperator,
NotEqualOperator, EqualOperator, LessOperator, GreaterOperator,
LessEqualOperator, GreaterEqualOperator, InListOperator,
SubscriptOperator, ListSlicingOperator, IfOperator, UnaryPlusOperator,
UnaryMinusOperator, IsNullOperator, ListLiteral, MapLiteral,
PropertyLookup, LabelsTest, Aggregation, Function, Reduce, Coalesce,
Extract, All, Single, ParameterLookup, Identifier, PrimitiveLiteral> {
};
} // namespace query

View File

@ -18,7 +18,7 @@
namespace query {
class ExpressionEvaluator : public TreeVisitor<TypedValue> {
class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
public:
ExpressionEvaluator(Frame *frame, const SymbolTable &symbol_table,
const EvaluationContext &ctx,
@ -29,39 +29,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
dba_(dba),
graph_view_(graph_view) {}
using TreeVisitor<TypedValue>::Visit;
#define BLOCK_VISIT(TREE_TYPE) \
TypedValue Visit(TREE_TYPE &) override { \
LOG(FATAL) << "ExpressionEvaluator should not visit " #TREE_TYPE; \
}
BLOCK_VISIT(CypherQuery);
BLOCK_VISIT(ExplainQuery);
BLOCK_VISIT(CypherUnion);
BLOCK_VISIT(SingleQuery);
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);
BLOCK_VISIT(IndexQuery);
BLOCK_VISIT(AuthQuery);
BLOCK_VISIT(StreamQuery);
#undef BLOCK_VISIT
using ExpressionVisitor<TypedValue>::Visit;
TypedValue Visit(NamedExpression &named_expression) override {
const auto &symbol = symbol_table_->at(named_expression);