nixd
Loading...
Searching...
No Matches
Visitor.h
Go to the documentation of this file.
1/// \file
2/// \brief Describe how to traverse upon nix::Expr * nodes.
3///
4/// This file contains a CRTP base class for traversing nix::Expr * nodes.
5
6#pragma once
7
8#include <nix/nixexpr.hh>
9#include <nix/symbol-table.hh>
10
11/// \brief Library for playing with `nix::Expr` nodes.
12///
13/// This is a library with some utilities playing with nix AST nodes (e.g.
14/// traversing, visiting, encoding, decoding, dispatching, printing). It is not
15/// a parser, so you should use other libraries to parse nix code.
16
17namespace nixt {
18
19/// \brief A
20/// [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
21/// base class for traversing `nix::Expr *` nodes.
22///
23/// Usage:
24///
25/// \code{.cpp}
26/// struct MyVisitor : public RecursiveASTVisitor<MyVisitor> {
27/// // This can be omitted.
28/// bool traverseExpr(const nix::Expr *E) {
29/// // Do something before/after traversing children.
30/// }
31///
32/// // return `true` to traverse post-order, otherwise pre-order (default).
33/// bool shouldTraversePostOrder() { return true; }
34///
35/// // sreturn `true` if we should continue traversing.
36/// bool visitExprInt(const nix::ExprInt *E) { return true; }
37/// bool visitExprFloat(const nix::ExprFloat *E) { return true; }
38/// } V;
39/// V.traverseExpr(Root); // call traverseExpr() on Root.
40/// \endcode
41///
42/// \note This is based on dynamic_cast, so it is not very efficient.
43///
44/// `visit*()` methods are called once for each node.` traverse*()` methods are
45/// automatically generated describing relations between nodes. Usually you
46/// should always write custom `visit*()` methods, and only write `traverse*()`
47/// methods when you need to do something special.
48template <class Derived> struct RecursiveASTVisitor {
49
50 bool shouldTraversePostOrder() { return false; }
51
52 bool visitExpr(const nix::Expr *) { return true; }
53
54#define NIX_EXPR(EXPR) bool traverse##EXPR(const nix::EXPR *E);
55#include "Nodes.inc"
56#undef NIX_EXPR
57
58#define NIX_EXPR(EXPR) \
59 bool visit##EXPR(const nix::EXPR *E) { return getDerived().visitExpr(E); }
60#include "Nodes.inc"
61#undef NIX_EXPR
62
63 Derived &getDerived() { return *static_cast<Derived *>(this); }
64
65 bool traverseExpr(const nix::Expr *E) {
66 if (!E)
67 return true;
68#define NIX_EXPR(EXPR) \
69 if (auto CE = dynamic_cast<const nix::EXPR *>(E)) { \
70 return getDerived().traverse##EXPR(CE); \
71 }
72#include "Nodes.inc"
73#undef NIX_EXPR
74 assert(false && "We are missing some nix AST Nodes!");
75 return true;
76 }
77};
78
79#define TRY_TO(CALL_EXPR) \
80 do { \
81 if (!getDerived().CALL_EXPR) \
82 return false; \
83 } while (false)
84
85#define TRY_TO_TRAVERSE(EXPR) TRY_TO(traverseExpr(EXPR))
86
87#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
88 template <typename Derived> \
89 bool RecursiveASTVisitor<Derived>::traverse##TYPE(const nix::TYPE *T) { \
90 if (!getDerived().shouldTraversePostOrder()) \
91 TRY_TO(visit##TYPE(T)); \
92 { CODE; } \
93 if (getDerived().shouldTraversePostOrder()) \
94 TRY_TO(visit##TYPE(T)); \
95 return true; \
96 }
97#include "Traverse.inc"
98#undef DEF_TRAVERSE_TYPE
99#undef TRY_TO_TRAVERSE
100
101} // namespace nixt
Access EvalCache in nix::EvalState.
Definition ArrayRef.h:7
A CRTP base class for traversing nix::Expr * nodes.
Definition Visitor.h:48
bool traverseExpr(const nix::Expr *E)
Definition Visitor.h:65
bool visitExpr(const nix::Expr *)
Definition Visitor.h:52
Derived & getDerived()
Definition Visitor.h:63