1 /* 2 * The Doomsday Engine Project -- libcore 3 * 4 * Copyright © 2004-2017 Jaakko Keränen <jaakko.keranen@iki.fi> 5 * 6 * @par License 7 * LGPL: http://www.gnu.org/licenses/lgpl.html 8 * 9 * <small>This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as published by 11 * the Free Software Foundation; either version 3 of the License, or (at your 12 * option) any later version. This program is distributed in the hope that it 13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. You should have received a copy of 16 * the GNU Lesser General Public License along with this program; if not, see: 17 * http://www.gnu.org/licenses</small> 18 */ 19 20 #ifndef LIBDENG2_TOKENRANGE_H 21 #define LIBDENG2_TOKENRANGE_H 22 23 #include "../String" 24 #include "../TokenBuffer" 25 26 namespace de { 27 28 /** 29 * Utility class for handling a range of tokens inside a token buffer. 30 * Parsers use this for keeping track of which section of the tokens is 31 * being analyzed. 32 * 33 * "Indices" refer to indices in the token buffer. "Positions" refer to 34 * locations relative to the beginning of the range, starting from zero. 35 * 36 * @ingroup script 37 */ 38 class DENG2_PUBLIC TokenRange 39 { 40 public: 41 /// The token range is unexpectedly empty. @ingroup errors 42 DENG2_ERROR(EmptyRangeError); 43 44 /// A position outside the range is accessed. @ingroup errors 45 DENG2_ERROR(OutOfBoundsError); 46 47 /// A matching bracket cannot be located within the range. @ingroup errors 48 DENG2_ERROR(MismatchedBracketError); 49 50 public: 51 TokenRange(); 52 53 /// Constructor that uses the entire range of tokens. 54 TokenRange(TokenBuffer const &tokens); 55 56 /// Constructor that uses a specific set of tokens. 57 TokenRange(TokenBuffer const &tokens, duint startIndex, duint endIndex); 58 buffer()59 TokenBuffer const &buffer() const { 60 return *_tokens; 61 } 62 63 /// Determines the length of the range. 64 /// @return Number of tokens in the range. size()65 duint size() const { 66 return _end - _start; 67 } 68 isEmpty()69 bool isEmpty() const { return !size(); } 70 71 TokenRange undefinedRange() const; 72 73 bool undefined() const; 74 75 /// Converts a position within the range to an index in the buffer. 76 duint tokenIndex(duint pos) const; 77 78 duint tokenPos(duint index) const; 79 80 /// Returns a specific token from the token buffer. 81 /// @param pos Position of the token within the range. 82 Token const &token(duint pos) const; 83 84 Token const &firstToken() const; 85 86 Token const &lastToken() const; 87 88 /// Determines whether the range begins with a specific token. 89 bool beginsWith(QChar const *token) const; 90 91 /** 92 * Composes a subrange that starts from a specific position. 93 * 94 * @param pos Start position of subrange. 95 * 96 * @return Subrange that starts from position @a pos and continues until 97 * the end of the range. 98 */ 99 TokenRange startingFrom(duint pos) const; 100 101 /** 102 * Composes a subrange that ends at a specific position. 103 * 104 * @param pos End position of subrange. 105 * 106 * @return Subrange that starts from the beginning of this range 107 * and ends to @a pos. 108 */ 109 TokenRange endingTo(duint pos) const; 110 111 TokenRange between(duint startPos, duint endPos) const; 112 shrink(duint count)113 TokenRange shrink(duint count) const { 114 return between(count, size() - count); 115 } 116 117 /** 118 * Determines if the range contains a specific token. 119 * 120 * @param token Token to look for. 121 * 122 * @return @c true, if token was found, otherwise @c false. 123 */ has(QChar const * token)124 bool has(QChar const *token) const { 125 return find(token) >= 0; 126 } 127 128 /** 129 * Determines if the range contains a specific token, but only if 130 * it is outside any brackets. 131 * 132 * @param token Token to look for. 133 * 134 * @return @c true, if token was found, otherwise @c false. 135 */ hasBracketless(QChar const * token)136 bool hasBracketless(QChar const *token) const { 137 return findIndexSkippingBrackets(token, _start) >= 0; 138 } 139 140 /** 141 * Finds the position of a specific token within the range. 142 * 143 * @param token Token to find. 144 * @param startPos Position where to start looking. 145 * 146 * @return Position of the token, or -1 if not found. 147 */ 148 dint find(QChar const *token, dint startPos = 0) const; 149 150 dint findBracketless(QChar const *token, dint startPos = 0) const; 151 152 /** 153 * Finds the index of a specific token within the range. When 154 * an opening bracket is encountered, its contents are skipped. 155 * 156 * @param token Token to find. 157 * @param startIndex Index where to start looking. 158 * 159 * @return Index of the token, or -1 if not found. 160 */ 161 dint findIndexSkippingBrackets(QChar const *token, dint startIndex) const; 162 163 /** 164 * Finds the next token subrange which is delimited with @c 165 * delimiter. @c subrange is adjusted so that if @c true is 166 * returned, it will contain the correct subrange. When calling 167 * this the first time, set the subrange to <code>undefinedRange()</code>. 168 * 169 * @param delimiter Delimiting token. 170 * @param subrange Token range that receives the delimiting subrange. 171 * 172 * @return @c true, if the next delimited subrange found successfully. 173 * Otherwise @c false. 174 */ 175 bool getNextDelimited(QChar const *delimiter, TokenRange &subrange) const; 176 177 /** 178 * Locates the matching closing bracket. If the matching bracket 179 * is not found, an exception is thrown. 180 * 181 * @param openBracketPos Position of the opening bracket. 182 * 183 * @return Position of the closing bracket. 184 */ 185 duint closingBracket(duint openBracketPos) const; 186 187 /** 188 * Locates the matching opening bracket. If the matching bracket 189 * is not found, an exception is thrown. 190 * 191 * @param closeBracketPos Position of the closing bracket. 192 * 193 * @return Position of the opening bracket. 194 */ 195 duint openingBracket(duint closeBracketPos) const; 196 197 /** 198 * Composes a string representation of the token range. Intended 199 * for error reporting. 200 * 201 * @return String containing the text of the tokens. 202 */ 203 String asText() const; 204 205 public: 206 static void bracketTokens(Token const &openingToken, 207 QChar const * &opening, QChar const * &closing); 208 209 private: 210 TokenBuffer const *_tokens; 211 212 /// Index of the start of the range. This is the first token in 213 /// the range. 214 duint _start; 215 216 /// Index of the end of the range, plus one. This is the token 217 /// just after the last token of the range. 218 duint _end; 219 }; 220 221 } // namespace de 222 223 #endif /* LIBDENG2_TOKENRANGE_H */ 224