source: trunk/src/xmlpatterns/parser/querytransformparser.ypp@ 679

Last change on this file since 679 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 189.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists purely as an
47// implementation detail. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51
52%{
53/****************************************************************************
54**
55** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
56** All rights reserved.
57** Contact: Nokia Corporation ([email protected])
58**
59** This file is part of the QtXmlPatterns module of the Qt Toolkit.
60**
61** $QT_BEGIN_LICENSE:LGPL$
62** Commercial Usage
63** Licensees holding valid Qt Commercial licenses may use this file in
64** accordance with the Qt Commercial License Agreement provided with the
65** Software or, alternatively, in accordance with the terms contained in
66** a written agreement between you and Nokia.
67**
68** GNU Lesser General Public License Usage
69** Alternatively, this file may be used under the terms of the GNU Lesser
70** General Public License version 2.1 as published by the Free Software
71** Foundation and appearing in the file LICENSE.LGPL included in the
72** packaging of this file. Please review the following information to
73** ensure the GNU Lesser General Public License version 2.1 requirements
74** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
75**
76** In addition, as a special exception, Nokia gives you certain additional
77** rights. These rights are described in the Nokia Qt LGPL Exception
78** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
79**
80** GNU General Public License Usage
81** Alternatively, this file may be used under the terms of the GNU
82** General Public License version 3.0 as published by the Free Software
83** Foundation and appearing in the file LICENSE.GPL included in the
84** packaging of this file. Please review the following information to
85** ensure the GNU General Public License version 3.0 requirements will be
86** met: http://www.gnu.org/copyleft/gpl.html.
87**
88** If you have questions regarding the use of this file, please contact
89** Nokia at [email protected].
90** $QT_END_LICENSE$
91**
92****************************************************************************/
93
94//
95// W A R N I N G
96// -------------
97//
98// This file is not part of the Qt API. It exists purely as an
99// implementation detail. This header file may change from version to
100// version without notice, or even be removed.
101//
102// We mean it.
103
104#include <limits>
105
106#include <QUrl>
107
108#include "qabstractfloat_p.h"
109#include "qandexpression_p.h"
110#include "qanyuri_p.h"
111#include "qapplytemplate_p.h"
112#include "qargumentreference_p.h"
113#include "qarithmeticexpression_p.h"
114#include "qatomicstring_p.h"
115#include "qattributeconstructor_p.h"
116#include "qattributenamevalidator_p.h"
117#include "qaxisstep_p.h"
118#include "qbuiltintypes_p.h"
119#include "qcalltemplate_p.h"
120#include "qcastableas_p.h"
121#include "qcastas_p.h"
122#include "qcombinenodes_p.h"
123#include "qcommentconstructor_p.h"
124#include "qcommonnamespaces_p.h"
125#include "qcommonsequencetypes_p.h"
126#include "qcommonvalues_p.h"
127#include "qcomputednamespaceconstructor_p.h"
128#include "qcontextitem_p.h"
129#include "qcopyof_p.h"
130#include "qcurrentitemstore_p.h"
131#include "qdebug_p.h"
132#include "qdelegatingnamespaceresolver_p.h"
133#include "qdocumentconstructor_p.h"
134#include "qelementconstructor_p.h"
135#include "qemptysequence_p.h"
136#include "qemptysequencetype_p.h"
137#include "qevaluationcache_p.h"
138#include "qexpressionfactory_p.h"
139#include "qexpressionsequence_p.h"
140#include "qexpressionvariablereference_p.h"
141#include "qexternalvariablereference_p.h"
142#include "qforclause_p.h"
143#include "qfunctioncall_p.h"
144#include "qfunctionfactory_p.h"
145#include "qfunctionsignature_p.h"
146#include "qgeneralcomparison_p.h"
147#include "qgenericpredicate_p.h"
148#include "qgenericsequencetype_p.h"
149#include "qifthenclause_p.h"
150#include "qinstanceof_p.h"
151#include "qletclause_p.h"
152#include "qliteral_p.h"
153#include "qlocalnametest_p.h"
154#include "qnamespaceconstructor_p.h"
155#include "qnamespacenametest_p.h"
156#include "qncnameconstructor_p.h"
157#include "qnodecomparison_p.h"
158#include "qnodesort_p.h"
159#include "qorderby_p.h"
160#include "qorexpression_p.h"
161#include "qparsercontext_p.h"
162#include "qpath_p.h"
163#include "qpatternistlocale_p.h"
164#include "qpositionalvariablereference_p.h"
165#include "qprocessinginstructionconstructor_p.h"
166#include "qqnameconstructor_p.h"
167#include "qqnametest_p.h"
168#include "qqnamevalue_p.h"
169#include "qquantifiedexpression_p.h"
170#include "qrangeexpression_p.h"
171#include "qrangevariablereference_p.h"
172#include "qreturnorderby_p.h"
173#include "qschemanumeric_p.h"
174#include "qschematypefactory_p.h"
175#include "qsimplecontentconstructor_p.h"
176#include "qstaticbaseuristore_p.h"
177#include "qstaticcompatibilitystore_p.h"
178#include "qtemplateparameterreference_p.h"
179#include "qtemplate_p.h"
180#include "qtextnodeconstructor_p.h"
181#include "qtokenizer_p.h"
182#include "qtreatas_p.h"
183#include "qtypechecker_p.h"
184#include "qunaryexpression_p.h"
185#include "qunresolvedvariablereference_p.h"
186#include "quserfunctioncallsite_p.h"
187#include "qvaluecomparison_p.h"
188#include "qxpathhelper_p.h"
189#include "qxsltsimplecontentconstructor_p.h"
190
191/*
192 * The cpp generated with bison 2.1 wants to
193 * redeclare the C-like prototypes of 'malloc' and 'free', so we avoid that.
194 */
195#define YYMALLOC malloc
196#define YYFREE free
197
198QT_BEGIN_NAMESPACE
199
200/* Due to Qt's QT_BEGIN_NAMESPACE magic, we can't use `using namespace', for some
201 * undocumented reason. */
202namespace QPatternist
203{
204
205/**
206 * "Macro that you define with #define in the Bison declarations
207 * section to request verbose, specific error message strings when
208 * yyerror is called."
209 */
210#define YYERROR_VERBOSE 1
211
212#undef YYLTYPE_IS_TRIVIAL
213#define YYLTYPE_IS_TRIVIAL 0
214
215/* Suppresses `warning: "YYENABLE_NLS" is not defined`
216 * @c YYENABLE_NLS enables Bison internationalization, and we don't
217 * use that, so disable it. See the Bison Manual, section 4.5 Parser Internationalization.
218 */
219#define YYENABLE_NLS 0
220
221static inline QSourceLocation fromYYLTYPE(const YYLTYPE &sourceLocator,
222 const ParserContext *const parseInfo)
223{
224 return QSourceLocation(parseInfo->tokenizer->queryURI(),
225 sourceLocator.first_line,
226 sourceLocator.first_column);
227}
228
229/**
230 * @internal
231 * @relates QXmlQuery
232 */
233typedef QFlags<QXmlQuery::QueryLanguage> QueryLanguages;
234
235/**
236 * @short Flags invalid expressions and declarations in the currently
237 * parsed language.
238 *
239 * Since this grammar is used for several languages: XQuery 1.0, XSL-T 2.0, and
240 * XPath 2.0 inside XSL-T, and field and selector patterns in W3C XML Schema's
241 * identity constraints, it is the union of all the constructs in these
242 * languages. However, when dealing with each language individually, we
243 * regularly need to disallow some expressions, such as direct element
244 * constructors when parsing XSL-T, or the typeswitch when parsing XPath.
245 *
246 * This is further complicated by that XSLTTokenizer sometimes generates code
247 * which is allowed in XQuery but not in XPath. For that reason the token
248 * INTERNAL is sometimes generated, which signals that an expression, for
249 * instance the @c let clause, should not be flagged as an error, because it's
250 * used for internal purposes.
251 *
252 * Hence, this function is called from each expression and declaration with @p
253 * allowedLanguages stating what languages it is allowed in.
254 *
255 * If @p isInternal is @c true, no error is raised. Otherwise, if the current
256 * language is not in @p allowedLanguages, an error is raised.
257 */
258static void allowedIn(const QueryLanguages allowedLanguages,
259 const ParserContext *const parseInfo,
260 const YYLTYPE &sourceLocator,
261 const bool isInternal = false)
262{
263 /* We treat XPath 2.0 as a subset of XSL-T 2.0, so if XPath 2.0 is allowed
264 * and XSL-T is the language, it's ok. */
265 if(!isInternal &&
266 (!allowedLanguages.testFlag(parseInfo->languageAccent) && !(allowedLanguages.testFlag(QXmlQuery::XPath20) && parseInfo->languageAccent == QXmlQuery::XSLT20)))
267 {
268
269 QString langName;
270
271 switch(parseInfo->languageAccent)
272 {
273 case QXmlQuery::XPath20:
274 langName = QLatin1String("XPath 2.0");
275 break;
276 case QXmlQuery::XSLT20:
277 langName = QLatin1String("XSL-T 2.0");
278 break;
279 case QXmlQuery::XQuery10:
280 langName = QLatin1String("XQuery 1.0");
281 break;
282 case QXmlQuery::XmlSchema11IdentityConstraintSelector:
283 langName = QtXmlPatterns::tr("W3C XML Schema identity constraint selector");
284 break;
285 case QXmlQuery::XmlSchema11IdentityConstraintField:
286 langName = QtXmlPatterns::tr("W3C XML Schema identity constraint field");
287 break;
288 }
289
290 parseInfo->staticContext->error(QtXmlPatterns::tr("A construct was encountered "
291 "which is disallowed in the current language(%1).").arg(langName),
292 ReportContext::XPST0003,
293 fromYYLTYPE(sourceLocator, parseInfo));
294
295 }
296}
297
298static inline bool isVariableReference(const Expression::ID id)
299{
300 return id == Expression::IDExpressionVariableReference
301 || id == Expression::IDRangeVariableReference
302 || id == Expression::IDArgumentReference;
303}
304
305class ReflectYYLTYPE : public SourceLocationReflection
306{
307public:
308 inline ReflectYYLTYPE(const YYLTYPE &sourceLocator,
309 const ParserContext *const pi) : m_sl(sourceLocator)
310 , m_parseInfo(pi)
311 {
312 }
313
314 virtual const SourceLocationReflection *actualReflection() const
315 {
316 return this;
317 }
318
319 virtual QSourceLocation sourceLocation() const
320 {
321 return fromYYLTYPE(m_sl, m_parseInfo);
322 }
323
324 virtual QString description() const
325 {
326 Q_ASSERT(false);
327 return QString();
328 }
329
330private:
331 const YYLTYPE &m_sl;
332 const ParserContext *const m_parseInfo;
333};
334
335/**
336 * @short Centralizes a translation string for the purpose of increasing consistency.
337 */
338static inline QString unknownType()
339{
340 return QtXmlPatterns::tr("%1 is an unknown schema type.");
341}
342
343static inline Expression::Ptr create(Expression *const expr,
344 const YYLTYPE &sourceLocator,
345 const ParserContext *const parseInfo)
346{
347 parseInfo->staticContext->addLocation(expr, fromYYLTYPE(sourceLocator, parseInfo));
348 return Expression::Ptr(expr);
349}
350
351static inline Template::Ptr create(Template *const expr,
352 const YYLTYPE &sourceLocator,
353 const ParserContext *const parseInfo)
354{
355 parseInfo->staticContext->addLocation(expr, fromYYLTYPE(sourceLocator, parseInfo));
356 return Template::Ptr(expr);
357}
358
359static inline Expression::Ptr create(const Expression::Ptr &expr,
360 const YYLTYPE &sourceLocator,
361 const ParserContext *const parseInfo)
362{
363 parseInfo->staticContext->addLocation(expr.data(), fromYYLTYPE(sourceLocator, parseInfo));
364 return expr;
365}
366
367static Expression::Ptr createSimpleContent(const Expression::Ptr &source,
368 const YYLTYPE &sourceLocator,
369 const ParserContext *const parseInfo)
370{
371 return create(parseInfo->isXSLT() ? new XSLTSimpleContentConstructor(source) : new SimpleContentConstructor(source),
372 sourceLocator,
373 parseInfo);
374}
375
376static void loadPattern(const Expression::Ptr &matchPattern,
377 TemplatePattern::Vector &ourPatterns,
378 const TemplatePattern::ID id,
379 const PatternPriority priority,
380 const Template::Ptr &temp)
381{
382 Q_ASSERT(temp);
383
384 const PatternPriority effectivePriority = qIsNaN(priority) ? matchPattern->patternPriority() : priority;
385
386 ourPatterns.append(TemplatePattern::Ptr(new TemplatePattern(matchPattern, effectivePriority, id, temp)));
387}
388
389static Expression::Ptr typeCheckTemplateBody(const Expression::Ptr &body,
390 const SequenceType::Ptr &reqType,
391 const ParserContext *const parseInfo)
392{
393 return TypeChecker::applyFunctionConversion(body, reqType,
394 parseInfo->staticContext,
395 ReportContext::XTTE0505,
396 TypeChecker::Options(TypeChecker::AutomaticallyConvert | TypeChecker::GeneratePromotion));
397}
398
399static void registerNamedTemplate(const QXmlName &name,
400 const Expression::Ptr &body,
401 ParserContext *const parseInfo,
402 const YYLTYPE &sourceLocator,
403 const Template::Ptr &temp)
404{
405 Template::Ptr &e = parseInfo->namedTemplates[name];
406
407 if(e)
408 {
409 parseInfo->staticContext->error(QtXmlPatterns::tr("A template by name %1 "
410 "has already been declared.")
411 .arg(formatKeyword(parseInfo->staticContext->namePool(),
412 name)),
413 ReportContext::XTSE0660,
414 fromYYLTYPE(sourceLocator, parseInfo));
415 }
416 else
417 {
418 e = temp;
419 e->body = body;
420 }
421}
422
423/**
424 * @short Centralizes code for creating numeric literals.
425 */
426template<typename TNumberClass>
427Expression::Ptr createNumericLiteral(const QString &in,
428 const YYLTYPE &sl,
429 const ParserContext *const parseInfo)
430{
431 const Item num(TNumberClass::fromLexical(in));
432
433 if(num.template as<AtomicValue>()->hasError())
434 {
435 parseInfo->staticContext->error(QtXmlPatterns::tr("%1 is not a valid numeric literal.")
436 .arg(formatData(in)),
437 ReportContext::XPST0003, fromYYLTYPE(sl, parseInfo));
438 return Expression::Ptr(); /* Avoid compiler warning. */
439 }
440 else
441 return create(new Literal(num), sl, parseInfo);
442}
443
444/**
445 * @short The generated Bison parser calls this function when there is a parse error.
446 *
447 * It is not called, nor should be, for logical errors(which the Bison not know about). For those,
448 * ReportContext::error() is called.
449 */
450static int XPatherror(YYLTYPE *sourceLocator, const ParserContext *const parseInfo, const char *const msg)
451{
452 Q_UNUSED(sourceLocator);
453 Q_ASSERT(parseInfo);
454
455 parseInfo->staticContext->error(escape(QLatin1String(msg)), ReportContext::XPST0003, fromYYLTYPE(*sourceLocator, parseInfo));
456 return 1;
457}
458
459/**
460 * When we want to connect the OrderBy and ReturnOrderBy, it might be that we have other expressions, such
461 * as @c where and @c let inbetween. We need to continue through them. This function does that.
462 */
463static ReturnOrderBy *locateReturnClause(const Expression::Ptr &expr)
464{
465 Q_ASSERT(expr);
466
467 const Expression::ID id = expr->id();
468 if(id == Expression::IDLetClause || id == Expression::IDIfThenClause || id == Expression::IDForClause)
469 return locateReturnClause(expr->operands()[1]);
470 else if(id == Expression::IDReturnOrderBy)
471 return expr->as<ReturnOrderBy>();
472 else
473 return 0;
474}
475
476static inline bool isPredicate(const Expression::ID id)
477{
478 return id == Expression::IDGenericPredicate ||
479 id == Expression::IDFirstItemPredicate;
480}
481
482/**
483 * Assumes expr is an AxisStep wrapped in some kind of predicates or paths. Filters
484 * through the predicates and returns the AxisStep.
485 */
486static Expression::Ptr findAxisStep(const Expression::Ptr &expr,
487 const bool throughStructures = true)
488{
489 Q_ASSERT(expr);
490
491 if(!throughStructures)
492 return expr;
493
494 Expression *candidate = expr.data();
495 Expression::ID id = candidate->id();
496
497 while(isPredicate(id) || id == Expression::IDPath)
498 {
499 const Expression::List &children = candidate->operands();
500 if(children.isEmpty())
501 return Expression::Ptr();
502 else
503 {
504 candidate = children.first().data();
505 id = candidate->id();
506 }
507 }
508
509 if(id == Expression::IDEmptySequence)
510 return Expression::Ptr();
511 else
512 {
513 Q_ASSERT(candidate->is(Expression::IDAxisStep));
514 return Expression::Ptr(candidate);
515 }
516}
517
518static void changeToTopAxis(const Expression::Ptr &op)
519{
520 /* This axis must have been written away by now. */
521 Q_ASSERT(op->as<AxisStep>()->axis() != QXmlNodeModelIndex::AxisChild);
522
523 if(op->as<AxisStep>()->axis() != QXmlNodeModelIndex::AxisSelf)
524 op->as<AxisStep>()->setAxis(QXmlNodeModelIndex::AxisAttributeOrTop);
525}
526
527/**
528 * @short Writes @p operand1 and @p operand2, two operands in an XSL-T pattern,
529 * into an equivalent XPath expression.
530 *
531 * Essentially, the following rewrite is done:
532 *
533 * <tt>
534 * axis1::test1(a)/axis2::test2(b)
535 * =>
536 * child-or-top::test2(b)[parent::test1(a)]
537 * </tt>
538 *
539 * Section 5.5.3 The Meaning of a Pattern talks about rewrites that are applied to
540 * only the first step in a pattern, but since we're doing rewrites more radically,
541 * its line of reasoning cannot be followed.
542 *
543 * Keep in mind the rewrites that non-terminal PatternStep do.
544 *
545 * @see createIdPatternPath()
546 */
547static inline Expression::Ptr createPatternPath(const Expression::Ptr &operand1,
548 const Expression::Ptr &operand2,
549 const QXmlNodeModelIndex::Axis axis,
550 const YYLTYPE &sl,
551 const ParserContext *const parseInfo)
552{
553 const Expression::Ptr operandL(findAxisStep(operand1, false));
554
555 if(operandL->is(Expression::IDAxisStep))
556 operandL->as<AxisStep>()->setAxis(axis);
557 else
558 findAxisStep(operand1)->as<AxisStep>()->setAxis(axis);
559
560 return create(GenericPredicate::create(operand2, operandL,
561 parseInfo->staticContext, fromYYLTYPE(sl, parseInfo)), sl, parseInfo);
562}
563
564/**
565 * @short Performs the same role as createPatternPath(), but is tailored
566 * for @c fn:key() and @c fn:id().
567 *
568 * @c fn:key() and @c fn:id() can be part of path patterns(only as the first step,
569 * to be precise) and that poses a challenge to rewriting because what
570 * createPatternPath() is not possible to express, since the functions cannot be
571 * node tests. E.g, this rewrite is not possible:
572 *
573 * <tt>
574 * id-or-key/abc
575 * =>
576 * child-or-top::abc[parent::id-or-key]
577 * </tt>
578 *
579 * Our approach is to rewrite like this:
580 *
581 * <tt>
582 * id-or-key/abc
583 * =>
584 * child-or-top::abc[parent::node is id-or-key]
585 * </tt>
586 *
587 * @p operand1 is the call to @c fn:key() or @c fn:id(), @p operand2
588 * the right operand, and @p axis the target axis to rewrite to.
589 *
590 * @see createPatternPath()
591 */
592static inline Expression::Ptr createIdPatternPath(const Expression::Ptr &operand1,
593 const Expression::Ptr &operand2,
594 const QXmlNodeModelIndex::Axis axis,
595 const YYLTYPE &sl,
596 const ParserContext *const parseInfo)
597{
598 const Expression::Ptr operandR(findAxisStep(operand2));
599 Q_ASSERT(operandR);
600 changeToTopAxis(operandR);
601
602 const Expression::Ptr parentStep(create(new AxisStep(axis, BuiltinTypes::node),
603 sl,
604 parseInfo));
605 const Expression::Ptr isComp(create(new NodeComparison(parentStep,
606 QXmlNodeModelIndex::Is,
607 operand1),
608 sl,
609 parseInfo));
610
611 return create(GenericPredicate::create(operandR, isComp,
612 parseInfo->staticContext, fromYYLTYPE(sl, parseInfo)), sl, parseInfo);
613}
614
615/**
616 * @short Centralizes a translation message, for the
617 * purpose of consistency and modularization.
618 */
619static inline QString prologMessage(const char *const msg)
620{
621 Q_ASSERT(msg);