| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef _GYOJI_INTERNAL | ||
| 2 | #error "This header is intended to be used internally as a part of the Gyoji front-end. Please include frontend.hpp instead." | ||
| 3 | #endif | ||
| 4 | #pragma once | ||
| 5 | |||
| 6 | /*! | ||
| 7 | * \addtogroup Frontend | ||
| 8 | * @{ | ||
| 9 | */ | ||
| 10 | |||
| 11 | /** | ||
| 12 | * @brief Abstract syntax tree | ||
| 13 | * | ||
| 14 | * @details | ||
| 15 | * Weakly-typed representation of the parse tree | ||
| 16 | * resulting from reading and parsing an input file. | ||
| 17 | * While the interface to the data is weakly typed, | ||
| 18 | * the underlying data can be accessed through | ||
| 19 | * a variant that exposes all of the different | ||
| 20 | * types of production that the grammar can produce. | ||
| 21 | */ | ||
| 22 | namespace Gyoji::frontend::ast { | ||
| 23 | |||
| 24 | /** | ||
| 25 | * @brief Weakly-typed syntax node | ||
| 26 | * | ||
| 27 | * @details | ||
| 28 | * The syntax tree can be viewed as a tree of nodes | ||
| 29 | * that follow the structure of the parsed grammar. | ||
| 30 | * | ||
| 31 | * This view of the syntax tree can be processed | ||
| 32 | * in a weakly-typed sense where each node of | ||
| 33 | * type SyntaxNode may have zero or more children | ||
| 34 | * that represent grammar productions below them. | ||
| 35 | * | ||
| 36 | * Each of these nodes can also, optionally, be | ||
| 37 | * examined to find the specific strongly-typed | ||
| 38 | * tree node corresponding to the data parsed. | ||
| 39 | * | ||
| 40 | * For example, the top-level SyntaxNode will hold | ||
| 41 | * a TranslationUnit so that it can be extracted: | ||
| 42 | * | ||
| 43 | * <pre> | ||
| 44 | * SyntaxNode *s; | ||
| 45 | * if (s->holds_alternative<TranslationUnit>()) { | ||
| 46 | * const TranslationUnit & tu = s->get<TranslationUnit>(); | ||
| 47 | * } | ||
| 48 | * </pre> | ||
| 49 | * | ||
| 50 | * The leaf nodes of the SyntaxTree will always be of | ||
| 51 | * type "Terminal" indicating that it is a "terminal" | ||
| 52 | * symbol of the grammer which corresponds to a parsed | ||
| 53 | * token from the lexer (gyoji.l). | ||
| 54 | */ | ||
| 55 | class SyntaxNode { | ||
| 56 | public: | ||
| 57 | typedef std::variant<GYOJI_SYNTAX_NODE_VARIANT_LIST> specific_type_t; | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Create a new syntax node of the given type holding | ||
| 61 | * the data associated with that production in the BNF | ||
| 62 | * grammar. | ||
| 63 | * @param _type Type of node this represents. | ||
| 64 | * @param _data The specific data associated with this node. | ||
| 65 | */ | ||
| 66 | SyntaxNode(Gyoji::context::TokenID _type, specific_type_t _data, const Gyoji::context::SourceReference & _source_ref); | ||
| 67 | ~SyntaxNode(); | ||
| 68 | |||
| 69 | |||
| 70 | /** | ||
| 71 | * This method returns a reference to an immutable array | ||
| 72 | * of children of this node. | ||
| 73 | */ | ||
| 74 | const std::vector<std::reference_wrapper<const SyntaxNode>> & get_children() const; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * This method returns an immutable reference to | ||
| 78 | * the type of the node. | ||
| 79 | */ | ||
| 80 | const Gyoji::context::TokenID & get_type() const; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * This interrogates the node to determine if it | ||
| 84 | * contains data of the specified type T. | ||
| 85 | * @tparam T Check type T to see if it is held in this node. | ||
| 86 | * @return True if this class contains that specific type of data. | ||
| 87 | */ | ||
| 88 | 46784 | template <class T> bool has_data() const { | |
| 89 | 46784 | return std::holds_alternative<T*>(data); | |
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * This returns an immutable reference to the | ||
| 94 | * data of type T contained in this node. | ||
| 95 | * Note that this is only safe to use if the | ||
| 96 | * holds_alternative<T>() returns true for | ||
| 97 | * this specific type. | ||
| 98 | * @tparam T The type of data to return. | ||
| 99 | */ | ||
| 100 | 16496 | template <class T> const T &get_data() const { | |
| 101 | 16496 | const T *d = std::get<T*>(data); | |
| 102 | 16496 | return *d; | |
| 103 | } | ||
| 104 | |||
| 105 | /** | ||
| 106 | * This method is provided so that callers | ||
| 107 | * of derived classes can be sure to get access | ||
| 108 | * to the SyntaxNode base-class instance. | ||
| 109 | */ | ||
| 110 | const SyntaxNode & get_syntax_node() const; | ||
| 111 | |||
| 112 | /** | ||
| 113 | * Returns the source reference for where | ||
| 114 | * this node appears in the source tree. | ||
| 115 | */ | ||
| 116 | const Gyoji::context::SourceReference & get_source_ref() const; | ||
| 117 | |||
| 118 | private: | ||
| 119 | // This list does NOT own its children, so | ||
| 120 | // the class deriving from this one must | ||
| 121 | // agree to own the pointers separately. | ||
| 122 | std::vector<std::reference_wrapper<const SyntaxNode>> children; | ||
| 123 | const Gyoji::context::SourceReference & source_ref; | ||
| 124 | |||
| 125 | protected: | ||
| 126 | // Children are owned by their parents, so this is | ||
| 127 | // private and can only be called by the | ||
| 128 | // deriving class. | ||
| 129 | void add_child(const SyntaxNode & node); | ||
| 130 | void prepend_child(const SyntaxNode & node); | ||
| 131 | |||
| 132 | Gyoji::context::TokenID type; | ||
| 133 | specific_type_t data; | ||
| 134 | |||
| 135 | }; | ||
| 136 | |||
| 137 | }; | ||
| 138 | /*! @} End of Doxygen Groups*/ | ||
| 139 |