|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef SRC_DEVELOPER_SHELL_PARSER_AST_H_ | 
|  | #define SRC_DEVELOPER_SHELL_PARSER_AST_H_ | 
|  |  | 
|  | #include <lib/syslog/cpp/macros.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <optional> | 
|  | #include <string> | 
|  | #include <string_view> | 
|  | #include <variant> | 
|  | #include <vector> | 
|  |  | 
|  | namespace shell::parser::ast { | 
|  |  | 
|  | class Node; | 
|  | class Terminal; | 
|  | class Nonterminal; | 
|  | class Error; | 
|  | class Program; | 
|  | class VariableDecl; | 
|  | class Identifier; | 
|  | class Integer; | 
|  | class Expression; | 
|  | class DecimalGroup; | 
|  | class HexGroup; | 
|  | class UnescapedIdentifier; | 
|  | class StringEntity; | 
|  | class EscapeSequence; | 
|  | class PathElement; | 
|  | class PathEscape; | 
|  | class PathSeparator; | 
|  | class Operator; | 
|  | class String; | 
|  | class Object; | 
|  | class Field; | 
|  | class Path; | 
|  | class AddSub; | 
|  |  | 
|  | template <typename T = void> | 
|  | class NodeVisitor; | 
|  |  | 
|  | template <typename T> | 
|  | class WrappingVisitor; | 
|  |  | 
|  | // A node in our AST. | 
|  | class Node { | 
|  | public: | 
|  | explicit Node(size_t start) : start_(start) {} | 
|  | virtual ~Node() = default; | 
|  |  | 
|  | size_t start() const { return start_; } | 
|  |  | 
|  | // Child nodes of this node. Always empty for terminals, may be empty for non-terminals. | 
|  | virtual const std::vector<std::shared_ptr<Node>>& Children() const = 0; | 
|  |  | 
|  | // Create an s-expression-like string representation of this node. We don't store the parsed text | 
|  | // in the node itself so we must be passed the original parsed string. | 
|  | virtual std::string ToString(std::string_view unit) const = 0; | 
|  |  | 
|  | // Number of characters this node corresponds to in the original text. | 
|  | virtual size_t Size() const = 0; | 
|  |  | 
|  | // Whether this node marks a parse error. | 
|  | virtual bool IsError() const { return false; } | 
|  |  | 
|  | // Whether this node is a whitespace node. | 
|  | virtual bool IsWhitespace() const { return false; } | 
|  |  | 
|  | // Whether this node or any of its children contains parse errors. | 
|  | virtual bool HasErrors() const { return IsError(); } | 
|  |  | 
|  | // Visit this node with a visitor. | 
|  | template <typename T> | 
|  | T Visit(NodeVisitor<T>* visitor) const { | 
|  | WrappingVisitor wrapped(visitor); | 
|  | Visit(&wrapped); | 
|  | return std::move(wrapped.result); | 
|  | } | 
|  | template <> | 
|  | void Visit<void>(NodeVisitor<void>* visitor) const { | 
|  | VisitVoid(visitor); | 
|  | } | 
|  |  | 
|  | // Downcasting methods | 
|  | virtual Error* AsError() { return nullptr; } | 
|  | const Error* AsError() const { return const_cast<Node*>(this)->AsError(); } | 
|  | virtual Program* AsProgram() { return nullptr; } | 
|  | const Program* AsProgram() const { return const_cast<Node*>(this)->AsProgram(); } | 
|  | virtual VariableDecl* AsVariableDecl() { return nullptr; } | 
|  | const VariableDecl* AsVariableDecl() const { return const_cast<Node*>(this)->AsVariableDecl(); } | 
|  | virtual Identifier* AsIdentifier() { return nullptr; } | 
|  | const Identifier* AsIdentifier() const { return const_cast<Node*>(this)->AsIdentifier(); } | 
|  | virtual Integer* AsInteger() { return nullptr; } | 
|  | const Integer* AsInteger() const { return const_cast<Node*>(this)->AsInteger(); } | 
|  | virtual Expression* AsExpression() { return nullptr; } | 
|  | const Expression* AsExpression() const { return const_cast<Node*>(this)->AsExpression(); } | 
|  | virtual DecimalGroup* AsDecimalGroup() { return nullptr; } | 
|  | const DecimalGroup* AsDecimalGroup() const { return const_cast<Node*>(this)->AsDecimalGroup(); } | 
|  | virtual HexGroup* AsHexGroup() { return nullptr; } | 
|  | const HexGroup* AsHexGroup() const { return const_cast<Node*>(this)->AsHexGroup(); } | 
|  | virtual UnescapedIdentifier* AsUnescapedIdentifier() { return nullptr; } | 
|  | const UnescapedIdentifier* AsUnescapedIdentifier() const { | 
|  | return const_cast<Node*>(this)->AsUnescapedIdentifier(); | 
|  | } | 
|  | virtual StringEntity* AsStringEntity() { return nullptr; } | 
|  | const StringEntity* AsStringEntity() const { return const_cast<Node*>(this)->AsStringEntity(); } | 
|  | virtual EscapeSequence* AsEscapeSequence() { return nullptr; } | 
|  | const EscapeSequence* AsEscapeSequence() const { | 
|  | return const_cast<Node*>(this)->AsEscapeSequence(); | 
|  | } | 
|  | virtual PathElement* AsPathElement() { return nullptr; } | 
|  | const PathElement* AsPathElement() const { return const_cast<Node*>(this)->AsPathElement(); } | 
|  | virtual PathEscape* AsPathEscape() { return nullptr; } | 
|  | const PathEscape* AsPathEscape() const { return const_cast<Node*>(this)->AsPathEscape(); } | 
|  | virtual Operator* AsOperator() { return nullptr; } | 
|  | const Operator* AsOperator() const { return const_cast<Node*>(this)->AsOperator(); } | 
|  | virtual String* AsString() { return nullptr; } | 
|  | const String* AsString() const { return const_cast<Node*>(this)->AsString(); } | 
|  | virtual Object* AsObject() { return nullptr; } | 
|  | const Object* AsObject() const { return const_cast<Node*>(this)->AsObject(); } | 
|  | virtual Field* AsField() { return nullptr; } | 
|  | const Field* AsField() const { return const_cast<Node*>(this)->AsField(); } | 
|  | virtual Path* AsPath() { return nullptr; } | 
|  | const Path* AsPath() const { return const_cast<Node*>(this)->AsPath(); } | 
|  | virtual AddSub* AsAddSub() { return nullptr; } | 
|  | const AddSub* AsAddSub() const { return const_cast<Node*>(this)->AsAddSub(); } | 
|  |  | 
|  | // ID methods for keywords | 
|  | virtual bool IsConst() const { return false; } | 
|  | virtual bool IsVar() const { return false; } | 
|  | virtual bool IsFieldSeparator() const { return false; } | 
|  | virtual bool IsPathSeparator() const { return false; } | 
|  |  | 
|  | private: | 
|  | virtual void VisitVoid(NodeVisitor<void>* visitor) const = 0; | 
|  |  | 
|  | // Offset into the original text where the text this node corresponds to starts. | 
|  | const size_t start_; | 
|  | }; | 
|  |  | 
|  | // Superclass of all terminal nodes in our AST. | 
|  | class Terminal : public Node { | 
|  | public: | 
|  | Terminal(size_t start, size_t size, std::string_view /*content*/) : Node(start), size_(size) {} | 
|  |  | 
|  | const std::vector<std::shared_ptr<Node>>& Children() const override { return kEmptyChildren; } | 
|  | size_t Size() const override { return size_; } | 
|  |  | 
|  | std::string ToString(std::string_view unit) const override; | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | static const std::vector<std::shared_ptr<Node>> kEmptyChildren; | 
|  |  | 
|  | const size_t size_; | 
|  | }; | 
|  |  | 
|  | class Error : public Terminal { | 
|  | public: | 
|  | Error(size_t start, size_t size, std::string_view message) | 
|  | : Terminal(start, size, ""), message_(message) {} | 
|  |  | 
|  | const std::string& message() const { return message_; } | 
|  |  | 
|  | bool IsError() const override { return true; } | 
|  |  | 
|  | std::string ToString(std::string_view unit) const override; | 
|  | Error* AsError() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | const std::string message_; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a ":". | 
|  | class FieldSeparator : public Terminal { | 
|  | public: | 
|  | FieldSeparator(size_t start, size_t size, std::string_view content) | 
|  | : Terminal(start, size, content) {} | 
|  |  | 
|  | bool IsFieldSeparator() const override { return true; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | // Terminal representing the "const" keyword. | 
|  | class Const : public Terminal { | 
|  | public: | 
|  | Const(size_t start, size_t size, std::string_view content) : Terminal(start, size, content) {} | 
|  |  | 
|  | bool IsConst() const override { return true; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | // Terminal representing the "var" keyword. | 
|  | class Var : public Terminal { | 
|  | public: | 
|  | Var(size_t start, size_t size, std::string_view content) : Terminal(start, size, content) {} | 
|  |  | 
|  | bool IsVar() const override { return true; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a sequence of decimal digits. | 
|  | class DecimalGroup : public Terminal { | 
|  | public: | 
|  | DecimalGroup(size_t start, size_t size, std::string_view content); | 
|  |  | 
|  | size_t digits() const { return digits_; } | 
|  | uint64_t value() const { return value_; } | 
|  |  | 
|  | DecimalGroup* AsDecimalGroup() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | size_t digits_; | 
|  | uint64_t value_ = 0; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a sequence of hex digits. | 
|  | class HexGroup : public Terminal { | 
|  | public: | 
|  | HexGroup(size_t start, size_t size, std::string_view content); | 
|  |  | 
|  | size_t digits() const { return digits_; } | 
|  | uint64_t value() const { return value_; } | 
|  |  | 
|  | HexGroup* AsHexGroup() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | size_t digits_; | 
|  | uint64_t value_ = 0; | 
|  | }; | 
|  |  | 
|  | // Terminal representing an unescaped identifier | 
|  | class UnescapedIdentifier : public Terminal { | 
|  | public: | 
|  | UnescapedIdentifier(size_t start, size_t size, std::string_view content) | 
|  | : Terminal(start, size, content), identifier_(content) {} | 
|  |  | 
|  | const std::string& identifier() const { return identifier_; } | 
|  |  | 
|  | UnescapedIdentifier* AsUnescapedIdentifier() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string identifier_ = ""; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a piece of a string literal. | 
|  | class StringEntity : public Terminal { | 
|  | public: | 
|  | StringEntity(size_t start, size_t size, std::string_view content) | 
|  | : Terminal(start, size, content), content_(content) {} | 
|  |  | 
|  | const std::string& content() const { return content_; } | 
|  |  | 
|  | StringEntity* AsStringEntity() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string content_ = ""; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a piece of an escape sequence in a string literal. | 
|  | class EscapeSequence : public StringEntity { | 
|  | public: | 
|  | EscapeSequence(size_t start, size_t size, std::string_view content) | 
|  | : StringEntity(start, size, Decode(content)) {} | 
|  |  | 
|  | EscapeSequence* AsEscapeSequence() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | static std::string Decode(std::string_view sequence); | 
|  | }; | 
|  |  | 
|  | // Terminal representing a continuous piece of a path. | 
|  | class PathElement : public Terminal { | 
|  | public: | 
|  | PathElement(size_t start, size_t size, std::string_view content) | 
|  | : Terminal(start, size, content), content_(content) {} | 
|  |  | 
|  | const std::string& content() const { return content_; } | 
|  |  | 
|  | PathElement* AsPathElement() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string content_ = ""; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a piece of an escape sequence in a path. | 
|  | class PathEscape : public PathElement { | 
|  | public: | 
|  | PathEscape(size_t start, size_t size, std::string_view content) | 
|  | : PathElement(start, size, content.substr(1)) {} | 
|  |  | 
|  | PathEscape* AsPathEscape() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | // Terminal representing a path separator. | 
|  | class PathSeparator : public Terminal { | 
|  | public: | 
|  | PathSeparator(size_t start, size_t size, std::string_view content) | 
|  | : Terminal(start, size, content) {} | 
|  |  | 
|  | bool IsPathSeparator() const override { return true; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | // Terminal representing an operator. | 
|  | class Operator : public Terminal { | 
|  | public: | 
|  | Operator(size_t start, size_t size, std::string_view content) | 
|  | : Terminal(start, size, content), operator_(content) {} | 
|  |  | 
|  | const std::string& op() const { return operator_; } | 
|  |  | 
|  | Operator* AsOperator() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string operator_ = ""; | 
|  | }; | 
|  |  | 
|  | // Superclass of all non-terminal nodes in our AST. | 
|  | class Nonterminal : public Node { | 
|  | public: | 
|  | Nonterminal(size_t start, std::vector<std::shared_ptr<Node>> children) | 
|  | : Node(start), children_(std::move(children)) { | 
|  | for (const auto& child : children_) { | 
|  | if (child->HasErrors()) { | 
|  | has_errors_ = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Name of this node as a string. | 
|  | virtual std::string_view Name() const = 0; | 
|  |  | 
|  | const std::vector<std::shared_ptr<Node>>& Children() const override { return children_; } | 
|  | size_t Size() const override { | 
|  | if (children_.empty()) { | 
|  | return 0; | 
|  | } else { | 
|  | return children_.back()->start() - start() + children_.back()->Size(); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string ToString(std::string_view unit) const override; | 
|  |  | 
|  | bool HasErrors() const override { return has_errors_; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | bool has_errors_ = false; | 
|  | std::vector<std::shared_ptr<Node>> children_; | 
|  | }; | 
|  |  | 
|  | // Result of an attempt to parse a single token. Usually that will result in a terminal, but if | 
|  | // there are errors, we may get one of these instead. Its children will be error nodes and the | 
|  | // fragments of the token that parsed correctly. | 
|  | class TokenResult : public Nonterminal { | 
|  | public: | 
|  | TokenResult(size_t start, std::vector<std::shared_ptr<Node>> children) | 
|  | : Nonterminal(start, std::move(children)) {} | 
|  |  | 
|  | std::string_view Name() const override { return ""; } | 
|  |  | 
|  | // If one of these ends up in output outside of the Token() combinator, then it's definitely an | 
|  | // error. | 
|  | bool IsError() const override { return true; } | 
|  | }; | 
|  |  | 
|  | class Whitespace : public Nonterminal { | 
|  | public: | 
|  | Whitespace(size_t start, std::vector<std::shared_ptr<Node>> children) | 
|  | : Nonterminal(start, std::move(children)) {} | 
|  |  | 
|  | std::string_view Name() const override { return "Whitespace"; } | 
|  | bool IsWhitespace() const override { return true; } | 
|  | }; | 
|  |  | 
|  | class Program : public Nonterminal { | 
|  | public: | 
|  | Program(size_t start, std::vector<std::shared_ptr<Node>> children) | 
|  | : Nonterminal(start, std::move(children)) {} | 
|  |  | 
|  | std::string_view Name() const override { return "Program"; } | 
|  | Program* AsProgram() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | class VariableDecl : public Nonterminal { | 
|  | public: | 
|  | VariableDecl(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | const std::string& identifier() const { return identifier_; } | 
|  | Expression* expression() const { return expression_; } | 
|  | bool is_const() const { return is_const_; } | 
|  |  | 
|  | std::string_view Name() const override { return "VariableDecl"; } | 
|  | VariableDecl* AsVariableDecl() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | Expression* expression_ = nullptr; | 
|  | bool is_const_ = false; | 
|  | std::string identifier_ = ""; | 
|  | }; | 
|  |  | 
|  | class Integer : public Nonterminal { | 
|  | public: | 
|  | Integer(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | uint64_t value() const { return value_; } | 
|  |  | 
|  | std::string_view Name() const override { return "Integer"; } | 
|  |  | 
|  | Integer* AsInteger() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | uint64_t value_ = 0; | 
|  | }; | 
|  |  | 
|  | class String : public Nonterminal { | 
|  | public: | 
|  | String(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | const std::string& value() const { return value_; } | 
|  |  | 
|  | std::string_view Name() const override { return "String"; } | 
|  |  | 
|  | String* AsString() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string value_; | 
|  | }; | 
|  |  | 
|  | class Identifier : public Nonterminal { | 
|  | public: | 
|  | Identifier(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | const std::string& identifier() const { return identifier_; } | 
|  |  | 
|  | std::string_view Name() const override { return "Identifier"; } | 
|  |  | 
|  | Identifier* AsIdentifier() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string identifier_; | 
|  | }; | 
|  |  | 
|  | class Object : public Nonterminal { | 
|  | public: | 
|  | Object(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | const std::vector<Field*> fields() const { return fields_; } | 
|  |  | 
|  | std::string_view Name() const override { return "Object"; } | 
|  |  | 
|  | Object* AsObject() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::vector<Field*> fields_; | 
|  | }; | 
|  |  | 
|  | class Field : public Nonterminal { | 
|  | public: | 
|  | Field(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | const std::string& name() const { return name_; } | 
|  | Node* value() const { return value_; } | 
|  |  | 
|  | std::string_view Name() const override { return "Field"; } | 
|  |  | 
|  | Field* AsField() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | std::string name_; | 
|  | Node* value_ = nullptr; | 
|  | }; | 
|  |  | 
|  | class Path : public Nonterminal { | 
|  | public: | 
|  | Path(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | bool is_local() const { return is_local_; } | 
|  | const std::vector<std::string>& elements() const { return elements_; } | 
|  |  | 
|  | std::string_view Name() const override { return "Path"; } | 
|  |  | 
|  | Path* AsPath() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | bool is_local_; | 
|  | std::vector<std::string> elements_; | 
|  | }; | 
|  |  | 
|  | class AddSub : public Nonterminal { | 
|  | public: | 
|  | enum Type { | 
|  | kAdd, | 
|  | kSubtract, | 
|  | }; | 
|  |  | 
|  | AddSub(size_t start, std::vector<std::shared_ptr<Node>> children); | 
|  |  | 
|  | Type type() const { return type_; } | 
|  | Node* a() const { return a_; } | 
|  | Node* b() const { return b_; } | 
|  |  | 
|  | std::string_view Name() const override { return "AddSub"; } | 
|  |  | 
|  | AddSub* AsAddSub() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  |  | 
|  | Type type_ = kAdd; | 
|  | Node* a_ = nullptr; | 
|  | Node* b_ = nullptr; | 
|  | }; | 
|  |  | 
|  | class Expression : public Nonterminal { | 
|  | public: | 
|  | Expression(size_t start, std::vector<std::shared_ptr<Node>> children) | 
|  | : Nonterminal(start, std::move(children)) {} | 
|  |  | 
|  | std::string_view Name() const override { return "Expression"; } | 
|  | Expression* AsExpression() override { return this; } | 
|  |  | 
|  | private: | 
|  | void VisitVoid(NodeVisitor<void>* visitor) const override; | 
|  | }; | 
|  |  | 
|  | // Visitor for AST nodes. | 
|  | template <typename T> | 
|  | class NodeVisitor { | 
|  | friend class Node; | 
|  | friend class Terminal; | 
|  | friend class Nonterminal; | 
|  | friend class Error; | 
|  | friend class Var; | 
|  | friend class Const; | 
|  | friend class FieldSeparator; | 
|  | friend class Program; | 
|  | friend class VariableDecl; | 
|  | friend class Identifier; | 
|  | friend class Integer; | 
|  | friend class Expression; | 
|  | friend class DecimalGroup; | 
|  | friend class HexGroup; | 
|  | friend class UnescapedIdentifier; | 
|  | friend class StringEntity; | 
|  | friend class EscapeSequence; | 
|  | friend class PathElement; | 
|  | friend class PathEscape; | 
|  | friend class PathSeparator; | 
|  | friend class Operator; | 
|  | friend class String; | 
|  | friend class Object; | 
|  | friend class Field; | 
|  | friend class Path; | 
|  | friend class AddSub; | 
|  |  | 
|  | friend class WrappingVisitor<T>; | 
|  |  | 
|  | protected: | 
|  | virtual T VisitNode(const Node& node) { | 
|  | if constexpr (!std::is_void<T>::value) { | 
|  | FX_NOTREACHED(); | 
|  | std::terminate(); | 
|  | } | 
|  | } | 
|  |  | 
|  | virtual T VisitTerminal(const Terminal& node) { return VisitNode(node); }; | 
|  | virtual T VisitNonterminal(const Nonterminal& node) { return VisitNode(node); }; | 
|  | virtual T VisitError(const Error& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitConst(const Const& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitVar(const Var& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitFieldSeparator(const FieldSeparator& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitProgram(const Program& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitVariableDecl(const VariableDecl& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitIdentifier(const Identifier& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitInteger(const Integer& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitExpression(const Expression& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitDecimalGroup(const DecimalGroup& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitHexGroup(const HexGroup& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitUnescapedIdentifier(const UnescapedIdentifier& node) { | 
|  | return VisitTerminal(node); | 
|  | }; | 
|  | virtual T VisitStringEntity(const StringEntity& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitEscapeSequence(const EscapeSequence& node) { return VisitStringEntity(node); }; | 
|  | virtual T VisitString(const String& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitObject(const Object& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitField(const Field& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitPathElement(const PathElement& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitPathEscape(const PathEscape& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitPathSeparator(const PathSeparator& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitOperator(const Operator& node) { return VisitTerminal(node); }; | 
|  | virtual T VisitPath(const Path& node) { return VisitNonterminal(node); }; | 
|  | virtual T VisitAddSub(const AddSub& node) { return VisitNonterminal(node); }; | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class WrappingVisitor : public NodeVisitor<void> { | 
|  | public: | 
|  | WrappingVisitor(NodeVisitor<T>* wrapped) : wrapped_(wrapped) {} | 
|  |  | 
|  | T result; | 
|  |  | 
|  | private: | 
|  | void VisitNode(const Node& node) override { result = wrapped_->VisitNode(node); } | 
|  | void VisitTerminal(const Terminal& node) override { result = wrapped_->VisitTerminal(node); } | 
|  | void VisitNonterminal(const Nonterminal& node) override { | 
|  | result = wrapped_->VisitNonterminal(node); | 
|  | } | 
|  | void VisitError(const Error& node) override { result = wrapped_->VisitError(node); } | 
|  | void VisitConst(const Const& node) override { result = wrapped_->VisitConst(node); } | 
|  | void VisitVar(const Var& node) override { result = wrapped_->VisitVar(node); } | 
|  | void VisitFieldSeparator(const FieldSeparator& node) override { | 
|  | result = wrapped_->VisitFieldSeparator(node); | 
|  | } | 
|  | void VisitProgram(const Program& node) override { result = wrapped_->VisitProgram(node); } | 
|  | void VisitVariableDecl(const VariableDecl& node) override { | 
|  | result = wrapped_->VisitVariableDecl(node); | 
|  | } | 
|  | void VisitIdentifier(const Identifier& node) override { | 
|  | result = wrapped_->VisitIdentifier(node); | 
|  | } | 
|  | void VisitInteger(const Integer& node) override { result = wrapped_->VisitInteger(node); } | 
|  | void VisitExpression(const Expression& node) override { | 
|  | result = wrapped_->VisitExpression(node); | 
|  | } | 
|  | void VisitDecimalGroup(const DecimalGroup& node) override { | 
|  | result = wrapped_->VisitDecimalGroup(node); | 
|  | } | 
|  | void VisitHexGroup(const HexGroup& node) override { result = wrapped_->VisitHexGroup(node); } | 
|  | void VisitUnescapedIdentifier(const UnescapedIdentifier& node) override { | 
|  | result = wrapped_->VisitUnescapedIdentifier(node); | 
|  | } | 
|  | void VisitStringEntity(const StringEntity& node) override { | 
|  | result = wrapped_->VisitStringEntity(node); | 
|  | } | 
|  | void VisitEscapeSequence(const EscapeSequence& node) override { | 
|  | result = wrapped_->VisitEscapeSequence(node); | 
|  | } | 
|  | void VisitString(const String& node) override { result = wrapped_->VisitString(node); } | 
|  | void VisitObject(const Object& node) override { result = wrapped_->VisitObject(node); } | 
|  | void VisitField(const Field& node) override { result = wrapped_->VisitField(node); } | 
|  | void VisitPathElement(const PathElement& node) override { | 
|  | result = wrapped_->VisitPathElement(node); | 
|  | } | 
|  | void VisitPathEscape(const PathEscape& node) override { | 
|  | result = wrapped_->VisitPathEscape(node); | 
|  | } | 
|  | void VisitPathSeparator(const PathSeparator& node) override { | 
|  | result = wrapped_->VisitPathSeparator(node); | 
|  | } | 
|  | void VisitOperator(const Operator& node) override { result = wrapped_->VisitOperator(node); } | 
|  | void VisitPath(const Path& node) override { result = wrapped_->VisitPath(node); } | 
|  | void VisitAddSub(const AddSub& node) override { result = wrapped_->VisitAddSub(node); } | 
|  |  | 
|  | NodeVisitor<T>* wrapped_; | 
|  | }; | 
|  |  | 
|  | }  // namespace shell::parser::ast | 
|  |  | 
|  | #endif  // SRC_DEVELOPER_SHELL_PARSER_AST_H_ |