1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | // |
41 | // W A R N I N G |
42 | // ------------- |
43 | // |
44 | // This file is not part of the Qt API. It exists purely as an |
45 | // implementation detail. This header file may change from version to |
46 | // version without notice, or even be removed. |
47 | // |
48 | // We mean it. |
49 | |
50 | #ifndef Patternist_ParserContext_H |
51 | #define Patternist_ParserContext_H |
52 | |
53 | #include <QFlags> |
54 | #include <QSharedData> |
55 | #include <QStack> |
56 | #include <QStringList> |
57 | #include <QtGlobal> |
58 | #include <QXmlQuery> |
59 | |
60 | #include <private/qbuiltintypes_p.h> |
61 | #include <private/qfunctionsignature_p.h> |
62 | #include <private/qorderby_p.h> |
63 | #include <private/qtemplatemode_p.h> |
64 | #include <private/quserfunctioncallsite_p.h> |
65 | #include <private/quserfunction_p.h> |
66 | #include <private/qvariabledeclaration_p.h> |
67 | #include <private/qtokenvalue_p.h> |
68 | |
69 | QT_BEGIN_NAMESPACE |
70 | |
71 | namespace QPatternist |
72 | { |
73 | class Tokenizer; |
74 | |
75 | /** |
76 | * @short Contains data used when parsing and tokenizing. |
77 | * |
78 | * When ExpressionFactory::create() is called, an instance of this class |
79 | * is passed to the scanner and parser. It holds all information that is |
80 | * needed to create the expression. |
81 | * |
82 | * @author Frans Englich <frans.englich@nokia.com> |
83 | */ |
84 | class ParserContext : public QSharedData |
85 | { |
86 | public: |
87 | typedef QExplicitlySharedDataPointer<ParserContext> Ptr; |
88 | |
89 | enum PrologDeclaration |
90 | { |
91 | BoundarySpaceDecl = 1, |
92 | DefaultCollationDecl = 2, |
93 | BaseURIDecl = 4, |
94 | ConstructionDecl = 8, |
95 | OrderingModeDecl = 16, |
96 | EmptyOrderDecl = 32, |
97 | CopyNamespacesDecl = 64, |
98 | DeclareDefaultElementNamespace = 128, |
99 | DeclareDefaultFunctionNamespace = 256 |
100 | }; |
101 | |
102 | typedef QFlags<PrologDeclaration> PrologDeclarations; |
103 | |
104 | /** |
105 | * Constructs a ParserContext instance. |
106 | * |
107 | * @param context the static context as defined in XPath. This contain |
108 | * namespace bindings, error handler, and other information necessary |
109 | * for creating an XPath expression. |
110 | * @param lang the particular XPath language sub-set that should be parsed |
111 | * @param tokenizer the Tokenizer to use. |
112 | * @see ExpressionFactory::LanguageAccent |
113 | */ |
114 | ParserContext(const StaticContext::Ptr &context, |
115 | const QXmlQuery::QueryLanguage lang, |
116 | Tokenizer *const tokenizer); |
117 | |
118 | /** |
119 | * @short Removes the recently pushed variables from |
120 | * scope. The amount of removed variables is @p amount. |
121 | * |
122 | * finalizePushedVariable() can be seen as popping the variable. |
123 | * |
124 | */ |
125 | void finalizePushedVariable(const int amount = 1, |
126 | const bool shouldPop = true); |
127 | |
128 | inline VariableSlotID allocatePositionalSlot() |
129 | { |
130 | ++m_positionSlot; |
131 | return m_positionSlot; |
132 | } |
133 | |
134 | inline VariableSlotID allocateExpressionSlot() |
135 | { |
136 | const VariableSlotID retval = m_expressionSlot; |
137 | ++m_expressionSlot; |
138 | return retval; |
139 | } |
140 | |
141 | inline VariableSlotID allocateGlobalVariableSlot() |
142 | { |
143 | ++m_globalVariableSlot; |
144 | return m_globalVariableSlot; |
145 | } |
146 | |
147 | inline bool hasDeclaration(const PrologDeclaration decl) const |
148 | { |
149 | return m_prologDeclarations.testFlag(flag: decl); |
150 | } |
151 | |
152 | inline void registerDeclaration(const PrologDeclaration decl) |
153 | { |
154 | m_prologDeclarations |= decl; |
155 | } |
156 | |
157 | /** |
158 | * The namespaces declared with <tt>declare namespace</tt>. |
159 | */ |
160 | QStringList declaredPrefixes; |
161 | |
162 | /** |
163 | * This is a temporary stack, used for keeping variables in scope, |
164 | * such as for function arguments & let clauses. |
165 | */ |
166 | VariableDeclaration::Stack variables; |
167 | |
168 | inline bool isXSLT() const |
169 | { |
170 | return languageAccent == QXmlQuery::XSLT20; |
171 | } |
172 | |
173 | const StaticContext::Ptr staticContext; |
174 | /** |
175 | * We don't store a Tokenizer::Ptr here, because then we would get a |
176 | * circular referencing between ParserContext and XSLTTokenizer, and |
177 | * hence they would never destruct. |
178 | */ |
179 | Tokenizer *const tokenizer; |
180 | const QXmlQuery::QueryLanguage languageAccent; |
181 | |
182 | /** |
183 | * Only used in the case of XSL-T. Is the name of the initial template |
184 | * to call. If null, no name was provided, and regular template |
185 | * matching should be done. |
186 | */ |
187 | QXmlName initialTemplateName; |
188 | |
189 | /** |
190 | * Used when parsing direct element constructors. It is used |
191 | * for ensuring tags are well-balanced. |
192 | */ |
193 | QStack<QXmlName> tagStack; |
194 | |
195 | /** |
196 | * The actual expression, the Query. This member may be @c null, |
197 | * such as in the case of an XQuery library module. |
198 | */ |
199 | Expression::Ptr queryBody; |
200 | |
201 | /** |
202 | * The user functions declared in the prolog. |
203 | */ |
204 | UserFunction::List userFunctions; |
205 | |
206 | /** |
207 | * Contains all calls to user defined functions. |
208 | */ |
209 | UserFunctionCallsite::List userFunctionCallsites; |
210 | |
211 | /** |
212 | * All variables declared with <tt>declare variable</tt>. |
213 | */ |
214 | VariableDeclaration::List declaredVariables; |
215 | |
216 | QVector<qint16> parserStack_yyss; |
217 | QVector<TokenValue> parserStack_yyvs; |
218 | QVector<XPATHLTYPE> parserStack_yyls; |
219 | |
220 | void handleStackOverflow(const char*, short **yyss, size_t, TokenValue **yyvs, size_t, |
221 | XPATHLTYPE **yyls, size_t, size_t *yystacksize); |
222 | |
223 | inline VariableSlotID currentPositionSlot() const |
224 | { |
225 | return m_positionSlot; |
226 | } |
227 | |
228 | inline VariableSlotID currentExpressionSlot() const |
229 | { |
230 | return m_expressionSlot; |
231 | } |
232 | |
233 | inline void restoreNodeTestSource() |
234 | { |
235 | nodeTestSource = BuiltinTypes::element; |
236 | } |
237 | |
238 | inline VariableSlotID allocateCacheSlot() |
239 | { |
240 | return ++m_evaluationCacheSlot; |
241 | } |
242 | |
243 | inline VariableSlotID allocateCacheSlots(const int count) |
244 | { |
245 | const VariableSlotID retval = m_evaluationCacheSlot + 1; |
246 | m_evaluationCacheSlot += count + 1; |
247 | return retval; |
248 | } |
249 | |
250 | ItemType::Ptr nodeTestSource; |
251 | |
252 | QStack<Expression::Ptr> typeswitchSource; |
253 | |
254 | /** |
255 | * The library module namespace set with <tt>declare module</tt>. |
256 | */ |
257 | QXmlName::NamespaceCode moduleNamespace; |
258 | |
259 | /** |
260 | * When a direct element constructor is processed, resolvers are |
261 | * created in order to carry the namespace declarations. In such case, |
262 | * the old resolver is pushed here. |
263 | */ |
264 | QStack<NamespaceResolver::Ptr> resolvers; |
265 | |
266 | /** |
267 | * This is used for handling the following obscene case: |
268 | * |
269 | * - <tt>\<e\>{1}{1}\<\/e\></tt> produce <tt>\<e\>11\</e\></tt> |
270 | * - <tt>\<e\>{1, 1}\<\/e\></tt> produce <tt>\<e\>1 1\</e\></tt> |
271 | * |
272 | * This boolean tracks whether the previous reduction inside element |
273 | * content was done with an enclosed expression. |
274 | */ |
275 | bool isPreviousEnclosedExpr; |
276 | |
277 | int elementConstructorDepth; |
278 | |
279 | QStack<bool> scanOnlyStack; |
280 | |
281 | QStack<OrderBy::Stability> orderStability; |
282 | |
283 | /** |
284 | * Whether any prolog declaration that must occur after the first |
285 | * group has been encountered. |
286 | */ |
287 | bool hasSecondPrologPart; |
288 | |
289 | bool preserveNamespacesMode; |
290 | bool inheritNamespacesMode; |
291 | |
292 | /** |
293 | * Contains all named templates. Since named templates |
294 | * can also have rules, each body may also be in templateRules. |
295 | */ |
296 | QHash<QXmlName, Template::Ptr> namedTemplates; |
297 | |
298 | /** |
299 | * All the @c xsl:call-template instructions that we have encountered. |
300 | */ |
301 | QVector<Expression::Ptr> templateCalls; |
302 | |
303 | /** |
304 | * If we're in XSL-T, and a variable reference is encountered |
305 | * which isn't in-scope, it's added to this hash since a global |
306 | * variable declaration may appear later on. |
307 | * |
308 | * We use a multi hash, since we can encounter several references to |
309 | * the same variable before it's declared. |
310 | */ |
311 | QMultiHash<QXmlName, Expression::Ptr> unresolvedVariableReferences; |
312 | |
313 | /** |
314 | * |
315 | * Contains the encountered template rules, as opposed |
316 | * to named templates. |
317 | * |
318 | * The key is the name of the template mode. If it's a default |
319 | * constructed value, it's the default mode. |
320 | * |
321 | * Since templates rules may also be named, each body may also be in |
322 | * namedTemplates. |
323 | * |
324 | * To be specific, the values are not the templates, the values are |
325 | * modes, and the TemplateMode contains the patterns and bodies. |
326 | */ |
327 | QHash<QXmlName, TemplateMode::Ptr> templateRules; |
328 | |
329 | /** |
330 | * @short Returns the TemplateMode for @p modeName or @c null if the |
331 | * mode being asked for is @c #current. |
332 | */ |
333 | TemplateMode::Ptr modeFor(const QXmlName &modeName) |
334 | { |
335 | /* #current is not a mode, so it cannot contain templates. #current |
336 | * specifies how to look up templates wrt. mode. This check helps |
337 | * code that calls us, asking for the mode it needs to lookup in. |
338 | */ |
339 | if(modeName == QXmlName(StandardNamespaces::InternalXSLT, StandardLocalNames::current)) |
340 | return TemplateMode::Ptr(); |
341 | |
342 | TemplateMode::Ptr &mode = templateRules[modeName]; |
343 | |
344 | if(!mode) |
345 | mode = TemplateMode::Ptr(new TemplateMode(modeName)); |
346 | |
347 | Q_ASSERT(templateRules[modeName]); |
348 | return mode; |
349 | } |
350 | |
351 | inline TemplatePattern::ID allocateTemplateID() |
352 | { |
353 | ++m_currentTemplateID; |
354 | return m_currentTemplateID; |
355 | } |
356 | |
357 | /** |
358 | * The @c xsl:param appearing inside template. |
359 | */ |
360 | VariableDeclaration::List templateParameters; |
361 | |
362 | /** |
363 | * The @c xsl:with-param appearing in template calling instruction. |
364 | */ |
365 | WithParam::Hash templateWithParams; |
366 | |
367 | inline void templateParametersHandled() |
368 | { |
369 | finalizePushedVariable(amount: templateParameters.count()); |
370 | templateParameters.clear(); |
371 | } |
372 | |
373 | inline void templateWithParametersHandled() |
374 | { |
375 | templateWithParams.clear(); |
376 | } |
377 | |
378 | inline bool isParsingWithParam() const |
379 | { |
380 | return m_isParsingWithParam.top(); |
381 | } |
382 | |
383 | void startParsingWithParam() |
384 | { |
385 | m_isParsingWithParam.push(t: true); |
386 | } |
387 | |
388 | void endParsingWithParam() |
389 | { |
390 | m_isParsingWithParam.pop(); |
391 | } |
392 | |
393 | /** |
394 | * This is used to deal with XSL-T's exception to the @c node() type, |
395 | * which doesn't match document nodes. |
396 | */ |
397 | bool isParsingPattern; |
398 | |
399 | ImportPrecedence currentImportPrecedence; |
400 | |
401 | bool isFirstTemplate() const |
402 | { |
403 | return m_currentTemplateID == InitialTemplateID; |
404 | } |
405 | |
406 | /** |
407 | * Whether we're processing XSL-T 1.0 code. |
408 | */ |
409 | QStack<bool> isBackwardsCompat; |
410 | |
411 | private: |
412 | enum |
413 | { |
414 | InitialTemplateID = -1 |
415 | }; |
416 | |
417 | VariableSlotID m_evaluationCacheSlot; |
418 | VariableSlotID m_expressionSlot; |
419 | VariableSlotID m_positionSlot; |
420 | PrologDeclarations m_prologDeclarations; |
421 | VariableSlotID m_globalVariableSlot; |
422 | TemplatePattern::ID m_currentTemplateID; |
423 | |
424 | /** |
425 | * The default is @c false. If we're not parsing @c xsl:with-param, |
426 | * hence parsing @c xsl:param, the value has changed. |
427 | */ |
428 | QStack<bool> m_isParsingWithParam; |
429 | Q_DISABLE_COPY(ParserContext) |
430 | }; |
431 | } |
432 | |
433 | QT_END_NAMESPACE |
434 | |
435 | #endif |
436 | |