src/xmlpatterns/parser/qxslttokenizer.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QStringList>
       
    43 
       
    44 #include "qbuiltintypes_p.h"
       
    45 #include "qcommonnamespaces_p.h"
       
    46 #include "qquerytransformparser_p.h"
       
    47 #include "qxquerytokenizer_p.h"
       
    48 #include "qpatternistlocale_p.h"
       
    49 
       
    50 #include "qxslttokenizer_p.h"
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 
       
    54 using namespace QPatternist;
       
    55 
       
    56 Tokenizer::Token SingleTokenContainer::nextToken(YYLTYPE *const location)
       
    57 {
       
    58     if(m_hasDelivered)
       
    59         return Tokenizer::Token(END_OF_FILE);
       
    60     else
       
    61     {
       
    62         *location = m_location;
       
    63         m_hasDelivered = true;
       
    64         return m_token;
       
    65     }
       
    66 }
       
    67 
       
    68 XSLTTokenizer::XSLTTokenizer(QIODevice *const queryDevice,
       
    69                              const QUrl &location,
       
    70                              const ReportContext::Ptr &context,
       
    71                              const NamePool::Ptr &np) : Tokenizer(location)
       
    72                                                       , MaintainingReader<XSLTTokenLookup>(createElementDescriptions(), createStandardAttributes(), context, queryDevice)
       
    73                                                       , m_location(location)
       
    74                                                       , m_namePool(np)
       
    75                                                       /* We initialize after all name constants. */
       
    76                                                       , m_validationAlternatives(createValidationAlternatives())
       
    77                                                       , m_parseInfo(0)
       
    78 {
       
    79     Q_ASSERT(m_namePool);
       
    80 
       
    81     pushState(OutsideDocumentElement);
       
    82 }
       
    83 
       
    84 bool XSLTTokenizer::isAnyAttributeAllowed() const
       
    85 {
       
    86     return m_processingMode.top() == ForwardCompatible;
       
    87 }
       
    88 
       
    89 void XSLTTokenizer::setParserContext(const ParserContext::Ptr &parseInfo)
       
    90 {
       
    91     m_parseInfo = parseInfo;
       
    92 }
       
    93 
       
    94 void XSLTTokenizer::validateElement() const
       
    95 {
       
    96     MaintainingReader<XSLTTokenLookup>::validateElement(currentElementName());
       
    97 }
       
    98 
       
    99 QSet<XSLTTokenizer::NodeName> XSLTTokenizer::createStandardAttributes()
       
   100 {
       
   101     QSet<NodeName> retval;
       
   102     enum
       
   103     {
       
   104         ReservedForAttributes = 6
       
   105     };
       
   106 
       
   107     retval.reserve(6);
       
   108 
       
   109     retval.insert(DefaultCollation);
       
   110     retval.insert(ExcludeResultPrefixes);
       
   111     retval.insert(ExtensionElementPrefixes);
       
   112     retval.insert(UseWhen);
       
   113     retval.insert(Version);
       
   114     retval.insert(XpathDefaultNamespace);
       
   115 
       
   116     Q_ASSERT(retval.count() == ReservedForAttributes);
       
   117 
       
   118     return retval;
       
   119 }
       
   120 
       
   121 ElementDescription<XSLTTokenLookup>::Hash XSLTTokenizer::createElementDescriptions()
       
   122 {
       
   123     ElementDescription<XSLTTokenLookup>::Hash result;
       
   124     enum
       
   125     {
       
   126         ReservedForElements = 40
       
   127     };
       
   128     result.reserve(ReservedForElements);
       
   129 
       
   130     /* xsl:apply-templates */
       
   131     {
       
   132         ElementDescription<XSLTTokenLookup> &e = result[ApplyTemplates];
       
   133         e.optionalAttributes.insert(Select);
       
   134         e.optionalAttributes.insert(Mode);
       
   135     }
       
   136 
       
   137     /* xsl:template */
       
   138     {
       
   139         ElementDescription<XSLTTokenLookup> &e = result[Template];
       
   140         e.optionalAttributes.insert(Match);
       
   141         e.optionalAttributes.insert(Name);
       
   142         e.optionalAttributes.insert(Mode);
       
   143         e.optionalAttributes.insert(Priority);
       
   144         e.optionalAttributes.insert(As);
       
   145     }
       
   146 
       
   147     /* xsl:text, xsl:choose and xsl:otherwise */
       
   148     {
       
   149         ElementDescription<XSLTTokenLookup> &e = result[Text];
       
   150         result.insert(Choose, e);
       
   151         result.insert(Otherwise, e);
       
   152     }
       
   153 
       
   154     /* xsl:stylesheet */
       
   155     {
       
   156         ElementDescription<XSLTTokenLookup> &e = result[Stylesheet];
       
   157 
       
   158         e.requiredAttributes.insert(Version);
       
   159 
       
   160         e.optionalAttributes.insert(Id);
       
   161         e.optionalAttributes.insert(ExtensionElementPrefixes);
       
   162         e.optionalAttributes.insert(ExcludeResultPrefixes);
       
   163         e.optionalAttributes.insert(XpathDefaultNamespace);
       
   164         e.optionalAttributes.insert(DefaultValidation);
       
   165         e.optionalAttributes.insert(DefaultCollation);
       
   166         e.optionalAttributes.insert(InputTypeAnnotations);
       
   167     }
       
   168 
       
   169     /* xsl:transform */
       
   170     {
       
   171         result[Transform] = result[Stylesheet];
       
   172     }
       
   173 
       
   174     /* xsl:value-of */
       
   175     {
       
   176         ElementDescription<XSLTTokenLookup> &e = result[ValueOf];
       
   177         e.optionalAttributes.insert(Separator);
       
   178         e.optionalAttributes.insert(Select);
       
   179     }
       
   180 
       
   181     /* xsl:variable */
       
   182     {
       
   183         ElementDescription<XSLTTokenLookup> &e = result[Variable];
       
   184 
       
   185         e.requiredAttributes.insert(Name);
       
   186 
       
   187         e.optionalAttributes.insert(Select);
       
   188         e.optionalAttributes.insert(As);
       
   189     }
       
   190 
       
   191     /* xsl:when & xsl:if */
       
   192     {
       
   193         ElementDescription<XSLTTokenLookup> &e = result[When];
       
   194 
       
   195         e.requiredAttributes.insert(Test);
       
   196 
       
   197         result.insert(If, e);
       
   198     }
       
   199 
       
   200     /* xsl:sequence, xsl:for-each */
       
   201     {
       
   202         ElementDescription<XSLTTokenLookup> &e = result[Sequence];
       
   203 
       
   204         e.requiredAttributes.insert(Select);
       
   205 
       
   206         result.insert(ForEach, e);
       
   207     }
       
   208 
       
   209     /* xsl:comment */
       
   210     {
       
   211         ElementDescription<XSLTTokenLookup> &e = result[XSLTTokenLookup::Comment];
       
   212 
       
   213         e.optionalAttributes.insert(Select);
       
   214     }
       
   215 
       
   216     /* xsl:processing-instruction */
       
   217     {
       
   218         ElementDescription<XSLTTokenLookup> &e = result[XSLTTokenLookup::ProcessingInstruction];
       
   219 
       
   220         e.requiredAttributes.insert(Name);
       
   221         e.optionalAttributes.insert(Select);
       
   222     }
       
   223 
       
   224     /* xsl:document */
       
   225     {
       
   226         ElementDescription<XSLTTokenLookup> &e = result[Document];
       
   227 
       
   228         e.optionalAttributes.insert(Validation);
       
   229         e.optionalAttributes.insert(Type);
       
   230     }
       
   231 
       
   232     /* xsl:element */
       
   233     {
       
   234         ElementDescription<XSLTTokenLookup> &e = result[Element];
       
   235 
       
   236         e.requiredAttributes.insert(Name);
       
   237 
       
   238         e.optionalAttributes.insert(Namespace);
       
   239         e.optionalAttributes.insert(InheritNamespaces);
       
   240         e.optionalAttributes.insert(UseAttributeSets);
       
   241         e.optionalAttributes.insert(Validation);
       
   242         e.optionalAttributes.insert(Type);
       
   243     }
       
   244 
       
   245     /* xsl:attribute */
       
   246     {
       
   247         ElementDescription<XSLTTokenLookup> &e = result[Attribute];
       
   248 
       
   249         e.requiredAttributes.insert(Name);
       
   250 
       
   251         e.optionalAttributes.insert(Namespace);
       
   252         e.optionalAttributes.insert(Select);
       
   253         e.optionalAttributes.insert(Separator);
       
   254         e.optionalAttributes.insert(Validation);
       
   255         e.optionalAttributes.insert(Type);
       
   256     }
       
   257 
       
   258     /* xsl:function */
       
   259     {
       
   260         ElementDescription<XSLTTokenLookup> &e = result[Function];
       
   261 
       
   262         e.requiredAttributes.insert(Name);
       
   263 
       
   264         e.optionalAttributes.insert(As);
       
   265         e.optionalAttributes.insert(Override);
       
   266     }
       
   267 
       
   268     /* xsl:param */
       
   269     {
       
   270         ElementDescription<XSLTTokenLookup> &e = result[Param];
       
   271 
       
   272         e.requiredAttributes.insert(Name);
       
   273 
       
   274         e.optionalAttributes.insert(Select);
       
   275         e.optionalAttributes.insert(As);
       
   276         e.optionalAttributes.insert(Required);
       
   277         e.optionalAttributes.insert(Tunnel);
       
   278     }
       
   279 
       
   280     /* xsl:namespace */
       
   281     {
       
   282         ElementDescription<XSLTTokenLookup> &e = result[Namespace];
       
   283 
       
   284         e.requiredAttributes.insert(Name);
       
   285         e.optionalAttributes.insert(Select);
       
   286     }
       
   287 
       
   288     /* xsl:call-template */
       
   289     {
       
   290         ElementDescription<XSLTTokenLookup> &e = result[CallTemplate];
       
   291         e.requiredAttributes.insert(Name);
       
   292     }
       
   293 
       
   294     /* xsl:perform-sort */
       
   295     {
       
   296         ElementDescription<XSLTTokenLookup> &e = result[PerformSort];
       
   297         e.requiredAttributes.insert(Select);
       
   298     }
       
   299 
       
   300     /* xsl:sort */
       
   301     {
       
   302         ElementDescription<XSLTTokenLookup> &e = result[Sort];
       
   303 
       
   304         e.optionalAttributes.reserve(7);
       
   305         e.optionalAttributes.insert(Select);
       
   306         e.optionalAttributes.insert(Lang);
       
   307         e.optionalAttributes.insert(Order);
       
   308         e.optionalAttributes.insert(Collation);
       
   309         e.optionalAttributes.insert(Stable);
       
   310         e.optionalAttributes.insert(CaseOrder);
       
   311         e.optionalAttributes.insert(DataType);
       
   312     }
       
   313 
       
   314     /* xsl:import-schema */
       
   315     {
       
   316         ElementDescription<XSLTTokenLookup> &e = result[ImportSchema];
       
   317 
       
   318         e.optionalAttributes.reserve(2);
       
   319         e.optionalAttributes.insert(Namespace);
       
   320         e.optionalAttributes.insert(SchemaLocation);
       
   321     }
       
   322 
       
   323     /* xsl:message */
       
   324     {
       
   325         ElementDescription<XSLTTokenLookup> &e = result[Message];
       
   326 
       
   327         e.optionalAttributes.reserve(2);
       
   328         e.optionalAttributes.insert(Select);
       
   329         e.optionalAttributes.insert(Terminate);
       
   330     }
       
   331 
       
   332     /* xsl:copy-of */
       
   333     {
       
   334         ElementDescription<XSLTTokenLookup> &e = result[CopyOf];
       
   335 
       
   336         e.requiredAttributes.insert(Select);
       
   337 
       
   338         e.optionalAttributes.reserve(2);
       
   339         e.optionalAttributes.insert(CopyNamespaces);
       
   340         e.optionalAttributes.insert(Type);
       
   341         e.optionalAttributes.insert(Validation);
       
   342     }
       
   343 
       
   344     /* xsl:copy */
       
   345     {
       
   346         ElementDescription<XSLTTokenLookup> &e = result[Copy];
       
   347 
       
   348         e.optionalAttributes.reserve(5);
       
   349         e.optionalAttributes.insert(CopyNamespaces);
       
   350         e.optionalAttributes.insert(InheritNamespaces);
       
   351         e.optionalAttributes.insert(UseAttributeSets);
       
   352         e.optionalAttributes.insert(Type);
       
   353         e.optionalAttributes.insert(Validation);
       
   354     }
       
   355 
       
   356     /* xsl:output */
       
   357     {
       
   358         ElementDescription<XSLTTokenLookup> &e = result[Output];
       
   359 
       
   360         e.optionalAttributes.reserve(17);
       
   361         e.optionalAttributes.insert(Name);
       
   362         e.optionalAttributes.insert(Method);
       
   363         e.optionalAttributes.insert(ByteOrderMark);
       
   364         e.optionalAttributes.insert(CdataSectionElements);
       
   365         e.optionalAttributes.insert(DoctypePublic);
       
   366         e.optionalAttributes.insert(DoctypeSystem);
       
   367         e.optionalAttributes.insert(Encoding);
       
   368         e.optionalAttributes.insert(EscapeUriAttributes);
       
   369         e.optionalAttributes.insert(IncludeContentType);
       
   370         e.optionalAttributes.insert(Indent);
       
   371         e.optionalAttributes.insert(MediaType);
       
   372         e.optionalAttributes.insert(NormalizationForm);
       
   373         e.optionalAttributes.insert(OmitXmlDeclaration);
       
   374         e.optionalAttributes.insert(Standalone);
       
   375         e.optionalAttributes.insert(UndeclarePrefixes);
       
   376         e.optionalAttributes.insert(UseCharacterMaps);
       
   377         e.optionalAttributes.insert(Version);
       
   378     }
       
   379 
       
   380     /* xsl:attribute-set */
       
   381     {
       
   382         ElementDescription<XSLTTokenLookup> &e = result[AttributeSet];
       
   383 
       
   384         e.requiredAttributes.insert(Name);
       
   385         e.optionalAttributes.insert(UseAttributeSets);
       
   386     }
       
   387 
       
   388     /* xsl:include and xsl:import. */
       
   389     {
       
   390         ElementDescription<XSLTTokenLookup> &e = result[Include];
       
   391         e.requiredAttributes.insert(Href);
       
   392         result[Import] = e;
       
   393     }
       
   394 
       
   395     /* xsl:with-param */
       
   396     {
       
   397         ElementDescription<XSLTTokenLookup> &e = result[WithParam];
       
   398         e.requiredAttributes.insert(Name);
       
   399 
       
   400         e.optionalAttributes.insert(Select);
       
   401         e.optionalAttributes.insert(As);
       
   402         e.optionalAttributes.insert(Tunnel);
       
   403     }
       
   404 
       
   405     /* xsl:strip-space */
       
   406     {
       
   407         ElementDescription<XSLTTokenLookup> &e = result[StripSpace];
       
   408         e.requiredAttributes.insert(Elements);
       
   409 
       
   410         result.insert(PreserveSpace, e);
       
   411     }
       
   412 
       
   413     /* xsl:result-document */
       
   414     {
       
   415         ElementDescription<XSLTTokenLookup> &e = result[ResultDocument];
       
   416 
       
   417         e.optionalAttributes.insert(ByteOrderMark);
       
   418         e.optionalAttributes.insert(CdataSectionElements);
       
   419         e.optionalAttributes.insert(DoctypePublic);
       
   420         e.optionalAttributes.insert(DoctypeSystem);
       
   421         e.optionalAttributes.insert(Encoding);
       
   422         e.optionalAttributes.insert(EscapeUriAttributes);
       
   423         e.optionalAttributes.insert(Format);
       
   424         e.optionalAttributes.insert(Href);
       
   425         e.optionalAttributes.insert(IncludeContentType);
       
   426         e.optionalAttributes.insert(Indent);
       
   427         e.optionalAttributes.insert(MediaType);
       
   428         e.optionalAttributes.insert(Method);
       
   429         e.optionalAttributes.insert(NormalizationForm);
       
   430         e.optionalAttributes.insert(OmitXmlDeclaration);
       
   431         e.optionalAttributes.insert(OutputVersion);
       
   432         e.optionalAttributes.insert(Standalone);
       
   433         e.optionalAttributes.insert(Type);
       
   434         e.optionalAttributes.insert(UndeclarePrefixes);
       
   435         e.optionalAttributes.insert(UseCharacterMaps);
       
   436         e.optionalAttributes.insert(Validation);
       
   437     }
       
   438 
       
   439     /* xsl:key */
       
   440     {
       
   441         ElementDescription<XSLTTokenLookup> &e = result[Key];
       
   442 
       
   443         e.requiredAttributes.insert(Name);
       
   444         e.requiredAttributes.insert(Match);
       
   445 
       
   446         e.optionalAttributes.insert(Use);
       
   447         e.optionalAttributes.insert(Collation);
       
   448     }
       
   449 
       
   450     /* xsl:analyze-string */
       
   451     {
       
   452         ElementDescription<XSLTTokenLookup> &e = result[AnalyzeString];
       
   453 
       
   454         e.requiredAttributes.insert(Select);
       
   455         e.requiredAttributes.insert(Regex);
       
   456 
       
   457         e.optionalAttributes.insert(Flags);
       
   458     }
       
   459 
       
   460     /* xsl:matching-substring */
       
   461     {
       
   462         /* We insert a default constructed value. */
       
   463         result[MatchingSubstring];
       
   464     }
       
   465 
       
   466     /* xsl:non-matching-substring */
       
   467     {
       
   468         /* We insert a default constructed value. */
       
   469         result[NonMatchingSubstring];
       
   470     }
       
   471 
       
   472     Q_ASSERT(result.count() == ReservedForElements);
       
   473 
       
   474     return result;
       
   475 }
       
   476 
       
   477 QHash<QString, int> XSLTTokenizer::createValidationAlternatives()
       
   478 {
       
   479     QHash<QString, int> retval;
       
   480 
       
   481     retval.insert(QLatin1String("preserve"), 0);
       
   482     retval.insert(QLatin1String("strip"), 1);
       
   483     retval.insert(QLatin1String("strict"), 2);
       
   484     retval.insert(QLatin1String("lax"), 3);
       
   485 
       
   486     return retval;
       
   487 }
       
   488 
       
   489 bool XSLTTokenizer::whitespaceToSkip() const
       
   490 {
       
   491     return m_stripWhitespace.top() && isWhitespace();
       
   492 }
       
   493 
       
   494 void XSLTTokenizer::unexpectedContent(const ReportContext::ErrorCode code) const
       
   495 {
       
   496     QString message;
       
   497 
       
   498     ReportContext::ErrorCode effectiveCode = code;
       
   499 
       
   500     switch(tokenType())
       
   501     {
       
   502         case QXmlStreamReader::StartElement:
       
   503         {
       
   504             if(isXSLT())
       
   505             {
       
   506                 switch(currentElementName())
       
   507                 {
       
   508                     case Include:
       
   509                         effectiveCode = ReportContext::XTSE0170;
       
   510                         break;
       
   511                     case Import:
       
   512                         effectiveCode = ReportContext::XTSE0190;
       
   513                         break;
       
   514                     default:
       
   515                         ;
       
   516                 }
       
   517             }
       
   518 
       
   519             message = QtXmlPatterns::tr("Element %1 is not allowed at this location.")
       
   520                                        .arg(formatKeyword(name()));
       
   521             break;
       
   522         }
       
   523         case QXmlStreamReader::Characters:
       
   524         {
       
   525             if(whitespaceToSkip())
       
   526                 return;
       
   527 
       
   528             message = QtXmlPatterns::tr("Text nodes are not allowed at this location.");
       
   529             break;
       
   530         }
       
   531         case QXmlStreamReader::Invalid:
       
   532         {
       
   533             /* It's an issue with well-formedness. */
       
   534             message = escape(errorString());
       
   535             break;
       
   536         }
       
   537         default:
       
   538             Q_ASSERT(false);
       
   539     }
       
   540 
       
   541     error(message, effectiveCode);
       
   542 }
       
   543 
       
   544 void XSLTTokenizer::checkForParseError() const
       
   545 {
       
   546     if(hasError())
       
   547     {
       
   548         error(QtXmlPatterns::tr("Parse error: %1").arg(escape(errorString())), ReportContext::XTSE0010);
       
   549     }
       
   550 }
       
   551 
       
   552 QString XSLTTokenizer::readElementText()
       
   553 {
       
   554     QString result;
       
   555 
       
   556     while(!atEnd())
       
   557     {
       
   558         switch(readNext())
       
   559         {
       
   560             case QXmlStreamReader::Characters:
       
   561             {
       
   562                 result += text().toString();
       
   563                 continue;
       
   564             }
       
   565             case QXmlStreamReader::Comment:
       
   566             /* Fallthrough. */
       
   567             case QXmlStreamReader::ProcessingInstruction:
       
   568                 continue;
       
   569             case QXmlStreamReader::EndElement:
       
   570                 return result;
       
   571             default:
       
   572                 unexpectedContent();
       
   573         }
       
   574     }
       
   575 
       
   576     checkForParseError();
       
   577     return result;
       
   578 }
       
   579 
       
   580 int XSLTTokenizer::commenceScanOnly()
       
   581 {
       
   582     /* Do nothing, return a dummy value. */
       
   583     return 0;
       
   584 }
       
   585 
       
   586 void XSLTTokenizer::resumeTokenizationFrom(const int position)
       
   587 {
       
   588     /* Do nothing. */
       
   589     Q_UNUSED(position);
       
   590 }
       
   591 
       
   592 void XSLTTokenizer::handleXSLTVersion(TokenSource::Queue *const to,
       
   593                                       QStack<Token> *const queueOnExit,
       
   594                                       const bool isXSLTElement,
       
   595                                       const QXmlStreamAttributes *atts,
       
   596                                       const bool generateCode,
       
   597                                       const bool setGlobalVersion)
       
   598 {
       
   599     const QString ns(isXSLTElement ? QString() : CommonNamespaces::XSLT);
       
   600     const QXmlStreamAttributes effectiveAtts(atts ? *atts : attributes());
       
   601 
       
   602     if(!effectiveAtts.hasAttribute(ns, QLatin1String("version")))
       
   603         return;
       
   604 
       
   605     const QString attribute(effectiveAtts.value(ns, QLatin1String("version")).toString());
       
   606     const AtomicValue::Ptr number(Decimal::fromLexical(attribute));
       
   607 
       
   608     if(number->hasError())
       
   609     {
       
   610         error(QtXmlPatterns::tr("The value of the XSL-T version attribute "
       
   611                                            "must be a value of type %1, which %2 isn't.").arg(formatType(m_namePool, BuiltinTypes::xsDecimal),
       
   612                                                                                               formatData(attribute)),
       
   613               ReportContext::XTSE0110);
       
   614     }
       
   615     else
       
   616     {
       
   617 
       
   618         if(generateCode)
       
   619         {
       
   620             queueToken(Token(XSLT_VERSION, attribute), to);
       
   621             queueToken(CURLY_LBRACE, to);
       
   622         }
       
   623 
       
   624         const xsDecimal version = number->as<Numeric>()->toDecimal();
       
   625         if(version == 2.0)
       
   626             m_processingMode.push(NormalProcessing);
       
   627         else if(version == 1.0)
       
   628         {
       
   629             /* See section 3.6 Stylesheet Element discussing this. */
       
   630             warning(QtXmlPatterns::tr("Running an XSL-T 1.0 stylesheet with a 2.0 processor."));
       
   631             m_processingMode.push(BackwardsCompatible);
       
   632 
       
   633             if(setGlobalVersion)
       
   634             {
       
   635                 m_parseInfo->staticContext->setCompatModeEnabled(true);
       
   636                 m_parseInfo->isBackwardsCompat.push(true);
       
   637             }
       
   638         }
       
   639         else if(version > 2.0)
       
   640             m_processingMode.push(ForwardCompatible);
       
   641         else if(version < 2.0)
       
   642             m_processingMode.push(BackwardsCompatible);
       
   643     }
       
   644 
       
   645     if(generateCode)
       
   646         queueOnExit->push(CURLY_RBRACE);
       
   647 }
       
   648 
       
   649 void XSLTTokenizer::handleXMLBase(TokenSource::Queue *const to,
       
   650                                   QStack<Token> *const queueOnExit,
       
   651                                   const bool isInstruction,
       
   652                                   const QXmlStreamAttributes *atts)
       
   653 {
       
   654     const QXmlStreamAttributes effectiveAtts(atts ? *atts : m_currentAttributes);
       
   655 
       
   656     if(effectiveAtts.hasAttribute(QLatin1String("xml:base")))
       
   657     {
       
   658         const QStringRef val(effectiveAtts.value(QLatin1String("xml:base")));
       
   659 
       
   660         if(!val.isEmpty())
       
   661         {
       
   662             if(isInstruction)
       
   663             {
       
   664                 queueToken(BASEURI, to);
       
   665                 queueToken(Token(STRING_LITERAL, val.toString()), to);
       
   666                 queueToken(CURLY_LBRACE, to);
       
   667                 queueOnExit->push(CURLY_RBRACE);
       
   668             }
       
   669             else
       
   670             {
       
   671                 queueToken(DECLARE, to);
       
   672                 queueToken(BASEURI, to);
       
   673                 queueToken(INTERNAL, to);
       
   674                 queueToken(Token(STRING_LITERAL, val.toString()), to);
       
   675                 queueToken(SEMI_COLON, to);
       
   676             }
       
   677         }
       
   678     }
       
   679 }
       
   680 
       
   681 void XSLTTokenizer::handleStandardAttributes(const bool isXSLTElement)
       
   682 {
       
   683     /* We're not necessarily StartElement, that's why we have atts passed in. */
       
   684     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
   685 
       
   686     if(m_hasHandledStandardAttributes)
       
   687         return;
       
   688 
       
   689     m_hasHandledStandardAttributes = true;
       
   690 
       
   691     const QString ns(isXSLTElement ? QString() : CommonNamespaces::XSLT);
       
   692     const int len = m_currentAttributes.count();
       
   693 
       
   694     for(int i = 0; i < len; ++i)
       
   695     {
       
   696         const QXmlStreamAttribute &att = m_currentAttributes.at(i);
       
   697 
       
   698         if(att.qualifiedName() == QLatin1String("xml:space"))
       
   699         {
       
   700             const QStringRef val(m_currentAttributes.value(CommonNamespaces::XML, QLatin1String("space")));
       
   701 
       
   702             /* We raise an error if the value is not recognized.
       
   703              *
       
   704              * Extensible Markup Language (XML) 1.0 (Fourth Edition), 2.10
       
   705              * White Space Handling:
       
   706              *
       
   707              * 'This specification does not give meaning to any value of
       
   708              * xml:space other than "default" and "preserve". It is an error
       
   709              * for other values to be specified; the XML processor may report
       
   710              * the error or may recover by ignoring the attribute specification
       
   711              * or by reporting the (erroneous) value to the application.' */
       
   712             m_stripWhitespace.push(readToggleAttribute(QLatin1String("xml:space"),
       
   713                                                        QLatin1String("default"),
       
   714                                                        QLatin1String("preserve"),
       
   715                                                        &m_currentAttributes));
       
   716         }
       
   717 
       
   718         if(att.namespaceUri() != ns)
       
   719             continue;
       
   720 
       
   721         switch(toToken(att.name()))
       
   722         {
       
   723             case Type:
       
   724             /* Fallthrough. */
       
   725             case Validation:
       
   726             /* Fallthrough. */
       
   727             case UseAttributeSets:
       
   728             /* Fallthrough. */
       
   729             case Version:
       
   730                 /* These are handled by other function such as
       
   731                  * handleValidationAttributes() and handleXSLTVersion(). */
       
   732                 continue;
       
   733             default:
       
   734             {
       
   735                 if(!isXSLTElement) /* validateElement() will take care of it, and we
       
   736                                     * don't want to flag non-standard XSL-T attributes. */
       
   737                 {
       
   738                     error(QtXmlPatterns::tr("Unknown XSL-T attribute %1.")
       
   739                                                       .arg(formatKeyword(att.name())),
       
   740                           ReportContext::XTSE0805);
       
   741                 }
       
   742             }
       
   743         }
       
   744     }
       
   745 }
       
   746 
       
   747 void XSLTTokenizer::handleValidationAttributes(const bool isLRE) const
       
   748 {
       
   749     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
   750 
       
   751     const QString ns(isLRE ? QString() : CommonNamespaces::XSLT);
       
   752 
       
   753     const bool hasValidation = hasAttribute(ns, QLatin1String("validation"));
       
   754     const bool hasType = hasAttribute(ns, QLatin1String("type"));
       
   755 
       
   756     if(!hasType && !hasValidation)
       
   757         return;
       
   758 
       
   759     if(hasType && hasValidation)
       
   760     {
       
   761         error(QtXmlPatterns::tr("Attribute %1 and %2 are mutually exclusive.")
       
   762                                           .arg(formatKeyword(QLatin1String("validation")),
       
   763                                                formatKeyword(QLatin1String("type"))),
       
   764               ReportContext::XTSE1505);
       
   765     }
       
   766 
       
   767     /* QXmlStreamReader surely doesn't make this easy. */
       
   768     QXmlStreamAttribute validationAttribute;
       
   769     int len = m_currentAttributes.count();
       
   770 
       
   771     for(int i = 0; i < len; ++i)
       
   772     {
       
   773         const QXmlStreamAttribute &at = m_currentAttributes.at(i);
       
   774         if(at.name() == QLatin1String("validation") && at.namespaceUri() == ns)
       
   775             validationAttribute = at;
       
   776     }
       
   777 
       
   778     Q_ASSERT_X(!validationAttribute.name().isNull(), Q_FUNC_INFO,
       
   779                "We should always find the attribute.");
       
   780 
       
   781     /* We don't care about the return value, we just want to check it's a valid
       
   782      * one. */
       
   783     readAlternativeAttribute(m_validationAlternatives,
       
   784                              validationAttribute);
       
   785 }
       
   786 
       
   787 Tokenizer::Token XSLTTokenizer::nextToken(YYLTYPE *const sourceLocator)
       
   788 {
       
   789     Q_UNUSED(sourceLocator);
       
   790 
       
   791     if(m_tokenSource.isEmpty())
       
   792     {
       
   793         switch(m_state.top())
       
   794         {
       
   795             case OutsideDocumentElement:
       
   796                 outsideDocumentElement();
       
   797                 break;
       
   798             case InsideStylesheetModule:
       
   799                 insideStylesheetModule();
       
   800                 break;
       
   801             case InsideSequenceConstructor:
       
   802                 insideSequenceConstructor(&m_tokenSource);
       
   803                 break;
       
   804         }
       
   805 
       
   806         if(m_tokenSource.isEmpty())
       
   807         {
       
   808             *sourceLocator = currentSourceLocator();
       
   809             return Token(END_OF_FILE);
       
   810         }
       
   811         else
       
   812             return m_tokenSource.head()->nextToken(sourceLocator);
       
   813     }
       
   814     else
       
   815     {
       
   816         do
       
   817         {
       
   818             const Token candidate(m_tokenSource.head()->nextToken(sourceLocator));
       
   819             if(candidate.type == END_OF_FILE)
       
   820                 m_tokenSource.dequeue();
       
   821             else
       
   822                 return candidate;
       
   823         }
       
   824         while(!m_tokenSource.isEmpty());
       
   825 
       
   826         /* Now we will resume parsing inside the regular XSL-T(XML) file. */
       
   827         return nextToken(sourceLocator);
       
   828     }
       
   829 }
       
   830 
       
   831 bool XSLTTokenizer::isElement(const XSLTTokenLookup::NodeName &name) const
       
   832 {
       
   833     Q_ASSERT(isXSLT());
       
   834     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement ||
       
   835              tokenType() == QXmlStreamReader::EndElement);
       
   836 
       
   837     return currentElementName() == name;
       
   838 }
       
   839 
       
   840 inline bool XSLTTokenizer::isXSLT() const
       
   841 {
       
   842     Q_ASSERT_X(tokenType() == QXmlStreamReader::StartElement ||
       
   843                tokenType() == QXmlStreamReader::EndElement,
       
   844                Q_FUNC_INFO, "The current token state must be StartElement or EndElement.");
       
   845     /* Possible optimization: let MaintainingReader set an m_isXSLT which we
       
   846      * read. */
       
   847     return namespaceUri() == CommonNamespaces::XSLT;
       
   848 }
       
   849 
       
   850 void XSLTTokenizer::queueOnExit(QStack<Token> &source,
       
   851                                 TokenSource::Queue *const destination)
       
   852 {
       
   853     while(!source.isEmpty())
       
   854         queueToken(source.pop(), destination);
       
   855 }
       
   856 
       
   857 void XSLTTokenizer::outsideDocumentElement()
       
   858 {
       
   859     while(!atEnd())
       
   860     {
       
   861         switch(readNext())
       
   862         {
       
   863             case QXmlStreamReader::StartElement:
       
   864             {
       
   865                 /* First, we synthesize one of the built-in templates,
       
   866                  * see section 6.6 Built-in Template Rules.
       
   867                  *
       
   868                  * Note that insideStylesheetModule() can be called multiple
       
   869                  * times so we can't do it there.  */
       
   870                 {
       
   871                     /* Start with the one for text nodes and attributes.
       
   872                      * declare template matches (text() | @*) mode #all
       
   873                      * {
       
   874                      *      text{.}
       
   875                      * };
       
   876                      */
       
   877 
       
   878                     /* declare template matches (text() | @*) */
       
   879                     queueToken(DECLARE, &m_tokenSource);
       
   880                     queueToken(TEMPLATE, &m_tokenSource);
       
   881                     queueToken(MATCHES, &m_tokenSource);
       
   882                     queueToken(LPAREN, &m_tokenSource);
       
   883                     queueToken(TEXT, &m_tokenSource);
       
   884                     queueToken(LPAREN, &m_tokenSource);
       
   885                     queueToken(RPAREN, &m_tokenSource);
       
   886                     queueToken(BAR, &m_tokenSource);
       
   887                     queueToken(AT_SIGN, &m_tokenSource);
       
   888                     queueToken(STAR, &m_tokenSource);
       
   889                     queueToken(RPAREN, &m_tokenSource);
       
   890 
       
   891                     /* mode #all */
       
   892                     queueToken(MODE, &m_tokenSource);
       
   893                     queueToken(Token(NCNAME, QLatin1String("#all")), &m_tokenSource);
       
   894                     queueToken(CURLY_LBRACE, &m_tokenSource);
       
   895 
       
   896                     /* text{.} { */
       
   897                     queueToken(TEXT, &m_tokenSource);
       
   898                     queueToken(CURLY_LBRACE, &m_tokenSource);
       
   899                     queueToken(DOT, &m_tokenSource);
       
   900                     queueToken(CURLY_RBRACE, &m_tokenSource);
       
   901 
       
   902                     /* }; */
       
   903                     queueToken(CURLY_RBRACE, &m_tokenSource);
       
   904                     queueToken(SEMI_COLON, &m_tokenSource);
       
   905                 }
       
   906 
       
   907                 if(isXSLT() && isStylesheetElement())
       
   908                 {
       
   909                     handleStandardAttributes(true);
       
   910                     QStack<Token> onExitTokens;
       
   911                     handleXMLBase(&m_tokenSource, &onExitTokens, false);
       
   912                     handleXSLTVersion(&m_tokenSource, &onExitTokens, true, 0, false, true);
       
   913                     validateElement();
       
   914                     queueNamespaceDeclarations(&m_tokenSource, 0, true);
       
   915 
       
   916                     /* We're a regular stylesheet. */
       
   917 
       
   918                     pushState(InsideStylesheetModule);
       
   919                     insideStylesheetModule();
       
   920                 }
       
   921                 else
       
   922                 {
       
   923                     /* We're a simplified stylesheet. */
       
   924 
       
   925                     if(!hasAttribute(CommonNamespaces::XSLT, QLatin1String("version")))
       
   926                     {
       
   927                         error(QtXmlPatterns::tr("In a simplified stylesheet module, attribute %1 must be present.")
       
   928                                                           .arg(formatKeyword(QLatin1String("version"))),
       
   929                               ReportContext::XTSE0010);
       
   930                     }
       
   931 
       
   932                     QStack<Token> onExitTokens;
       
   933 
       
   934                     /* We synthesize this as exemplified in
       
   935                      * 3.7 Simplified Stylesheet Modules. */
       
   936                     queueToken(DECLARE, &m_tokenSource);
       
   937                     queueToken(TEMPLATE, &m_tokenSource);
       
   938                     queueToken(MATCHES, &m_tokenSource);
       
   939                     queueToken(LPAREN, &m_tokenSource);
       
   940                     queueToken(SLASH, &m_tokenSource);
       
   941                     queueToken(RPAREN, &m_tokenSource);
       
   942                     queueToken(CURLY_LBRACE, &m_tokenSource);
       
   943                     pushState(InsideSequenceConstructor);
       
   944 
       
   945                     handleXSLTVersion(&m_tokenSource, &onExitTokens, false, 0, true);
       
   946                     handleStandardAttributes(false);
       
   947 
       
   948                     insideSequenceConstructor(&m_tokenSource, false);
       
   949 
       
   950                     queueOnExit(onExitTokens, &m_tokenSource);
       
   951                     queueToken(CURLY_RBRACE, &m_tokenSource);
       
   952                     queueToken(CURLY_RBRACE, &m_tokenSource);
       
   953                     queueToken(SEMI_COLON, &m_tokenSource);
       
   954                 }
       
   955 
       
   956                 queueToken(APPLY_TEMPLATE, &m_tokenSource);
       
   957                 queueToken(LPAREN, &m_tokenSource);
       
   958                 queueToken(RPAREN, &m_tokenSource);
       
   959 
       
   960                 break;
       
   961             }
       
   962             default:
       
   963                 /* Do nothing. */;
       
   964         }
       
   965     }
       
   966     checkForParseError();
       
   967 }
       
   968 
       
   969 void XSLTTokenizer::queueToken(const Token &token,
       
   970                                TokenSource::Queue *const to)
       
   971 {
       
   972     TokenSource::Queue *const effective = to ? to : &m_tokenSource;
       
   973 
       
   974     effective->enqueue(TokenSource::Ptr(new SingleTokenContainer(token, currentSourceLocator())));
       
   975 }
       
   976 
       
   977 void XSLTTokenizer::pushState(const State nextState)
       
   978 {
       
   979     m_state.push(nextState);
       
   980 }
       
   981 
       
   982 void XSLTTokenizer::leaveState()
       
   983 {
       
   984     m_state.pop();
       
   985 }
       
   986 
       
   987 void XSLTTokenizer::insideTemplate()
       
   988 {
       
   989     const bool hasPriority  = hasAttribute(QLatin1String("priority"));
       
   990     const bool hasMatch     = hasAttribute(QLatin1String("match"));
       
   991     const bool hasName      = hasAttribute(QLatin1String("name"));
       
   992     const bool hasMode      = hasAttribute(QLatin1String("mode"));
       
   993     const bool hasAs        = hasAttribute(QLatin1String("as"));
       
   994 
       
   995     if(!hasMatch &&
       
   996        (hasMode ||
       
   997         hasPriority))
       
   998     {
       
   999         error(QtXmlPatterns::tr("If element %1 has no attribute %2, it cannot have attribute %3 or %4.")
       
  1000                          .arg(formatKeyword(QLatin1String("template")),
       
  1001                               formatKeyword(QLatin1String("match")),
       
  1002                               formatKeyword(QLatin1String("mode")),
       
  1003                               formatKeyword(QLatin1String("priority"))),
       
  1004               ReportContext::XTSE0500);
       
  1005     }
       
  1006     else if(!hasMatch && !hasName)
       
  1007     {
       
  1008         error(QtXmlPatterns::tr("Element %1 must have at least one of the attributes %2 or %3.")
       
  1009                          .arg(formatKeyword(QLatin1String("template")),
       
  1010                               formatKeyword(QLatin1String("name")),
       
  1011                               formatKeyword(QLatin1String("match"))),
       
  1012               ReportContext::XTSE0500);
       
  1013     }
       
  1014 
       
  1015     queueToken(DECLARE, &m_tokenSource);
       
  1016     queueToken(TEMPLATE, &m_tokenSource);
       
  1017 
       
  1018     if(hasName)
       
  1019     {
       
  1020         queueToken(NAME, &m_tokenSource);
       
  1021         queueToken(Token(QNAME, readAttribute(QLatin1String("name"))), &m_tokenSource);
       
  1022     }
       
  1023 
       
  1024     if(hasMatch)
       
  1025     {
       
  1026         queueToken(MATCHES, &m_tokenSource);
       
  1027         queueExpression(readAttribute(QLatin1String("match")), &m_tokenSource);
       
  1028     }
       
  1029 
       
  1030     if(hasMode)
       
  1031     {
       
  1032         const QString modeString(readAttribute(QLatin1String("mode")).simplified());
       
  1033 
       
  1034         if(modeString.isEmpty())
       
  1035         {
       
  1036             error(QtXmlPatterns::tr("At least one mode must be specified in the %1-attribute on element %2.")
       
  1037                              .arg(formatKeyword(QLatin1String("mode")),
       
  1038                                   formatKeyword(QLatin1String("template"))),
       
  1039                   ReportContext::XTSE0500);
       
  1040         }
       
  1041 
       
  1042         queueToken(MODE, &m_tokenSource);
       
  1043 
       
  1044         const QStringList modeList(modeString.split(QLatin1Char(' ')));
       
  1045 
       
  1046         for(int i = 0; i < modeList.count(); ++i)
       
  1047         {
       
  1048             const QString &mode = modeList.at(i);
       
  1049 
       
  1050             queueToken(Token(mode.contains(QLatin1Char(':')) ? QNAME : NCNAME, mode), &m_tokenSource);
       
  1051 
       
  1052             if(i < modeList.count() - 1)
       
  1053                 queueToken(COMMA, &m_tokenSource);
       
  1054         }
       
  1055     }
       
  1056 
       
  1057     if(hasPriority)
       
  1058     {
       
  1059         queueToken(PRIORITY, &m_tokenSource);
       
  1060         queueToken(Token(STRING_LITERAL, readAttribute(QLatin1String("priority"))), &m_tokenSource);
       
  1061     }
       
  1062 
       
  1063     QStack<Token> onExitTokens;
       
  1064     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  1065 
       
  1066     /* queueParams moves the reader so we need to freeze the attributes. */
       
  1067     const QXmlStreamAttributes atts(m_currentAttributes);
       
  1068     handleStandardAttributes(true);
       
  1069     queueToken(LPAREN, &m_tokenSource);
       
  1070     queueParams(Template, &m_tokenSource);
       
  1071     queueToken(RPAREN, &m_tokenSource);
       
  1072 
       
  1073     if(hasAs)
       
  1074     {
       
  1075         queueToken(AS, &m_tokenSource);
       
  1076         queueSequenceType(atts.value(QLatin1String("as")).toString());
       
  1077     }
       
  1078 
       
  1079     queueToken(CURLY_LBRACE, &m_tokenSource);
       
  1080 
       
  1081     handleXMLBase(&m_tokenSource, &onExitTokens, true, &atts);
       
  1082     handleXSLTVersion(&m_tokenSource, &onExitTokens, true, &atts);
       
  1083     pushState(InsideSequenceConstructor);
       
  1084     startStorageOfCurrent(&m_tokenSource);
       
  1085     insideSequenceConstructor(&m_tokenSource, onExitTokens, false);
       
  1086     queueOnExit(onExitTokens, &m_tokenSource);
       
  1087 }
       
  1088 
       
  1089 void XSLTTokenizer::queueExpression(const QString &expr,
       
  1090                                     TokenSource::Queue *const to,
       
  1091                                     const bool wrapWithParantheses)
       
  1092 {
       
  1093     TokenSource::Queue *const effectiveTo = to ? to : &m_tokenSource;
       
  1094 
       
  1095     if(wrapWithParantheses)
       
  1096         queueToken(LPAREN, effectiveTo);
       
  1097 
       
  1098     effectiveTo->enqueue(TokenSource::Ptr(new XQueryTokenizer(expr, queryURI())));
       
  1099 
       
  1100     if(wrapWithParantheses)
       
  1101         queueToken(RPAREN, effectiveTo);
       
  1102 }
       
  1103 
       
  1104 void XSLTTokenizer::queueAVT(const QString &expr,
       
  1105                              TokenSource::Queue *const to)
       
  1106 {
       
  1107     queueToken(AVT, to);
       
  1108     queueToken(LPAREN, to);
       
  1109     to->enqueue(TokenSource::Ptr(new XQueryTokenizer(expr, queryURI(),
       
  1110                                                                XQueryTokenizer::QuotAttributeContent)));
       
  1111     queueToken(RPAREN, to);
       
  1112 }
       
  1113 
       
  1114 void XSLTTokenizer::queueSequenceType(const QString &expr)
       
  1115 {
       
  1116     m_tokenSource.enqueue(TokenSource::Ptr(new XQueryTokenizer(expr, queryURI(),
       
  1117                                                                          XQueryTokenizer::ItemType)));
       
  1118 }
       
  1119 
       
  1120 void XSLTTokenizer::commencingExpression(bool &hasWrittenExpression,
       
  1121                                          TokenSource::Queue *const to)
       
  1122 {
       
  1123     if(hasWrittenExpression)
       
  1124         queueToken(COMMA, to);
       
  1125     else
       
  1126         hasWrittenExpression = true;
       
  1127 }
       
  1128 
       
  1129 void XSLTTokenizer::queueEmptySequence(TokenSource::Queue *const to)
       
  1130 {
       
  1131     queueToken(LPAREN, to);
       
  1132     queueToken(RPAREN, to);
       
  1133 }
       
  1134 
       
  1135 void XSLTTokenizer::insideChoose(TokenSource::Queue *const to)
       
  1136 {
       
  1137     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  1138     bool hasHandledOtherwise = false;
       
  1139     bool hasEncounteredAtLeastOneWhen = false;
       
  1140 
       
  1141     while(!atEnd())
       
  1142     {
       
  1143         switch(readNext())
       
  1144         {
       
  1145             case QXmlStreamReader::StartElement:
       
  1146             {
       
  1147                 if(isXSLT())
       
  1148                 {
       
  1149                     QStack<Token> onExitTokens;
       
  1150                     handleStandardAttributes(true);
       
  1151                     validateElement();
       
  1152 
       
  1153                     switch(currentElementName())
       
  1154                     {
       
  1155                         case When:
       
  1156                         {
       
  1157                             if(hasHandledOtherwise)
       
  1158                             {
       
  1159                                 error(QtXmlPatterns::tr("Element %1 must come last.")
       
  1160                                                                   .arg(formatKeyword(QLatin1String("otherwise"))),
       
  1161                                       ReportContext::XTSE0010);
       
  1162                             }
       
  1163 
       
  1164                             queueToken(IF, to);
       
  1165                             queueToken(LPAREN, to);
       
  1166                             queueExpression(readAttribute(QLatin1String("test")), to);
       
  1167                             queueToken(RPAREN, to);
       
  1168                             queueToken(THEN, to);
       
  1169                             queueToken(LPAREN, to);
       
  1170                             pushState(InsideSequenceConstructor);
       
  1171                             insideSequenceConstructor(to);
       
  1172                             queueToken(RPAREN, to);
       
  1173                             Q_ASSERT(tokenType() == QXmlStreamReader::EndElement);
       
  1174                             queueToken(ELSE, to);
       
  1175                             hasEncounteredAtLeastOneWhen = true;
       
  1176                             queueOnExit(onExitTokens, to);
       
  1177                             break;
       
  1178                         }
       
  1179                         case Otherwise:
       
  1180                         {
       
  1181                             if(!hasEncounteredAtLeastOneWhen)
       
  1182                             {
       
  1183                                 error(QtXmlPatterns::tr("At least one %1-element must occur before %2.")
       
  1184                                                                   .arg(formatKeyword(QLatin1String("when")),
       
  1185                                                                        formatKeyword(QLatin1String("otherwise"))),
       
  1186                                       ReportContext::XTSE0010);
       
  1187                             }
       
  1188                             else if(hasHandledOtherwise)
       
  1189                             {
       
  1190                                 error(QtXmlPatterns::tr("Only one %1-element can appear.")
       
  1191                                                                   .arg(formatKeyword(QLatin1String("otherwise"))),
       
  1192                                       ReportContext::XTSE0010);
       
  1193                             }
       
  1194 
       
  1195                             pushState(InsideSequenceConstructor);
       
  1196                             queueToken(LPAREN, to);
       
  1197                             insideSequenceConstructor(to, to);
       
  1198                             queueToken(RPAREN, to);
       
  1199                             hasHandledOtherwise = true;
       
  1200                             queueOnExit(onExitTokens, to);
       
  1201                             break;
       
  1202                         }
       
  1203                         default:
       
  1204                             unexpectedContent();
       
  1205                     }
       
  1206                 }
       
  1207                 else
       
  1208                     unexpectedContent();
       
  1209                 break;
       
  1210             }
       
  1211             case QXmlStreamReader::EndElement:
       
  1212             {
       
  1213                 if(isXSLT())
       
  1214                 {
       
  1215                     switch(currentElementName())
       
  1216                     {
       
  1217                         case Choose:
       
  1218                         {
       
  1219                             if(!hasEncounteredAtLeastOneWhen)
       
  1220                             {
       
  1221                                 error(QtXmlPatterns::tr("At least one %1-element must occur inside %2.")
       
  1222                                                                   .arg(formatKeyword(QLatin1String("when")),
       
  1223                                                                        formatKeyword(QLatin1String("choose"))),
       
  1224                                       ReportContext::XTSE0010);
       
  1225                             }
       
  1226 
       
  1227                             if(!hasHandledOtherwise)
       
  1228                                 queueEmptySequence(to);
       
  1229                             return;
       
  1230                         }
       
  1231                         case Otherwise:
       
  1232                             continue;
       
  1233                         default:
       
  1234                             unexpectedContent();
       
  1235                     }
       
  1236                 }
       
  1237                 else
       
  1238                     unexpectedContent();
       
  1239                 break;
       
  1240             }
       
  1241             case QXmlStreamReader::Comment:
       
  1242             /* Fallthrough. */
       
  1243             case QXmlStreamReader::ProcessingInstruction:
       
  1244                 continue;
       
  1245             case QXmlStreamReader::Characters:
       
  1246             {
       
  1247                 /* We ignore regardless of what xml:space says, see step 4 in
       
  1248                  * 4.2 Stripping Whitespace from the Stylesheet. */
       
  1249                 if(isWhitespace())
       
  1250                     continue;
       
  1251                 /* Fallthrough. */
       
  1252             }
       
  1253             default:
       
  1254                 /* Fallthrough. */
       
  1255                 unexpectedContent();
       
  1256                 break;
       
  1257         }
       
  1258     }
       
  1259     checkForParseError();
       
  1260 }
       
  1261 
       
  1262 bool XSLTTokenizer::queueSelectOrSequenceConstructor(const ReportContext::ErrorCode code,
       
  1263                                                      const bool emptynessAllowed,
       
  1264                                                      TokenSource::Queue *const to,
       
  1265                                                      const QXmlStreamAttributes *const attsP,
       
  1266                                                      const bool queueEmptyOnEmpty)
       
  1267 {
       
  1268     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement || attsP);
       
  1269     const NodeName elementName(currentElementName());
       
  1270     const QXmlStreamAttributes atts(attsP ? *attsP : m_currentAttributes);
       
  1271 
       
  1272     if(atts.hasAttribute(QLatin1String("select")))
       
  1273     {
       
  1274         queueExpression(atts.value(QLatin1String("select")).toString(), to);
       
  1275 
       
  1276         /* First, verify that we don't have a body. */
       
  1277         if(skipSubTree(true))
       
  1278         {
       
  1279             error(QtXmlPatterns::tr("When attribute %1 is present on %2, a sequence "
       
  1280                                                "constructor cannot be used.").arg(formatKeyword(QLatin1String("select")),
       
  1281                                                                                   formatKeyword(toString(elementName))),
       
  1282                   code);
       
  1283         }
       
  1284 
       
  1285         return true;
       
  1286     }
       
  1287     else
       
  1288     {
       
  1289         pushState(InsideSequenceConstructor);
       
  1290         if(!insideSequenceConstructor(to, true, queueEmptyOnEmpty) && !emptynessAllowed)
       
  1291         {
       
  1292             error(QtXmlPatterns::tr("Element %1 must have either a %2-attribute "
       
  1293                                                "or a sequence constructor.").arg(formatKeyword(toString(elementName)),
       
  1294                                                                                  formatKeyword(QLatin1String("select"))),
       
  1295                   code);
       
  1296 
       
  1297         }
       
  1298 
       
  1299         return false;
       
  1300     }
       
  1301 }
       
  1302 
       
  1303 void XSLTTokenizer::queueSimpleContentConstructor(const ReportContext::ErrorCode code,
       
  1304                                                   const bool emptynessAllowed,
       
  1305                                                   TokenSource::Queue *const to,
       
  1306                                                   const bool selectOnlyFirst)
       
  1307 {
       
  1308     queueToken(INTERNAL_NAME, to);
       
  1309     queueToken(Token(NCNAME, QLatin1String("generic-string-join")), to);
       
  1310     queueToken(LPAREN, to);
       
  1311 
       
  1312     /* We have to read the attribute before calling
       
  1313      * queueSelectOrSequenceConstructor(), since it advances the reader. */
       
  1314     const bool hasSeparator = m_currentAttributes.hasAttribute(QLatin1String("separator"));
       
  1315     const QString separatorAVT(m_currentAttributes.value(QLatin1String("separator")).toString());
       
  1316 
       
  1317     queueToken(LPAREN, to);
       
  1318     const bool viaSelectAttribute = queueSelectOrSequenceConstructor(code, emptynessAllowed, to);
       
  1319     queueToken(RPAREN, to);
       
  1320 
       
  1321     if(selectOnlyFirst)
       
  1322     {
       
  1323         queueToken(LBRACKET, to);
       
  1324         queueToken(Token(NUMBER, QChar::fromLatin1('1')), to);
       
  1325         queueToken(RBRACKET, to);
       
  1326     }
       
  1327 
       
  1328     queueToken(COMMA, to);
       
  1329 
       
  1330     if(hasSeparator)
       
  1331         queueAVT(separatorAVT, to);
       
  1332     else
       
  1333     {
       
  1334         /* The default value depends on whether the value is from @select, or from
       
  1335          * the sequence constructor. */
       
  1336         queueToken(Token(STRING_LITERAL, viaSelectAttribute ? QString(QLatin1Char(' '))
       
  1337                                                             : QString()),
       
  1338                    to);
       
  1339     }
       
  1340 
       
  1341     queueToken(RPAREN, to);
       
  1342 }
       
  1343 
       
  1344 void XSLTTokenizer::queueTextConstructor(QString &chars,
       
  1345                                          bool &hasWrittenExpression,
       
  1346                                          TokenSource::Queue *const to)
       
  1347 {
       
  1348     if(!chars.isEmpty())
       
  1349     {
       
  1350         commencingExpression(hasWrittenExpression, to);
       
  1351         queueToken(TEXT, to);
       
  1352         queueToken(CURLY_LBRACE, to);
       
  1353         queueToken(Token(STRING_LITERAL, chars), to);
       
  1354         queueToken(CURLY_RBRACE, to);
       
  1355         chars.clear();
       
  1356     }
       
  1357 }
       
  1358 
       
  1359 void XSLTTokenizer::queueVariableDeclaration(const VariableType variableType,
       
  1360                                              TokenSource::Queue *const to)
       
  1361 {
       
  1362     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  1363 
       
  1364     if(variableType == VariableInstruction)
       
  1365     {
       
  1366         queueToken(LET, to);
       
  1367         queueToken(INTERNAL, to);
       
  1368     }
       
  1369     else if(variableType == VariableDeclaration || variableType == GlobalParameter)
       
  1370     {
       
  1371         queueToken(DECLARE, to);
       
  1372         queueToken(VARIABLE, to);
       
  1373         queueToken(INTERNAL, to);
       
  1374     }
       
  1375 
       
  1376     queueToken(DOLLAR, to);
       
  1377 
       
  1378     queueExpression(readAttribute(QLatin1String("name")), to, false);
       
  1379 
       
  1380     const bool hasAs = m_currentAttributes.hasAttribute(QLatin1String("as"));
       
  1381     if(hasAs)
       
  1382     {
       
  1383         queueToken(AS, to);
       
  1384         queueSequenceType(m_currentAttributes.value(QLatin1String("as")).toString());
       
  1385     }
       
  1386 
       
  1387     if(variableType == FunctionParameter)
       
  1388     {
       
  1389         skipBodyOfParam(ReportContext::XTSE0760);
       
  1390         return;
       
  1391     }
       
  1392 
       
  1393     /* We must do this here, because queueSelectOrSequenceConstructor()
       
  1394      * advances the reader. */
       
  1395     const bool hasSelect = hasAttribute(QLatin1String("select"));
       
  1396     const bool isRequired = hasAttribute(QLatin1String("required")) ? attributeYesNo(QLatin1String("required")) : false;
       
  1397 
       
  1398     TokenSource::Queue storage;
       
  1399     queueSelectOrSequenceConstructor(ReportContext::XTSE0620, true, &storage, 0, false);
       
  1400 
       
  1401     /* XSL-T has some wicked rules, see
       
  1402      * 9.3 Values of Variables and Parameters. */
       
  1403 
       
  1404     const bool hasQueuedContent = !storage.isEmpty();
       
  1405 
       
  1406     /* The syntax for global parameters is:
       
  1407      *
       
  1408      * declare variable $var external := 'defaultValue';
       
  1409      */
       
  1410     if(variableType == GlobalParameter)
       
  1411         queueToken(EXTERNAL, to);
       
  1412 
       
  1413     if(isRequired)
       
  1414     {
       
  1415         if(hasQueuedContent)
       
  1416         {
       
  1417             error(QtXmlPatterns::tr("When a parameter is required, a default value "
       
  1418                                                "cannot be supplied through a %1-attribute or "
       
  1419                                                "a sequence constructor.").arg(formatKeyword(QLatin1String("select"))),
       
  1420                   ReportContext::XTSE0010);
       
  1421         }
       
  1422     }
       
  1423     else
       
  1424     {
       
  1425         if(hasQueuedContent)
       
  1426         {
       
  1427             queueToken(ASSIGN, to);
       
  1428 
       
  1429             if(!hasSelect && !hasAs && !hasQueuedContent)
       
  1430                 queueToken(Token(STRING_LITERAL, QString()), to);
       
  1431             else if(hasAs || hasSelect)
       
  1432                 queueToken(LPAREN, to);
       
  1433             else
       
  1434             {
       
  1435                 queueToken(DOCUMENT, to);
       
  1436                 queueToken(INTERNAL, to);
       
  1437                 queueToken(CURLY_LBRACE, to);
       
  1438             }
       
  1439         }
       
  1440         else
       
  1441         {
       
  1442             if(!hasAs)
       
  1443             {
       
  1444                 queueToken(ASSIGN, to);
       
  1445                 queueToken(Token(STRING_LITERAL, QString()), to);
       
  1446             }
       
  1447             else if(variableType == VariableDeclaration || variableType == VariableInstruction)
       
  1448             {
       
  1449                 queueToken(ASSIGN, to);
       
  1450                 queueEmptySequence(to);
       
  1451             }
       
  1452         }
       
  1453 
       
  1454         /* storage has tokens if hasSelect or hasQueuedContent is true. */
       
  1455         if(hasSelect | hasQueuedContent)
       
  1456             *to += storage;
       
  1457 
       
  1458         if(hasQueuedContent)
       
  1459         {
       
  1460             if(!hasSelect && !hasAs && !hasQueuedContent)
       
  1461                 queueToken(Token(STRING_LITERAL, QString()), to);
       
  1462             else if(hasAs || hasSelect)
       
  1463                 queueToken(RPAREN, to);
       
  1464             else
       
  1465                 queueToken(CURLY_RBRACE, to);
       
  1466         }
       
  1467     }
       
  1468 
       
  1469     if(variableType == VariableInstruction)
       
  1470         queueToken(RETURN, to);
       
  1471     else if(variableType == VariableDeclaration || variableType == GlobalParameter)
       
  1472         queueToken(SEMI_COLON, to);
       
  1473 }
       
  1474 
       
  1475 void XSLTTokenizer::startStorageOfCurrent(TokenSource::Queue *const to)
       
  1476 {
       
  1477     queueToken(CURRENT, to);
       
  1478     queueToken(CURLY_LBRACE, to);
       
  1479 }
       
  1480 
       
  1481 void XSLTTokenizer::endStorageOfCurrent(TokenSource::Queue *const to)
       
  1482 {
       
  1483     queueToken(CURLY_RBRACE, to);
       
  1484 }
       
  1485 
       
  1486 void XSLTTokenizer::queueNamespaceDeclarations(TokenSource::Queue *const to,
       
  1487                                                QStack<Token> *const queueOnExit,
       
  1488                                                const bool isDeclaration)
       
  1489 {
       
  1490     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  1491     Q_ASSERT_X(isDeclaration || queueOnExit,
       
  1492                Q_FUNC_INFO,
       
  1493                "If isDeclaration is false, queueOnExit must be passed.");
       
  1494 
       
  1495     const QXmlStreamNamespaceDeclarations nss(namespaceDeclarations());
       
  1496 
       
  1497     for(int i = 0; i < nss.count(); ++i)
       
  1498     {
       
  1499         const QXmlStreamNamespaceDeclaration &at = nss.at(i);
       
  1500         queueToken(DECLARE, to);
       
  1501         queueToken(NAMESPACE, to);
       
  1502         queueToken(Token(NCNAME, at.prefix().toString()), to);
       
  1503         queueToken(G_EQ, to);
       
  1504         queueToken(Token(STRING_LITERAL, at.namespaceUri().toString()), to);
       
  1505 
       
  1506         if(isDeclaration)
       
  1507         {
       
  1508             queueToken(INTERNAL, to);
       
  1509             queueToken(SEMI_COLON, to);
       
  1510         }
       
  1511         else
       
  1512         {
       
  1513             queueToken(CURLY_LBRACE, to);
       
  1514             queueOnExit->push(CURLY_RBRACE);
       
  1515         }
       
  1516     }
       
  1517 }
       
  1518 
       
  1519 bool XSLTTokenizer::insideSequenceConstructor(TokenSource::Queue *const to,
       
  1520                                               const bool initialAdvance,
       
  1521                                               const bool queueEmptyOnEmpty)
       
  1522 {
       
  1523     QStack<Token> onExitTokens;
       
  1524     return insideSequenceConstructor(to, onExitTokens, initialAdvance, queueEmptyOnEmpty);
       
  1525 }
       
  1526 
       
  1527 bool XSLTTokenizer::insideSequenceConstructor(TokenSource::Queue *const to,
       
  1528                                               QStack<Token> &onExitTokens,
       
  1529                                               const bool initialAdvance,
       
  1530                                               const bool queueEmptyOnEmpty)
       
  1531 {
       
  1532     bool effectiveInitialAdvance = initialAdvance;
       
  1533     bool hasWrittenExpression = false;
       
  1534 
       
  1535     /* Buffer which all text nodes, that might be split up by comments,
       
  1536      * processing instructions and CDATA sections, are appended to. */
       
  1537     QString characters;
       
  1538 
       
  1539     while(!atEnd())
       
  1540     {
       
  1541         if(effectiveInitialAdvance)
       
  1542             readNext();
       
  1543         else
       
  1544             effectiveInitialAdvance = true;
       
  1545 
       
  1546         switch(tokenType())
       
  1547         {
       
  1548             case QXmlStreamReader::StartElement:
       
  1549             {
       
  1550                 queueTextConstructor(characters, hasWrittenExpression, to);
       
  1551                 handleXMLBase(to, &onExitTokens);
       
  1552 
       
  1553                 pushState(InsideSequenceConstructor);
       
  1554 
       
  1555                 commencingExpression(hasWrittenExpression, to);
       
  1556 
       
  1557                 if(isXSLT())
       
  1558                 {
       
  1559                     handleXSLTVersion(&m_tokenSource, &onExitTokens, true);
       
  1560                     handleStandardAttributes(true);
       
  1561                     validateElement();
       
  1562 
       
  1563                     queueNamespaceDeclarations(to, &onExitTokens);
       
  1564 
       
  1565                     switch(currentElementName())
       
  1566                     {
       
  1567                         case If:
       
  1568                         {
       
  1569                             queueToken(IF, to);
       
  1570                             queueToken(LPAREN, to);
       
  1571 
       
  1572                             queueExpression(readAttribute(QLatin1String("test")), to);
       
  1573                             queueToken(RPAREN, to);
       
  1574                             queueToken(THEN, to);
       
  1575 
       
  1576                             queueToken(LPAREN, to);
       
  1577                             pushState(InsideSequenceConstructor);
       
  1578                             insideSequenceConstructor(to);
       
  1579 
       
  1580                             break;
       
  1581                         }
       
  1582                         case Choose:
       
  1583                         {
       
  1584                             insideChoose(to);
       
  1585                             break;
       
  1586                         }
       
  1587                         case ValueOf:
       
  1588                         {
       
  1589                             /* We generate a computed text node constructor. */
       
  1590                             queueToken(TEXT, to);
       
  1591                             queueToken(CURLY_LBRACE, to);
       
  1592 
       
  1593                             queueSimpleContentConstructor(ReportContext::XTSE0870, true, to,
       
  1594                                                           !hasAttribute(QLatin1String("separator")) && m_processingMode.top() == BackwardsCompatible);
       
  1595                             queueToken(CURLY_RBRACE, to);
       
  1596                             break;
       
  1597                         }
       
  1598                         case Sequence:
       
  1599                         {
       
  1600                             queueExpression(readAttribute(QLatin1String("select")), to);
       
  1601                             parseFallbacksOnly();
       
  1602                             break;
       
  1603                         }
       
  1604                         case Text:
       
  1605                         {
       
  1606                             queueToken(TEXT, to);
       
  1607                             queueToken(CURLY_LBRACE, to);
       
  1608 
       
  1609                             queueToken(Token(STRING_LITERAL, readElementText()), to);
       
  1610                             queueToken(CURLY_RBRACE, to);
       
  1611                             break;
       
  1612                         }
       
  1613                         case Variable:
       
  1614                         {
       
  1615                             queueVariableDeclaration(VariableInstruction, to);
       
  1616 
       
  1617                             /* We wrap the children in parantheses since we may
       
  1618                              * queue several expressions using the comma operator,
       
  1619                              * and in that case the let-binding is only in-scope
       
  1620                              * for the first expression. */
       
  1621                             queueToken(LPAREN, to);
       
  1622 
       
  1623                             /* We don't want a comma outputted, we're expecting an
       
  1624                              * expression now. */
       
  1625                             hasWrittenExpression = false;
       
  1626 
       
  1627                             onExitTokens.push(RPAREN);
       
  1628 
       
  1629                             break;
       
  1630                         }
       
  1631                         case CallTemplate:
       
  1632                         {
       
  1633                             queueToken(CALL_TEMPLATE, to);
       
  1634                             queueToken(Token(QNAME, readAttribute(QLatin1String("name"))), to);
       
  1635                             queueToken(LPAREN, to);
       
  1636                             queueWithParams(CallTemplate, to);
       
  1637                             queueToken(RPAREN, to);
       
  1638                             break;
       
  1639                         }
       
  1640                         case ForEach:
       
  1641                         {
       
  1642                             queueExpression(readAttribute(QLatin1String("select")), to);
       
  1643                             queueToken(MAP, to);
       
  1644                             pushState(InsideSequenceConstructor);
       
  1645 
       
  1646                             TokenSource::Queue sorts;
       
  1647                             queueSorting(false, &sorts);
       
  1648 
       
  1649 
       
  1650                             if(sorts.isEmpty())
       
  1651                             {
       
  1652                                 startStorageOfCurrent(to);
       
  1653                                 insideSequenceConstructor(to, false);
       
  1654                                 endStorageOfCurrent(to);
       
  1655                             }
       
  1656                             else
       
  1657                             {
       
  1658                                 queueToken(SORT, to);
       
  1659                                 *to += sorts;
       
  1660                                 queueToken(RETURN, to);
       
  1661                                 startStorageOfCurrent(to);
       
  1662                                 insideSequenceConstructor(to, false);
       
  1663                                 endStorageOfCurrent(to);
       
  1664                                 queueToken(END_SORT, to);
       
  1665                             }
       
  1666 
       
  1667                             break;
       
  1668                         }
       
  1669                         case XSLTTokenLookup::Comment:
       
  1670                         {
       
  1671                             queueToken(COMMENT, to);
       
  1672                             queueToken(INTERNAL, to);
       
  1673                             queueToken(CURLY_LBRACE, to);
       
  1674                             queueSelectOrSequenceConstructor(ReportContext::XTSE0940, true, to);
       
  1675                             queueToken(CURLY_RBRACE, to);
       
  1676                             break;
       
  1677                         }
       
  1678                         case CopyOf:
       
  1679                         {
       
  1680                             queueExpression(readAttribute(QLatin1String("select")), to);
       
  1681                             // TODO
       
  1682 
       
  1683                             if(readNext() == QXmlStreamReader::EndElement)
       
  1684                                 break;
       
  1685                             else
       
  1686                             {
       
  1687                                 error(QtXmlPatterns::tr("Element %1 cannot have children.").arg(formatKeyword(QLatin1String("copy-of"))),
       
  1688                                       ReportContext::XTSE0010);
       
  1689                             }
       
  1690                             break;
       
  1691                         }
       
  1692                         case AnalyzeString:
       
  1693                         {
       
  1694                             // TODO
       
  1695                             skipSubTree();
       
  1696                             break;
       
  1697                         }
       
  1698                         case ResultDocument:
       
  1699                         {
       
  1700                             // TODO
       
  1701                             pushState(InsideSequenceConstructor);
       
  1702                             insideSequenceConstructor(to);
       
  1703                             break;
       
  1704                         }
       
  1705                         case Copy:
       
  1706                         {
       
  1707                             /* We translate:
       
  1708                              *      <xsl:copy>expr</xsl:copy>
       
  1709                              * into:
       
  1710                              *
       
  1711                              *  let $body := expr
       
  1712                              *  return
       
  1713                              *      if(self::element()) then
       
  1714                              *          element internal {node-name()} {$body}
       
  1715                              *      else if(self::document-node()) then
       
  1716                              *          document internal {$body}
       
  1717                              *      else (: This includes comments, processing-instructions,
       
  1718                              *              attributes, and comments. :)
       
  1719                              *          .
       
  1720                              *
       
  1721                              * TODO node identity is the same as the old node.
       
  1722                              * TODO namespace bindings are lost when elements are constructed
       
  1723                              */
       
  1724 
       
  1725                             /* let $body := expr */
       
  1726                             queueToken(LET, to);
       
  1727                             queueToken(INTERNAL, to);
       
  1728                             queueToken(DOLLAR, to);
       
  1729                             queueToken(Token(NCNAME, QString(QLatin1Char('b'))), to); // TODO we need an internal name
       
  1730                             queueToken(ASSIGN, to);
       
  1731                             queueToken(LPAREN, to);
       
  1732                             pushState(InsideSequenceConstructor);
       
  1733                             /* Don't queue an empty sequence, we want the dot. */
       
  1734                             insideSequenceConstructor(to);
       
  1735                             queueToken(RPAREN, to);
       
  1736                             queueToken(RETURN, to);
       
  1737 
       
  1738                             /* if(self::element()) then */
       
  1739                             queueToken(IF, to);
       
  1740                             queueToken(LPAREN, to);
       
  1741                             queueToken(SELF, to);
       
  1742                             queueToken(COLONCOLON, to);
       
  1743                             queueToken(ELEMENT, to);
       
  1744                             queueToken(LPAREN, to);
       
  1745                             queueToken(RPAREN, to);
       
  1746                             queueToken(RPAREN, to);
       
  1747                             queueToken(THEN, to);
       
  1748 
       
  1749                             /* element internal {node-name()} {$body} */
       
  1750                             queueToken(ELEMENT, to);
       
  1751                             queueToken(INTERNAL, to);
       
  1752                             queueToken(CURLY_LBRACE, to);
       
  1753                             queueToken(Token(NCNAME, QLatin1String("node-name")), to); // TODO what if the default ns changes?
       
  1754                             queueToken(LPAREN, to);
       
  1755                             queueToken(DOT, to);
       
  1756                             queueToken(RPAREN, to);
       
  1757                             queueToken(CURLY_RBRACE, to);
       
  1758                             queueToken(CURLY_LBRACE, to);
       
  1759                             queueToken(DOLLAR, to);
       
  1760                             queueToken(Token(NCNAME, QString(QLatin1Char('b'))), to); // TODO we need an internal name
       
  1761                             queueToken(CURLY_RBRACE, to);
       
  1762 
       
  1763                             /* else if(self::document-node()) then */
       
  1764                             queueToken(ELSE, to);
       
  1765                             queueToken(IF, to);
       
  1766                             queueToken(LPAREN, to);
       
  1767                             queueToken(SELF, to);
       
  1768                             queueToken(COLONCOLON, to);
       
  1769                             queueToken(DOCUMENT_NODE, to);
       
  1770                             queueToken(LPAREN, to);
       
  1771                             queueToken(RPAREN, to);
       
  1772                             queueToken(RPAREN, to);
       
  1773                             queueToken(THEN, to);
       
  1774 
       
  1775                             /* document internal {$body} */
       
  1776                             queueToken(DOCUMENT, to);
       
  1777                             queueToken(INTERNAL, to);
       
  1778                             queueToken(CURLY_LBRACE, to);
       
  1779                             queueToken(DOLLAR, to);
       
  1780                             queueToken(Token(NCNAME, QString(QLatin1Char('b'))), to); // TODO we need an internal name
       
  1781                             queueToken(CURLY_RBRACE, to);
       
  1782 
       
  1783                             /* else . */
       
  1784                             queueToken(ELSE, to);
       
  1785                             queueToken(DOT, to);
       
  1786 
       
  1787                             break;
       
  1788                         }
       
  1789                         case XSLTTokenLookup::ProcessingInstruction:
       
  1790                         {
       
  1791                             queueToken(PROCESSING_INSTRUCTION, to);
       
  1792                             queueToken(CURLY_LBRACE, to);
       
  1793                             queueAVT(readAttribute(QLatin1String("name")), to);
       
  1794                             queueToken(CURLY_RBRACE, to);
       
  1795                             queueToken(CURLY_LBRACE, to);
       
  1796                             queueSelectOrSequenceConstructor(ReportContext::XTSE0880, true, to);
       
  1797                             queueToken(CURLY_RBRACE, to);
       
  1798                             break;
       
  1799                         }
       
  1800                         case Document:
       
  1801                         {
       
  1802                             handleValidationAttributes(false);
       
  1803 
       
  1804                             // TODO base-URI
       
  1805                             queueToken(DOCUMENT, to);
       
  1806                             queueToken(INTERNAL, to);
       
  1807                             queueToken(CURLY_LBRACE, to);
       
  1808                             pushState(InsideSequenceConstructor);
       
  1809                             insideSequenceConstructor(to);
       
  1810                             queueToken(CURLY_RBRACE, to);
       
  1811                             break;
       
  1812                         }
       
  1813                         case Element:
       
  1814                         {
       
  1815                             handleValidationAttributes(false);
       
  1816 
       
  1817                             // TODO base-URI
       
  1818                             queueToken(ELEMENT, to);
       
  1819                             queueToken(INTERNAL, to);
       
  1820 
       
  1821                             /* The name. */
       
  1822                             queueToken(CURLY_LBRACE, to);
       
  1823                             // TODO only strings allowed, not qname values.
       
  1824                             queueAVT(readAttribute(QLatin1String("name")), to);
       
  1825                             queueToken(CURLY_RBRACE, to);
       
  1826 
       
  1827                             /* The sequence constructor. */
       
  1828                             queueToken(CURLY_LBRACE, to);
       
  1829                             pushState(InsideSequenceConstructor);
       
  1830                             insideSequenceConstructor(to);
       
  1831                             queueToken(CURLY_RBRACE, to);
       
  1832                             break;
       
  1833                         }
       
  1834                         case Attribute:
       
  1835                         {
       
  1836                             handleValidationAttributes(false);
       
  1837 
       
  1838                             // TODO base-URI
       
  1839                             queueToken(ATTRIBUTE, to);
       
  1840                             queueToken(INTERNAL, to);
       
  1841 
       
  1842                             /* The name. */
       
  1843                             queueToken(CURLY_LBRACE, to);
       
  1844                             // TODO only strings allowed, not qname values.
       
  1845                             queueAVT(readAttribute(QLatin1String("name")), to);
       
  1846                             queueToken(CURLY_RBRACE, to);
       
  1847 
       
  1848                             /* The sequence constructor. */
       
  1849                             queueToken(CURLY_LBRACE, to);
       
  1850                             queueSimpleContentConstructor(ReportContext::XTSE0840,
       
  1851                                                           true, to);
       
  1852                             queueToken(CURLY_RBRACE, to);
       
  1853                             break;
       
  1854                         }
       
  1855                         case Namespace:
       
  1856                         {
       
  1857                             queueToken(NAMESPACE, to);
       
  1858 
       
  1859                             /* The name. */
       
  1860                             queueToken(CURLY_LBRACE, to);
       
  1861                             queueAVT(readAttribute(QLatin1String("name")), to);
       
  1862                             queueToken(CURLY_RBRACE, to);
       
  1863 
       
  1864                             /* The sequence constructor. */
       
  1865                             queueToken(CURLY_LBRACE, to);
       
  1866                             queueSelectOrSequenceConstructor(ReportContext::XTSE0910,
       
  1867                                                              false, to);
       
  1868                             queueToken(CURLY_RBRACE, to);
       
  1869                             break;
       
  1870                         }
       
  1871                         case PerformSort:
       
  1872                         {
       
  1873                             /* For:
       
  1874                              * <xsl:perform-sort select="$in">
       
  1875                              *      <xsl:sort select="@key"/>
       
  1876                              * </xsl:perform-sort>
       
  1877                              *
       
  1878                              * we generate:
       
  1879                              *
       
  1880                              * $in map sort order by @key
       
  1881                              *         return .
       
  1882                              *         end_sort
       
  1883                              */
       
  1884 
       
  1885                             /* In XQuery, the sort keys appear after the expression
       
  1886                              * supplying the initial sequence, while in
       
  1887                              * xsl:perform-sort, if a sequence constructor is used,
       
  1888                              * they appear in the opposite order. Hence, we need to
       
  1889                              * reorder it. */
       
  1890 
       
  1891                             /* We store the attributes of xsl:perform-sort, before
       
  1892                              * queueSorting() advances the reader. */
       
  1893                             const QXmlStreamAttributes atts(m_currentAttributes);
       
  1894 
       
  1895                             TokenSource::Queue sorts;
       
  1896                             queueSorting(true, &sorts);
       
  1897                             queueSelectOrSequenceConstructor(ReportContext::XTSE1040,
       
  1898                                                              true,
       
  1899                                                              to,
       
  1900                                                              &atts);
       
  1901                             /* queueSelectOrSequenceConstructor() positions us on EndElement. */
       
  1902                             effectiveInitialAdvance = false;
       
  1903                             queueToken(MAP, to);
       
  1904                             queueToken(SORT, to);
       
  1905                             *to += sorts;
       
  1906                             queueToken(RETURN, to);
       
  1907                             queueToken(DOT, to);
       
  1908                             queueToken(END_SORT, to);
       
  1909 
       
  1910                             break;
       
  1911                         }
       
  1912                         case Message:
       
  1913                         {
       
  1914                             // TODO
       
  1915                             queueEmptySequence(to);
       
  1916                             skipSubTree();
       
  1917                             break;
       
  1918                         }
       
  1919                         case ApplyTemplates:
       
  1920                         {
       
  1921                             if(hasAttribute(QLatin1String("select")))
       
  1922                                 queueExpression(readAttribute(QLatin1String("select")), to);
       
  1923                             else
       
  1924                             {
       
  1925                                 queueToken(CHILD, to);
       
  1926                                 queueToken(COLONCOLON, to);
       
  1927                                 queueToken(NODE, to);
       
  1928                                 queueToken(LPAREN, to);
       
  1929                                 queueToken(RPAREN, to);
       
  1930                             }
       
  1931 
       
  1932                             bool hasMode = hasAttribute(QLatin1String("mode"));
       
  1933                             QString mode;
       
  1934 
       
  1935                             if(hasMode)
       
  1936                                 mode = readAttribute(QLatin1String("mode")).trimmed();
       
  1937 
       
  1938                             queueToken(FOR_APPLY_TEMPLATE, to);
       
  1939 
       
  1940                             TokenSource::Queue sorts;
       
  1941                             queueSorting(false, &sorts, true);
       
  1942 
       
  1943                             if(!sorts.isEmpty())
       
  1944                             {
       
  1945                                 queueToken(SORT, to);
       
  1946                                 *to += sorts;
       
  1947                                 queueToken(RETURN, to);
       
  1948                             }
       
  1949 
       
  1950                             queueToken(APPLY_TEMPLATE, to);
       
  1951 
       
  1952                             if(hasMode)
       
  1953                             {
       
  1954                                 queueToken(MODE, to);
       
  1955                                 queueToken(Token(mode.startsWith(QLatin1Char('#')) ? NCNAME : QNAME, mode), to);
       
  1956                             }
       
  1957 
       
  1958                             queueToken(LPAREN, to);
       
  1959                             queueWithParams(ApplyTemplates, to, false);
       
  1960                             queueToken(RPAREN, to);
       
  1961 
       
  1962                             if(!sorts.isEmpty())
       
  1963                                 queueToken(END_SORT, to);
       
  1964 
       
  1965                             break;
       
  1966                         }
       
  1967                         default:
       
  1968                             unexpectedContent();
       
  1969                     }
       
  1970                     continue;
       
  1971                 }
       
  1972                 else
       
  1973                 {
       
  1974                     handleXSLTVersion(&m_tokenSource, &onExitTokens, true);
       
  1975                     handleStandardAttributes(false);
       
  1976                     handleValidationAttributes(false);
       
  1977 
       
  1978                     /* We're generating an element constructor. */
       
  1979                     queueNamespaceDeclarations(to, &onExitTokens); // TODO same in the isXSLT() branch
       
  1980                     queueToken(ELEMENT, to);
       
  1981                     queueToken(INTERNAL, to);
       
  1982                     queueToken(Token(QNAME, qualifiedName().toString()), to);
       
  1983                     queueToken(CURLY_LBRACE, to);
       
  1984                     const int len = m_currentAttributes.count();
       
  1985 
       
  1986                     for(int i = 0; i < len; ++i)
       
  1987                     {
       
  1988                         const QXmlStreamAttribute &at = m_currentAttributes.at(i);
       
  1989 
       
  1990                         /* We don't want to generate constructors for XSL-T attributes. */
       
  1991                         if(at.namespaceUri() == CommonNamespaces::XSLT)
       
  1992                             continue;
       
  1993 
       
  1994                         queueToken(ATTRIBUTE, to);
       
  1995                         queueToken(INTERNAL, to);
       
  1996 
       
  1997                         queueToken(Token(at.prefix().isEmpty() ? NCNAME : QNAME, at.qualifiedName().toString()), to);
       
  1998                         queueToken(CURLY_LBRACE, to);
       
  1999                         queueAVT(at.value().toString(), to);
       
  2000                         queueToken(CURLY_RBRACE, to);
       
  2001                         queueToken(COMMA, to);
       
  2002                     }
       
  2003 
       
  2004                     pushState(InsideSequenceConstructor);
       
  2005                     insideSequenceConstructor(to);
       
  2006                     Q_ASSERT(tokenType() == QXmlStreamReader::EndElement || hasError());
       
  2007                     continue;
       
  2008                 }
       
  2009 
       
  2010                 unexpectedContent();
       
  2011                 break;
       
  2012             }
       
  2013             case QXmlStreamReader::EndElement:
       
  2014             {
       
  2015                 queueTextConstructor(characters, hasWrittenExpression, to);
       
  2016                 leaveState();
       
  2017 
       
  2018                 if(!hasWrittenExpression && queueEmptyOnEmpty)
       
  2019                     queueEmptySequence(to);
       
  2020 
       
  2021                 queueOnExit(onExitTokens, to);
       
  2022 
       
  2023                 if(isXSLT())
       
  2024                 {
       
  2025                     Q_ASSERT(!isElement(Sequence));
       
  2026 
       
  2027                     switch(currentElementName())
       
  2028                     {
       
  2029                         /* Fallthrough all these. */
       
  2030                         case When:
       
  2031                         case Choose:
       
  2032                         case ForEach:
       
  2033                         case Otherwise:
       
  2034                         case PerformSort:
       
  2035                         case Message:
       
  2036                         case ResultDocument:
       
  2037                         case Copy:
       
  2038                         case CallTemplate:
       
  2039                         case Text:
       
  2040                         case ValueOf:
       
  2041                         {
       
  2042                             hasWrittenExpression = true;
       
  2043                             break;
       
  2044                         }
       
  2045                         case If:
       
  2046                         {
       
  2047                             queueToken(RPAREN, to);
       
  2048                             queueToken(ELSE, to);
       
  2049                             queueEmptySequence(to);
       
  2050                             break;
       
  2051                         }
       
  2052                         case Function:
       
  2053                         {
       
  2054                             queueToken(CURLY_RBRACE, to);
       
  2055                             queueToken(SEMI_COLON, to);
       
  2056                             break;
       
  2057                         }
       
  2058                         case Template:
       
  2059                         {
       
  2060                             endStorageOfCurrent(&m_tokenSource);
       
  2061                             /* TODO, fallthrough to Function. */
       
  2062                             queueToken(CURLY_RBRACE, to);
       
  2063                             queueToken(SEMI_COLON, to);
       
  2064                             break;
       
  2065                         }
       
  2066                         default:
       
  2067                             ;
       
  2068                     }
       
  2069                 }
       
  2070                 else
       
  2071                 {
       
  2072                     /* We're closing a direct element constructor. */
       
  2073                     hasWrittenExpression = true;
       
  2074                     queueToken(CURLY_RBRACE, to);
       
  2075                 }
       
  2076 
       
  2077                 return hasWrittenExpression;
       
  2078             }
       
  2079             case QXmlStreamReader::ProcessingInstruction:
       
  2080             /* Fallthrough. */
       
  2081             case QXmlStreamReader::Comment:
       
  2082                 /* We do nothing, we just ignore them. */
       
  2083                 continue;
       
  2084             case QXmlStreamReader::Characters:
       
  2085             {
       
  2086                 if(whitespaceToSkip())
       
  2087                     continue;
       
  2088                 else
       
  2089                 {
       
  2090                     characters += text().toString();
       
  2091                     continue;
       
  2092                 }
       
  2093             }
       
  2094             default:
       
  2095                 ;
       
  2096         }
       
  2097     }
       
  2098 
       
  2099     leaveState();
       
  2100     return hasWrittenExpression;
       
  2101 }
       
  2102 
       
  2103 bool XSLTTokenizer::isStylesheetElement() const
       
  2104 {
       
  2105     Q_ASSERT(isXSLT());
       
  2106     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement ||
       
  2107              tokenType() == QXmlStreamReader::EndElement);
       
  2108 
       
  2109     const NodeName name = currentElementName();
       
  2110     return name == Stylesheet || name == Transform;
       
  2111 }
       
  2112 
       
  2113 void XSLTTokenizer::skipBodyOfParam(const ReportContext::ErrorCode code)
       
  2114 {
       
  2115     Q_ASSERT(isXSLT());
       
  2116     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  2117     const NodeName name(currentElementName());
       
  2118 
       
  2119     if(skipSubTree())
       
  2120     {
       
  2121         error(QtXmlPatterns::tr("Element %1 cannot have a sequence constructor.")
       
  2122                                           .arg(formatKeyword(toString(name))),
       
  2123               code);
       
  2124     }
       
  2125 }
       
  2126 
       
  2127 void XSLTTokenizer::queueWithParams(const XSLTTokenLookup::NodeName parentName,
       
  2128                                     TokenSource::Queue *const to,
       
  2129                                     const bool initialAdvance)
       
  2130 {
       
  2131     Q_ASSERT(parentName == ApplyTemplates || parentName == CallTemplate);
       
  2132 
       
  2133     bool effectiveInitialAdvance = initialAdvance;
       
  2134     bool hasQueuedParam = false;
       
  2135 
       
  2136     while(!atEnd())
       
  2137     {
       
  2138         if(effectiveInitialAdvance)
       
  2139             readNext();
       
  2140         else
       
  2141             effectiveInitialAdvance = true;
       
  2142 
       
  2143         switch(tokenType())
       
  2144         {
       
  2145             case QXmlStreamReader::StartElement:
       
  2146             {
       
  2147                 if(hasQueuedParam)
       
  2148                     queueToken(COMMA, to);
       
  2149 
       
  2150                 if(isXSLT() && isElement(WithParam))
       
  2151                 {
       
  2152                     if(hasAttribute(QLatin1String("tunnel")) && attributeYesNo(QLatin1String("tunnel")))
       
  2153                         queueToken(TUNNEL, to);
       
  2154 
       
  2155                     queueVariableDeclaration(WithParamVariable, to);
       
  2156                     hasQueuedParam = true;
       
  2157                     continue;
       
  2158                 }
       
  2159                 else
       
  2160                     unexpectedContent();
       
  2161             }
       
  2162             case QXmlStreamReader::EndElement:
       
  2163             {
       
  2164                 if(isElement(parentName))
       
  2165                     return;
       
  2166                 else
       
  2167                     continue;
       
  2168             }
       
  2169             case QXmlStreamReader::ProcessingInstruction:
       
  2170             /* Fallthrough. */
       
  2171             case QXmlStreamReader::Comment:
       
  2172                 continue;
       
  2173             case QXmlStreamReader::Characters:
       
  2174                 if(whitespaceToSkip())
       
  2175                     continue;
       
  2176                 else
       
  2177                     return;
       
  2178             default:
       
  2179                 unexpectedContent();
       
  2180         }
       
  2181     }
       
  2182     unexpectedContent();
       
  2183 }
       
  2184 
       
  2185 void XSLTTokenizer::queueParams(const XSLTTokenLookup::NodeName parentName,
       
  2186                                 TokenSource::Queue *const to)
       
  2187 {
       
  2188     bool hasQueuedParam = false;
       
  2189 
       
  2190     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  2191 
       
  2192     while(!atEnd())
       
  2193     {
       
  2194         switch(readNext())
       
  2195         {
       
  2196             case QXmlStreamReader::StartElement:
       
  2197             {
       
  2198                 if(isXSLT() && isElement(Param))
       
  2199                 {
       
  2200                     if(hasQueuedParam)
       
  2201                         queueToken(COMMA, to);
       
  2202 
       
  2203                     validateElement();
       
  2204 
       
  2205                     if(parentName == Function && m_currentAttributes.hasAttribute(QLatin1String("select")))
       
  2206                     {
       
  2207                         error(QtXmlPatterns::tr("The attribute %1 cannot appear on %2, when it is a child of %3.")
       
  2208                                          .arg(formatKeyword(QLatin1String("select")),
       
  2209                                               formatKeyword(QLatin1String("param")),
       
  2210                                               formatKeyword(QLatin1String("function"))),
       
  2211                               ReportContext::XTSE0760);
       
  2212                     }
       
  2213 
       
  2214                     if(parentName == Function && m_currentAttributes.hasAttribute(QLatin1String("required")))
       
  2215                     {
       
  2216                         error(QtXmlPatterns::tr("The attribute %1 cannot appear on %2, when it is a child of %3.")
       
  2217                                          .arg(formatKeyword(QLatin1String("required")),
       
  2218                                               formatKeyword(QLatin1String("param")),
       
  2219                                               formatKeyword(QLatin1String("function"))),
       
  2220                               ReportContext::XTSE0010);
       
  2221                     }
       
  2222 
       
  2223                     const bool hasTunnel = m_currentAttributes.hasAttribute(QLatin1String("tunnel"));
       
  2224                     const bool isTunnel = hasTunnel ? attributeYesNo(QLatin1String("tunnel")) : false;
       
  2225 
       
  2226                     if(isTunnel)
       
  2227                     {
       
  2228                         if(parentName == Function)
       
  2229                         {
       
  2230                             /* See W3C public report 5650: http://www.w3.org/Bugs/Public/show_bug.cgi?id=5650 */
       
  2231                             error(QtXmlPatterns::tr("A parameter in a function cannot be declared to be a tunnel."),
       
  2232                                   ReportContext::XTSE0010);
       
  2233                         }
       
  2234                         else
       
  2235                             queueToken(TUNNEL, to);
       
  2236                     }
       
  2237 
       
  2238                     hasQueuedParam = true;
       
  2239                     queueVariableDeclaration(parentName == Function ? FunctionParameter : TemplateParameter, to);
       
  2240                     continue;
       
  2241                 }
       
  2242                 else
       
  2243                     return;
       
  2244             }
       
  2245             case QXmlStreamReader::Characters:
       
  2246             {
       
  2247                 if(whitespaceToSkip())
       
  2248                     continue;
       
  2249                 /* Fallthrough. */
       
  2250             }
       
  2251             case QXmlStreamReader::EndElement:
       
  2252                 return;
       
  2253             default:
       
  2254                 ;
       
  2255         }
       
  2256     }
       
  2257 }
       
  2258 
       
  2259 bool XSLTTokenizer::skipSubTree(const bool exitOnContent)
       
  2260 {
       
  2261     bool hasContent = false;
       
  2262     int depth = 0;
       
  2263 
       
  2264     while(!atEnd())
       
  2265     {
       
  2266         switch(readNext())
       
  2267         {
       
  2268             case QXmlStreamReader::Characters:
       
  2269             {
       
  2270                 if(whitespaceToSkip())
       
  2271                     continue;
       
  2272                 else
       
  2273                 {
       
  2274                     hasContent = true;
       
  2275                     if(exitOnContent)
       
  2276                         return true;
       
  2277 
       
  2278                     break;
       
  2279                 }
       
  2280             }
       
  2281             case QXmlStreamReader::StartElement:
       
  2282             {
       
  2283                 hasContent = true;
       
  2284                 if(exitOnContent)
       
  2285                     return true;
       
  2286 
       
  2287                 ++depth;
       
  2288                 break;
       
  2289             }
       
  2290             case QXmlStreamReader::EndElement:
       
  2291             {
       
  2292                 --depth;
       
  2293                 break;
       
  2294             }
       
  2295             default:
       
  2296                 continue;
       
  2297         }
       
  2298 
       
  2299         if(depth == -1)
       
  2300             return hasContent;
       
  2301     }
       
  2302 
       
  2303     checkForParseError();
       
  2304     return hasContent;
       
  2305 }
       
  2306 
       
  2307 void XSLTTokenizer::parseFallbacksOnly()
       
  2308 {
       
  2309     Q_ASSERT(isXSLT());
       
  2310     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  2311 
       
  2312     skipSubTree();
       
  2313     Q_ASSERT(tokenType() == QXmlStreamReader::EndElement);
       
  2314 }
       
  2315 
       
  2316 void XSLTTokenizer::insideAttributeSet()
       
  2317 {
       
  2318     while(!atEnd())
       
  2319     {
       
  2320         switch(readNext())
       
  2321         {
       
  2322             case QXmlStreamReader::StartElement:
       
  2323             {
       
  2324                 if(isXSLT() && isElement(AttributeSet))
       
  2325                 {
       
  2326                     // TODO
       
  2327                     skipSubTree();
       
  2328                 }
       
  2329                 else
       
  2330                     unexpectedContent();
       
  2331             }
       
  2332             case QXmlStreamReader::EndElement:
       
  2333                 return;
       
  2334             case QXmlStreamReader::ProcessingInstruction:
       
  2335             /* Fallthrough. */
       
  2336             case QXmlStreamReader::Comment:
       
  2337                 continue;
       
  2338             case QXmlStreamReader::Characters:
       
  2339                 if(whitespaceToSkip())
       
  2340                     continue;
       
  2341                 /* Fallthrough. */
       
  2342             default:
       
  2343                 unexpectedContent();
       
  2344         }
       
  2345     }
       
  2346     unexpectedContent();
       
  2347 }
       
  2348 
       
  2349 void XSLTTokenizer::insideStylesheetModule()
       
  2350 {
       
  2351     while(!atEnd())
       
  2352     {
       
  2353         switch(readNext())
       
  2354         {
       
  2355             case QXmlStreamReader::StartElement:
       
  2356             {
       
  2357                 if(isXSLT())
       
  2358                 {
       
  2359                     handleStandardAttributes(true);
       
  2360                     handleXSLTVersion(0, 0, true, 0, false);
       
  2361                     validateElement();
       
  2362 
       
  2363                     /* Handle the various declarations. */
       
  2364                     switch(currentElementName())
       
  2365                     {
       
  2366                         case Template:
       
  2367                             insideTemplate();
       
  2368                             break;
       
  2369                         case Function:
       
  2370                             insideFunction();
       
  2371                             break;
       
  2372                         case Variable:
       
  2373                             queueVariableDeclaration(VariableDeclaration, &m_tokenSource);
       
  2374                             break;
       
  2375                         case Param:
       
  2376                             queueVariableDeclaration(GlobalParameter, &m_tokenSource);
       
  2377                             break;
       
  2378                         case ImportSchema:
       
  2379                         {
       
  2380                             error(QtXmlPatterns::tr("This processor is not Schema-aware and "
       
  2381                                                                "therefore %1 cannot be used.").arg(formatKeyword(toString(ImportSchema))),
       
  2382                                   ReportContext::XTSE1660);
       
  2383                             break;
       
  2384                         }
       
  2385                         case Output:
       
  2386                         {
       
  2387                             // TODO
       
  2388                             skipSubTree();
       
  2389                             break;
       
  2390                         }
       
  2391                         case StripSpace:
       
  2392                         /* Fallthrough. */
       
  2393                         case PreserveSpace:
       
  2394                         {
       
  2395                             // TODO @elements
       
  2396                             skipSubTree(true);
       
  2397                             readNext();
       
  2398 
       
  2399                             if(!isEndElement())
       
  2400                                 unexpectedContent();
       
  2401                             break;
       
  2402                         }
       
  2403                         case Include:
       
  2404                         {
       
  2405                             // TODO
       
  2406                             if(skipSubTree(true))
       
  2407                                 unexpectedContent();
       
  2408                             break;
       
  2409                         }
       
  2410                         case Import:
       
  2411                         {
       
  2412                             // TODO
       
  2413                             if(skipSubTree(true))
       
  2414                                 unexpectedContent();
       
  2415                             break;
       
  2416                         }
       
  2417                         case Key:
       
  2418                         {
       
  2419                             // TODO
       
  2420                             skipSubTree();
       
  2421                             break;
       
  2422                         }
       
  2423                         case AttributeSet:
       
  2424                             insideAttributeSet();
       
  2425                             break;
       
  2426                         default:
       
  2427                             if(m_processingMode.top() != ForwardCompatible)
       
  2428                                 unexpectedContent();
       
  2429                     }
       
  2430                 }
       
  2431                 else
       
  2432                 {
       
  2433                     /* We have a user-defined data element. See section 3.6.2. */
       
  2434 
       
  2435                     if(namespaceUri().isEmpty())
       
  2436                     {
       
  2437                         error(QtXmlPatterns::tr("Top level stylesheet elements must be "
       
  2438                                                            "in a non-null namespace, which %1 isn't.").arg(formatKeyword(name())),
       
  2439                               ReportContext::XTSE0130);
       
  2440                     }
       
  2441                     else
       
  2442                         skipSubTree();
       
  2443                 }
       
  2444                 break;
       
  2445             }
       
  2446             case QXmlStreamReader::Characters:
       
  2447             {
       
  2448                 /* Regardless of xml:space, we skip whitespace, see step 4 in
       
  2449                  * 4.2 Stripping Whitespace from the Stylesheet. */
       
  2450                 if(isWhitespace())
       
  2451                     continue;
       
  2452 
       
  2453                 unexpectedContent(ReportContext::XTSE0120);
       
  2454                 break;
       
  2455             }
       
  2456             case QXmlStreamReader::EndElement:
       
  2457             {
       
  2458                 if(isXSLT())
       
  2459                     leaveState();
       
  2460 
       
  2461                 break;
       
  2462             }
       
  2463             default:
       
  2464                 ;
       
  2465         }
       
  2466     }
       
  2467     checkForParseError();
       
  2468 }
       
  2469 
       
  2470 bool XSLTTokenizer::readToggleAttribute(const QString &localName,
       
  2471                                         const QString &isTrue,
       
  2472                                         const QString &isFalse,
       
  2473                                         const QXmlStreamAttributes *const attsP) const
       
  2474 {
       
  2475     const QXmlStreamAttributes atts(attsP ? *attsP : m_currentAttributes);
       
  2476     Q_ASSERT(atts.hasAttribute(localName));
       
  2477     const QString value(atts.value(localName).toString());
       
  2478 
       
  2479     if(value == isTrue)
       
  2480         return true;
       
  2481     else if(value == isFalse)
       
  2482         return false;
       
  2483     else
       
  2484     {
       
  2485         error(QtXmlPatterns::tr("The value for attribute %1 on element %2 must either "
       
  2486                                            "be %3 or %4, not %5.").arg(formatKeyword(localName),
       
  2487                                                                        formatKeyword(name()),
       
  2488                                                                        formatData(isTrue),
       
  2489                                                                        formatData(isFalse),
       
  2490                                                                        formatData(value)),
       
  2491               ReportContext::XTSE0020);
       
  2492         /* Silences a compiler warning. */
       
  2493         return false;
       
  2494     }
       
  2495 }
       
  2496 
       
  2497 int XSLTTokenizer::readAlternativeAttribute(const QHash<QString, int> &alternatives,
       
  2498                                             const QXmlStreamAttribute &attr) const
       
  2499 {
       
  2500     const QString value(attr.value().toString().trimmed());
       
  2501 
       
  2502     if(alternatives.contains(value))
       
  2503         return alternatives[value];
       
  2504 
       
  2505     error(QtXmlPatterns::tr("Attribute %1 cannot have the value %2.")
       
  2506                                        .arg(formatKeyword(attr.name().toString()),
       
  2507                                             formatData(attr.value().toString())),
       
  2508           ReportContext::XTSE0020);
       
  2509     return 0; /* Silence compiler warning. */
       
  2510 }
       
  2511 
       
  2512 bool XSLTTokenizer::attributeYesNo(const QString &localName) const
       
  2513 {
       
  2514     return readToggleAttribute(localName, QLatin1String("yes"), QLatin1String("no"));
       
  2515 }
       
  2516 
       
  2517 void XSLTTokenizer::queueSorting(const bool oneSortRequired,
       
  2518                                  TokenSource::Queue *const to,
       
  2519                                  const bool speciallyTreatWhitespace)
       
  2520 {
       
  2521     Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
       
  2522 
       
  2523     const NodeName elementName(currentElementName());
       
  2524     bool hasQueuedOneSort = false;
       
  2525 
       
  2526     while(!atEnd())
       
  2527     {
       
  2528         switch(readNext())
       
  2529         {
       
  2530             case QXmlStreamReader::EndElement:
       
  2531             {
       
  2532                 /* Let's say we have no sequence constructor, but only
       
  2533                  * ignorable space. In that case we will actually loop
       
  2534                  * infinitely if we don't have this check. */
       
  2535                 if(isXSLT())
       
  2536                 {
       
  2537                     switch(currentElementName())
       
  2538                     {
       
  2539                         case PerformSort:
       
  2540                         /* Fallthrough. */
       
  2541                         case ForEach:
       
  2542                         /* Fallthrough. */
       
  2543                         case ApplyTemplates:
       
  2544                             return;
       
  2545                         default:
       
  2546                             ;
       
  2547                     }
       
  2548                 }
       
  2549                 continue;
       
  2550             }
       
  2551             case QXmlStreamReader::StartElement:
       
  2552             {
       
  2553                 if(isXSLT() && isElement(Sort))
       
  2554                 {
       
  2555                     if(hasQueuedOneSort)
       
  2556                         queueToken(COMMA, to);
       
  2557 
       
  2558                     /* sorts are by default stable. */
       
  2559                     if(hasAttribute(QLatin1String("stable")))
       
  2560                     {
       
  2561                         if(hasQueuedOneSort)
       
  2562                         {
       
  2563                             error(QtXmlPatterns::tr("The attribute %1 can only appear on "
       
  2564                                                                "the first %2 element.").arg(formatKeyword(QLatin1String("stable")),
       
  2565                                                                                             formatKeyword(QLatin1String("sort"))),
       
  2566                                   ReportContext::XTSE0020);
       
  2567                         }
       
  2568 
       
  2569                         if(attributeYesNo(QLatin1String("stable")))
       
  2570                             queueToken(STABLE, to);
       
  2571                     }
       
  2572 
       
  2573                     if(!hasQueuedOneSort)
       
  2574                     {
       
  2575                         queueToken(ORDER, to);
       
  2576                         queueToken(BY, to);
       
  2577                     }
       
  2578 
       
  2579                     /* We store a copy such that we can use them after
       
  2580                      * queueSelectOrSequenceConstructor() advances the reader. */
       
  2581                     const QXmlStreamAttributes atts(m_currentAttributes);
       
  2582 
       
  2583                     const int before = to->count();
       
  2584 
       
  2585                     // TODO This doesn't work as is. @data-type can be an AVT.
       
  2586                     if(atts.hasAttribute(QLatin1String("data-type")))
       
  2587                     {
       
  2588                         if(readToggleAttribute(QLatin1String("data-type"),
       
  2589                                                QLatin1String("text"),
       
  2590                                                QLatin1String("number"),
       
  2591                                                &atts))
       
  2592                             queueToken(Token(NCNAME, QLatin1String("string")), to);
       
  2593                         else
       
  2594                             queueToken(Token(NCNAME, QLatin1String("number")), to);
       
  2595                     }
       
  2596                     /* We queue these parantheses for the sake of the function
       
  2597                      * call for attribute data-type. In the case we don't have
       
  2598                      * such an attribute, the parantheses are just redundant. */
       
  2599                     queueToken(LPAREN, to);
       
  2600                     queueSelectOrSequenceConstructor(ReportContext::XTSE1015,
       
  2601                                                      true,
       
  2602                                                      to,
       
  2603                                                      0,
       
  2604                                                      false);
       
  2605                     /* If neither a select attribute or a sequence constructor is supplied,
       
  2606                      * we're supposed to use the context item. */
       
  2607                     queueToken(RPAREN, to);
       
  2608                     if(before == to->count())
       
  2609                         queueToken(DOT, to);
       
  2610 
       
  2611                     // TODO case-order
       
  2612                     // TODO lang
       
  2613 
       
  2614                     // TODO This doesn't work as is. @order can be an AVT, and so can case-order and lang.
       
  2615                     if(atts.hasAttribute(QLatin1String("order")) && readToggleAttribute(QLatin1String("order"),
       
  2616                                                                                        QLatin1String("descending"),
       
  2617                                                                                        QLatin1String("ascending"),
       
  2618                                                                                        &atts))
       
  2619                     {
       
  2620                         queueToken(DESCENDING, to);
       
  2621                     }
       
  2622                     else
       
  2623                     {
       
  2624                         /* This is the default. */
       
  2625                         queueToken(ASCENDING, to);
       
  2626                     }
       
  2627 
       
  2628                     if(atts.hasAttribute(QLatin1String("collation")))
       
  2629                     {
       
  2630                         queueToken(INTERNAL, to);
       
  2631                         queueToken(COLLATION, to);
       
  2632                         queueAVT(atts.value(QLatin1String("collation")).toString(), to);
       
  2633                     }
       
  2634 
       
  2635                     hasQueuedOneSort = true;
       
  2636                     continue;
       
  2637                 }
       
  2638                 else
       
  2639                     break;
       
  2640             }
       
  2641             case QXmlStreamReader::Characters:
       
  2642             {
       
  2643                 if(speciallyTreatWhitespace && isWhitespace())
       
  2644                     continue;
       
  2645 
       
  2646                 if(QXmlStreamReader::Characters && whitespaceToSkip())
       
  2647                     continue;
       
  2648 
       
  2649                 /* We have an instruction which is a text node, we're done. */
       
  2650                 break;
       
  2651             }
       
  2652             case QXmlStreamReader::ProcessingInstruction:
       
  2653             /* Fallthrough. */
       
  2654             case QXmlStreamReader::Comment:
       
  2655                 continue;
       
  2656             default:
       
  2657                 unexpectedContent();
       
  2658 
       
  2659         };
       
  2660         if(oneSortRequired && !hasQueuedOneSort)
       
  2661         {
       
  2662             error(QtXmlPatterns::tr("At least one %1 element must appear as child of %2.")
       
  2663                                               .arg(formatKeyword(QLatin1String("sort")), formatKeyword(toString(elementName))),
       
  2664                   ReportContext::XTSE0010);
       
  2665         }
       
  2666         else
       
  2667             return;
       
  2668     }
       
  2669     checkForParseError();
       
  2670 }
       
  2671 
       
  2672 void XSLTTokenizer::insideFunction()
       
  2673 {
       
  2674     queueToken(DECLARE, &m_tokenSource);
       
  2675     queueToken(FUNCTION, &m_tokenSource);
       
  2676     queueToken(INTERNAL, &m_tokenSource);
       
  2677     queueToken(Token(QNAME, readAttribute(QLatin1String("name"))), &m_tokenSource);
       
  2678     queueToken(LPAREN, &m_tokenSource);
       
  2679     const QString expectedType(hasAttribute(QLatin1String("as")) ? readAttribute(QLatin1String("as")): QString());
       
  2680 
       
  2681     if(hasAttribute(QLatin1String("override")))
       
  2682     {
       
  2683         /* We currently have no external functions, so we don't pass it on currently. */
       
  2684         attributeYesNo(QLatin1String("override"));
       
  2685     }
       
  2686 
       
  2687     queueParams(Function, &m_tokenSource);
       
  2688 
       
  2689     queueToken(RPAREN, &m_tokenSource);
       
  2690 
       
  2691     if(!expectedType.isNull())
       
  2692     {
       
  2693         queueToken(AS, &m_tokenSource);
       
  2694         queueSequenceType(expectedType);
       
  2695     }
       
  2696 
       
  2697     QStack<Token> onExitTokens;
       
  2698     handleXMLBase(&m_tokenSource, &onExitTokens, true, &m_currentAttributes);
       
  2699     handleXSLTVersion(&m_tokenSource, &onExitTokens, true);
       
  2700     queueToken(CURLY_LBRACE, &m_tokenSource);
       
  2701 
       
  2702     pushState(InsideSequenceConstructor);
       
  2703     insideSequenceConstructor(&m_tokenSource, onExitTokens, false);
       
  2704     /* We don't queue CURLY_RBRACE, because it's done in
       
  2705      * insideSequenceConstructor(). */
       
  2706 }
       
  2707 
       
  2708 YYLTYPE XSLTTokenizer::currentSourceLocator() const
       
  2709 {
       
  2710     YYLTYPE retval;
       
  2711     retval.first_line = lineNumber();
       
  2712     retval.first_column = columnNumber();
       
  2713     return retval;
       
  2714 }
       
  2715 
       
  2716 QT_END_NAMESPACE
       
  2717