Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / frontend / ParseNodeVisitor.h
blob18e57d68e61c8c24ce0efa32e7dbc1c843fccfc8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef frontend_ParseNodeVisitor_h
8 #define frontend_ParseNodeVisitor_h
10 #include "mozilla/Assertions.h"
12 #include "frontend/ParseNode.h"
13 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
15 namespace js {
17 class FrontendContext;
19 namespace frontend {
21 /**
22 * Utility class for walking a JS AST.
24 * Simple usage:
26 * class HowTrueVisitor : public ParseNodeVisitor<HowTrueVisitor> {
27 * public:
28 * bool visitTrueExpr(BooleanLiteral* pn) {
29 * std::cout << "How true.\n";
30 * return true;
31 * }
32 * bool visitClassDecl(ClassNode* pn) {
33 * // The base-class implementation of each visit method
34 * // simply visits the node's children. So the subclass
35 * // gets to decide whether to descend into a subtree
36 * // and can do things either before or after:
37 * std::cout << "How classy.\n";
38 * return ParseNodeVisitor::visitClassDecl(pn);
39 * }
40 * };
42 * HowTrueVisitor v;
43 * v.visit(programRootNode); // walks the entire tree
45 * A ParseNodeVisitor can modify nodes, but it can't replace the current node
46 * with a different one; for that, use a RewritingParseNodeVisitor.
48 * Note that the Curiously Recurring Template Pattern is used for performance,
49 * as it eliminates the need for virtual method calls. Some rough testing shows
50 * about a 12% speedup in the FoldConstants.cpp pass.
51 * https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
53 template <typename Derived>
54 class ParseNodeVisitor {
55 public:
56 FrontendContext* fc_;
58 explicit ParseNodeVisitor(FrontendContext* fc) : fc_(fc) {}
60 [[nodiscard]] bool visit(ParseNode* pn) {
61 AutoCheckRecursionLimit recursion(fc_);
62 if (!recursion.check(fc_)) {
63 return false;
66 switch (pn->getKind()) {
67 #define VISIT_CASE(KIND, TYPE) \
68 case ParseNodeKind::KIND: \
69 return static_cast<Derived*>(this)->visit##KIND(&pn->as<TYPE>());
70 FOR_EACH_PARSE_NODE_KIND(VISIT_CASE)
71 #undef VISIT_CASE
72 default:
73 MOZ_CRASH("invalid node kind");
77 // using static_cast<Derived*> here allows plain visit() to be overridden.
78 #define VISIT_METHOD(KIND, TYPE) \
79 [[nodiscard]] bool visit##KIND(TYPE* pn) { /* NOLINT */ \
80 return pn->accept(*static_cast<Derived*>(this)); \
82 FOR_EACH_PARSE_NODE_KIND(VISIT_METHOD)
83 #undef VISIT_METHOD
87 * Utility class for walking a JS AST that allows for replacing nodes.
89 * The API is the same as ParseNodeVisitor, except that visit methods take an
90 * argument of type `ParseNode*&`, a reference to the field in the parent node
91 * that points down to the node being visited. Methods can replace the current
92 * node by assigning to this reference.
94 * All visit methods take a `ParseNode*&` rather than more specific types like
95 * `BinaryNode*&`, to allow replacing the current node with one of a different
96 * type. Constant folding makes use of this.
98 template <typename Derived>
99 class RewritingParseNodeVisitor {
100 public:
101 FrontendContext* fc_;
103 explicit RewritingParseNodeVisitor(FrontendContext* fc) : fc_(fc) {}
105 [[nodiscard]] bool visit(ParseNode*& pn) {
106 AutoCheckRecursionLimit recursion(fc_);
107 if (!recursion.check(fc_)) {
108 return false;
111 switch (pn->getKind()) {
112 #define VISIT_CASE(KIND, _type) \
113 case ParseNodeKind::KIND: \
114 return static_cast<Derived*>(this)->visit##KIND(pn);
115 FOR_EACH_PARSE_NODE_KIND(VISIT_CASE)
116 #undef VISIT_CASE
117 default:
118 MOZ_CRASH("invalid node kind");
122 // using static_cast<Derived*> here allows plain visit() to be overridden.
123 #define VISIT_METHOD(KIND, TYPE) \
124 [[nodiscard]] bool visit##KIND(ParseNode*& pn) { \
125 MOZ_ASSERT(pn->is<TYPE>(), \
126 "Node of kind " #KIND " was not of type " #TYPE); \
127 return pn->as<TYPE>().accept(*static_cast<Derived*>(this)); \
129 FOR_EACH_PARSE_NODE_KIND(VISIT_METHOD)
130 #undef VISIT_METHOD
133 } // namespace frontend
134 } // namespace js
136 #endif // frontend_ParseNodeVisitor_h