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