1 #ifndef PARSERCONTEXT_H 2 #define PARSERCONTEXT_H 3 4 #include "ast/sqlitequery.h" 5 #include "parser.h" 6 7 #include <QHash> 8 #include <QList> 9 #include <QSet> 10 11 class ParserError; 12 13 /** 14 * @brief Parser context for SQL parsing process 15 * This class should not be used outside of @class Parser. 16 */ 17 class ParserContext 18 { 19 friend class Parser; 20 21 public: 22 /** 23 * @brief Releases all internal resources. 24 */ 25 virtual ~ParserContext(); 26 27 /** 28 * @brief Adds parsed query to collection of parsed queries. 29 * @param query Parsed query (AST object). 30 * 31 * This is called by Lemon parser. 32 */ 33 void addQuery(SqliteQuery* query); 34 35 /** 36 * @brief Stores error at given token with given message. 37 * @param token Token at which the error occurred. 38 * @param text Error message. 39 * 40 * This is called by Lemon parser. 41 */ 42 void error(TokenPtr token, const QString& text); 43 44 /** 45 * @overload 46 */ 47 void error(Token* token, const QString& text); 48 49 /** 50 * @brief Stores error with given message. 51 * @param text Error message. 52 * 53 * This method is used to report an error not related to specific token, 54 * like when Lemon's stack would get exceeded (which is very unlikely). 55 * 56 * This is called by Lemon parser. 57 * 58 * @overload 59 */ 60 void error(const QString& text); 61 62 /** 63 * @brief Stores error with most recently parsed token and given message. 64 * @param text Error message. 65 * 66 * Lemon parser calls it when it found out that the error started at the token before. 67 * 68 * This is just a minor error, so it will be ognored if ignoreMinorErrors is set. 69 */ 70 void minorErrorAfterLastToken(const QString& text); 71 72 /** 73 * @brief Marks next token to be parsed with given error message. 74 * @param text Error message. 75 * 76 * Lemon parser calls it when it knows that any next token will be an error. 77 * 78 * This is just a minor error, so it will be ognored if ignoreMinorErrors is set. 79 */ 80 void minorErrorBeforeNextToken(const QString& text); 81 82 /** 83 * @brief Stores error message for most recently parsed token. 84 * @param text Error message. 85 * 86 * Lemon parser calls it when critical error occurred at the most recently parsed token. 87 */ 88 void errorAfterLastToken(const QString& text); 89 90 /** 91 * @brief Stores error message for the next token to be parsed. 92 * @param text Error message. 93 * 94 * Lemon parser calls it when critical error is about to happen at any next token. 95 */ 96 void errorBeforeNextToken(const QString& text); 97 98 /** 99 * @brief Reports parsing error at given token position. 100 * @param text Error message. 101 * @param pos Position relative to after the last token. -1 means the last token, -2 the token before it and so on. -1 is default. 102 * 103 * This method is only useful when we know exactly which token was problematic. If error relates to some already wrapped 104 * syntax rule, it may have many tokens and it's hard to tell which token should we blame, but sometimes it can be calculated. 105 * Anyway, the token with error is reported by the pos argument. If you don't pass it, it means the error is at last token. 106 * 107 * Lemon parser uses it for example when there's a statement <tt>"CREATE TABLE ... (...) WITHOUT ROWID"</tt>. The SQLite grammar 108 * rule says, that the <tt>"ROWID"</tt> at the end is not necessarily the <tt>ROWID</tt> keyword, but it can be any word, 109 * but for now SQLite doesn't understand any other words at that position anyway and returns errors. 110 */ 111 void errorAtToken(const QString& text, int pos = -1); 112 113 /** 114 * @brief Flushes pending errors. 115 * 116 * In case the errorBeforeNextToken() was called and no more tokens were feed to the context, then this method flushes 117 * pending error as the error for the last token consumed, but only if minor errors are not ignored. 118 * This happens for example for "SELECT " statement, where it's not correct, but it's a minor error, cause user 119 * might enter more contents afterwards. 120 */ 121 void flushErrors(); 122 123 /** 124 * @brief Translates token pointer to it's shared pointer instance. 125 * @param token Token pointer to translate. 126 * @return QSharedPointer for the token, or null shared pointer in case of failure. 127 * 128 * This method works basing on internal collection of managed tokens. At each step of parsing, the internal lexer 129 * provides token (in form of shared pointer) and that token is then passed to the Lemon parser (as a pure C++ pointer, 130 * extracted from shared pointer). The very same token is stored in the internal collection of managed tokens (as a shared pointer). 131 * This method allows to get back to the shared pointer. 132 * 133 * This method is necessary to use shared pointers together with Lemon parser, which works on unions and won't be able to use 134 * shared pointers. 135 */ 136 TokenPtr getTokenPtr(Token* token); 137 138 /** 139 * @brief Translates list of token pointers to their shared pointer instances. 140 * @param tokens Token pointers to translate. 141 * @return List of QSharedPointers. 142 * 143 * This method is just a convenience way to call getTokenPtr() for a list of pointers. 144 */ 145 TokenList getTokenPtrList(const QList<Token*>& tokens); 146 147 /** 148 * @brief Adds token to managed list. 149 * @param token Token to be added to managed tokens. 150 * Tokens managed by context are shared to the Parser, so the API allows to see all parsed tokens. 151 * Some tokens might be created outside of Lexer, so this is the central repository for all tokens to be shared. 152 */ 153 void addManagedToken(TokenPtr token); 154 155 /** 156 * @brief Tests whether the token is in the collection of tokens managed by this context. 157 * @param token Token to test. 158 * @return true if the token is managed by this context, or false if not. 159 */ 160 bool isManagedToken(Token* token); 161 162 /** 163 * @brief Provides complete list of tokens managed by this context. 164 * @return List of tokens. 165 */ 166 TokenList getManagedTokens(); 167 168 /** 169 * @brief Tests whether there were any critical errors so far during parsing. 170 * @return true if there were no critical errors, or false otherwise. 171 */ 172 bool isSuccessful() const; 173 174 /** 175 * @brief Provides access to list of queries parsed so far. 176 * @return List of parsed AST objects. 177 * 178 * If there was an error, then queries from the list might be incomplete, which means their data members 179 * may still be initialized with their default values. It depends on where the error appeared in the parsed query string. 180 */ 181 const QList<SqliteQueryPtr>& getQueries(); 182 183 /** 184 * @brief Provides access to all errors occurred so far. 185 * @return List of errors. 186 */ 187 const QList<ParserError*>& getErrors(); 188 189 QVariant* handleNumberToken(const QString& tokenValue); 190 bool isCandidateForMaxNegativeNumber() const; 191 192 /** 193 * @brief Flag indicating if the Lemon parser should setup token collections. 194 * 195 * This setting allows to define whether the Lemon parser should setup token collections for parsed AST objects. 196 * In other words, it tells whether the SqliteStatement::tokens and SqliteStatement::tokensMap should be filled. 197 * 198 * Sometimes it might be worth to disable it to speed up parsig process, but by default it's enabled. 199 */ 200 bool setupTokens = true; 201 202 /** 203 * @brief Flag inficating if the Lemon parser should exectute code for the grammar rules. 204 * 205 * This setting allows to define whether the Lemon parser should execute the code associated with rules. 206 * Disabling it will cause no AST objects to be produced, but it can be used to find out syntax errors. 207 * If you don't need AST objects (output from parsing), then you can turn this off to speed up Lemon parser. 208 * 209 * The Parser class for example turns it of when it probes for next valid token candidates. In that case 210 * no AST output objects are used, just information whether the next candidate is valid or not. 211 */ 212 bool executeRules = true; 213 214 /** 215 * @brief Flag indicating if the Lemon parser should perform "fallback" logic. 216 * 217 * The "fallback" login in the Lemon parser is used when the input token is one of the keywords and it failed 218 * at that step. Then the "fallback" steps in and converts keyword token into the "ID" token, which represents 219 * a name of any object in the database (not necessarily existing one). Then the Lemon parser retries with 220 * that ID token and if that fails to fulfill the syntax rules too, then the error is reported. 221 * 222 * This is enabled by default, cause SQLite usually uses that too. It is for example disabled when looking 223 * for the next valid token candidate in Parser::getNextTokenCandidates(), cause for that case we need 224 * very strict token matching against the syntax. 225 */ 226 bool doFallbacks = true; 227 228 /** 229 * @brief Flag indicating if minor errors should be ignored by the Lemon parser. 230 * 231 * See description of Parser::parse() for details. 232 */ 233 bool ignoreMinorErrors = false; 234 235 private: 236 /** 237 * @brief Clears all internal containers and deletes error objects. 238 */ 239 void cleanUp(); 240 241 /** 242 * @brief List of parsed AST objects. 243 */ 244 QList<SqliteQueryPtr> parsedQueries; 245 246 /** 247 * @brief Tokens managed by this context. 248 */ 249 TokenList managedTokens; 250 251 /** 252 * @brief Mapping from token pointer to it's shared pointer instance. 253 */ 254 QHash<Token*, TokenPtr> tokenPtrMap; 255 256 /** 257 * @brief Flag indicating successful or failure parsing. 258 * 259 * Changed to false when the error was reported. 260 */ 261 bool successful = true; 262 263 /** 264 * @brief List of errors reported by Lemon. 265 */ 266 QList<ParserError*> errors; 267 268 /** 269 * @brief Flag indicating that the next token should raise an error. 270 * 271 * This is set by errorBeforeNextToken() and minorErrorBeforeNextToken(). 272 */ 273 bool raiseErrorBeforeNextToken = false; 274 275 /** 276 * @brief Error to be used for the error at next token. 277 * 278 * Defined by errorBeforeNextToken() and minorErrorBeforeNextToken(). 279 */ 280 QString nextTokenError; 281 282 /** 283 * @brief Indicates that the number value is 1 over the max longlong value. 284 * 285 * Then the positive number is over max longlong by 1, then this is a candidate 286 * for max negative longlong value, but this is to be identified in the next parser reduce level. 287 * 288 * Because of that this flag is set to false by default each time the number is parsed and is set afterwards 289 * to true each timethe value is 1 over max longlong. This way if the 'term' rule includes 'minus' token, 290 * then it will be properly converted to max negative longlong. 291 */ 292 bool recentNumberIsCandidateForMaxNegative = false; 293 }; 294 295 #endif // PARSERCONTEXT_H 296