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