src/xmlpatterns/expr/qexpressionfactory.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 <QBuffer>
       
    43 #include <QByteArray>
       
    44 
       
    45 #include "qcalltemplate_p.h"
       
    46 #include "qcommonsequencetypes_p.h"
       
    47 #include "qdebug_p.h"
       
    48 #include "qexpression_p.h"
       
    49 #include "qgenericstaticcontext_p.h"
       
    50 #include "qoperandsiterator_p.h"
       
    51 #include "qoptimizationpasses_p.h"
       
    52 #include "qparsercontext_p.h"
       
    53 #include "qpath_p.h"
       
    54 #include "qquerytransformparser_p.h"
       
    55 #include "qstaticfocuscontext_p.h"
       
    56 #include "qtokenrevealer_p.h"
       
    57 #include "qxquerytokenizer_p.h"
       
    58 #include "qxslttokenizer_p.h"
       
    59 
       
    60 #include "qexpressionfactory_p.h"
       
    61 
       
    62 QT_BEGIN_NAMESPACE
       
    63 
       
    64 namespace QPatternist {
       
    65 
       
    66 /**
       
    67  * @short The entry point to the parser.
       
    68  *
       
    69  * @param info supplies the information the parser & scanner
       
    70  * needs to create expressions. The created expression, if everything
       
    71  * succeeds, can be retrieved via the object @p info points to.
       
    72  * @returns non-negative if the parser fails.
       
    73  * @see ExpressionFactory::createExpression()
       
    74  */
       
    75 extern int XPathparse(QPatternist::ParserContext *const info);
       
    76 
       
    77 Expression::Ptr ExpressionFactory::createExpression(const QString &expr,
       
    78                                                     const StaticContext::Ptr &context,
       
    79                                                     const QXmlQuery::QueryLanguage lang,
       
    80                                                     const SequenceType::Ptr &requiredType,
       
    81                                                     const QUrl &queryURI,
       
    82                                                     const QXmlName &initialTemplateName)
       
    83 {
       
    84     if(lang == QXmlQuery::XSLT20)
       
    85     {
       
    86         QByteArray query(expr.toUtf8());
       
    87         QBuffer buffer(&query);
       
    88         buffer.open(QIODevice::ReadOnly);
       
    89 
       
    90         return createExpression(&buffer,
       
    91                                 context,
       
    92                                 lang,
       
    93                                 requiredType,
       
    94                                 queryURI,
       
    95                                 initialTemplateName);
       
    96     }
       
    97     else
       
    98     {
       
    99         return createExpression(Tokenizer::Ptr(new XQueryTokenizer(expr, queryURI)),
       
   100                                 context,
       
   101                                 lang,
       
   102                                 requiredType,
       
   103                                 queryURI,
       
   104                                 initialTemplateName);
       
   105     }
       
   106 }
       
   107 
       
   108 Expression::Ptr ExpressionFactory::createExpression(QIODevice *const device,
       
   109                                                     const StaticContext::Ptr &context,
       
   110                                                     const QXmlQuery::QueryLanguage lang,
       
   111                                                     const SequenceType::Ptr &requiredType,
       
   112                                                     const QUrl &queryURI,
       
   113                                                     const QXmlName &initialTemplateName)
       
   114 {
       
   115     Q_ASSERT(device);
       
   116     Q_ASSERT(device->isReadable());
       
   117 
       
   118     Tokenizer::Ptr tokenizer;
       
   119 
       
   120     if(lang == QXmlQuery::XSLT20)
       
   121         tokenizer = Tokenizer::Ptr(new XSLTTokenizer(device, queryURI, context, context->namePool()));
       
   122     else
       
   123         tokenizer = Tokenizer::Ptr(new XQueryTokenizer(QString::fromUtf8(device->readAll()), queryURI));
       
   124 
       
   125     return createExpression(tokenizer, context, lang, requiredType, queryURI, initialTemplateName);
       
   126 }
       
   127 
       
   128 Expression::Ptr ExpressionFactory::createExpression(const Tokenizer::Ptr &tokenizer,
       
   129                                                     const StaticContext::Ptr &context,
       
   130                                                     const QXmlQuery::QueryLanguage lang,
       
   131                                                     const SequenceType::Ptr &requiredType,
       
   132                                                     const QUrl &queryURI,
       
   133                                                     const QXmlName &initialTemplateName)
       
   134 {
       
   135     Q_ASSERT(context);
       
   136     Q_ASSERT(requiredType);
       
   137     Q_ASSERT(queryURI.isValid());
       
   138 
       
   139     Tokenizer::Ptr effectiveTokenizer(tokenizer);
       
   140 #ifdef Patternist_DEBUG
       
   141     effectiveTokenizer = Tokenizer::Ptr(new TokenRevealer(queryURI, tokenizer));
       
   142 #endif
       
   143 
       
   144     OptimizationPasses::Coordinator::init();
       
   145 
       
   146     const ParserContext::Ptr info(new ParserContext(context, lang, effectiveTokenizer.data()));
       
   147     info->initialTemplateName = initialTemplateName;
       
   148 
       
   149     effectiveTokenizer->setParserContext(info);
       
   150 
       
   151     const int bisonRetval = XPathparse(info.data());
       
   152 
       
   153     Q_ASSERT_X(bisonRetval == 0, Q_FUNC_INFO,
       
   154                "We shouldn't be able to get an error, because we throw exceptions.");
       
   155     Q_UNUSED(bisonRetval); /* Needed when not compiled in debug mode, since bisonRetval won't
       
   156                             * be used in the Q_ASSERT_X above. */
       
   157 
       
   158     Expression::Ptr result(info->queryBody);
       
   159 
       
   160     if(!result)
       
   161     {
       
   162         context->error(QtXmlPatterns::tr("A library module cannot be evaluated "
       
   163                                          "directly. It must be imported from a "
       
   164                                          "main module."),
       
   165                        ReportContext::XPST0003,
       
   166                        QSourceLocation(queryURI, 1, 1));
       
   167     }
       
   168 
       
   169     /* Optimization: I think many things are done in the wrong order below. We
       
   170      * probably want everything typechecked before compressing, since we can
       
   171      * have references all over the place(variable references, template
       
   172      * invocations, function callsites). This could even be a source to bugs.
       
   173      */
       
   174 
       
   175     /* Here, we type check user declared functions and global variables. This
       
   176      * means that variables and functions that are not used are type
       
   177      * checked(which they otherwise wouldn't have been), and those which are
       
   178      * used, are type-checked twice, unfortunately. */
       
   179 
       
   180     const bool hasExternalFocus = context->contextItemType();
       
   181 
       
   182     if(lang == QXmlQuery::XSLT20)
       
   183     {
       
   184         /* Bind xsl:call-template instructions to their template bodies.
       
   185          *
       
   186          * We do this before type checking and compressing them, because a
       
   187          * CallTemplate obviously needs its template before being compressed.
       
   188          *
       
   189          * Also, we do this before type checking and compressing user
       
   190          * functions, since they can contain template call sites.
       
   191          */
       
   192         for(int i = 0; i < info->templateCalls.count(); ++i)
       
   193         {
       
   194             CallTemplate *const site = info->templateCalls.at(i)->as<CallTemplate>();
       
   195             const QXmlName targetName(site->name());
       
   196             const Template::Ptr t(info->namedTemplates.value(targetName));
       
   197 
       
   198             if(t)
       
   199                 site->setTemplate(t);
       
   200             else
       
   201             {
       
   202                 context->error(QtXmlPatterns::tr("No template by name %1 exists.").arg(formatKeyword(context->namePool(), targetName)),
       
   203                                ReportContext::XTSE0650,
       
   204                                site);
       
   205             }
       
   206         }
       
   207     }
       
   208 
       
   209     /* Type check and compress user functions. */
       
   210     {
       
   211         const UserFunction::List::const_iterator end(info->userFunctions.constEnd());
       
   212         UserFunction::List::const_iterator it(info->userFunctions.constBegin());
       
   213 
       
   214         /* If the query has a focus(which is common, in the case of a
       
   215          * stylesheet), we must ensure that the focus isn't visible in the
       
   216          * function body. */
       
   217         StaticContext::Ptr effectiveContext;
       
   218 
       
   219         if(hasExternalFocus)
       
   220         {
       
   221             effectiveContext = StaticContext::Ptr(new StaticFocusContext(ItemType::Ptr(),
       
   222                                                                          context));
       
   223         }
       
   224         else
       
   225             effectiveContext = context;
       
   226 
       
   227         for(; it != end; ++it)
       
   228         {
       
   229             pDebug() << "-----      User Function Typecheck      -----";
       
   230             registerLastPath((*it)->body());
       
   231 
       
   232             /* We will most likely call body()->typeCheck() again, once for
       
   233              * each callsite. That is, it will be called from
       
   234              * UserFunctionCallsite::typeCheck(), which will be called
       
   235              * indirectly when we check the query body. */
       
   236             const Expression::Ptr typeCheck((*it)->body()->typeCheck(effectiveContext,
       
   237                                                                      (*it)->signature()->returnType()));
       
   238             /* We don't have to call (*it)->setBody(typeCheck) here since it's
       
   239              * only used directly below. */
       
   240             processTreePass(typeCheck, UserFunctionTypeCheck);
       
   241             pDebug() << "------------------------------";
       
   242 
       
   243             pDebug() << "-----      User Function Compress      -----";
       
   244             const Expression::Ptr comp(typeCheck->compress(effectiveContext));
       
   245             (*it)->setBody(comp);
       
   246             processTreePass(comp, UserFunctionCompression);
       
   247             pDebug() << "------------------------------";
       
   248         }
       
   249     }
       
   250 
       
   251     /* Type check and compress global variables. */
       
   252     {
       
   253         const VariableDeclaration::Stack::const_iterator vend(info->variables.constEnd());
       
   254         VariableDeclaration::Stack::const_iterator vit(info->variables.constBegin());
       
   255         for(; vit != vend; ++vit)
       
   256         {
       
   257             Q_ASSERT(*vit);
       
   258             /* This is a bit murky, the global variable will have it
       
   259              * Expression::typeCheck() function called from all its references,
       
   260              * but we also want to check it here globally, so we do
       
   261              * typechecking using a proper focus. */
       
   262             if((*vit)->type == VariableDeclaration::ExternalVariable)
       
   263                 continue;
       
   264 
       
   265             pDebug() << "-----      Global Variable Typecheck      -----";
       
   266             Q_ASSERT((*vit)->expression());
       
   267             /* We supply ZeroOrMoreItems, meaning the variable can evaluate to anything. */
       
   268             // FIXME which is a source to bugs
       
   269             // TODO What about compressing variables?
       
   270             const Expression::Ptr
       
   271             nev((*vit)->expression()->typeCheck(context, CommonSequenceTypes::ZeroOrMoreItems));
       
   272             processTreePass(nev, GlobalVariableTypeCheck);
       
   273             pDebug() << "------------------------------";
       
   274         }
       
   275     }
       
   276 
       
   277     /* Do all tests specific to XSL-T. */
       
   278     if(lang == QXmlQuery::XSLT20)
       
   279     {
       
   280         /* Type check and compress named templates. */
       
   281         {
       
   282             pDebug() << "Have " << info->namedTemplates.count() << "named templates";
       
   283 
       
   284             QMutableHashIterator<QXmlName, Template::Ptr> it(info->namedTemplates);
       
   285 
       
   286             while(it.hasNext())
       
   287             {
       
   288                 it.next();
       
   289                 processNamedTemplate(it.key(), it.value()->body, TemplateInitial);
       
   290 
       
   291                 it.value()->body = it.value()->body->typeCheck(context, CommonSequenceTypes::ZeroOrMoreItems);
       
   292                 processNamedTemplate(it.key(), it.value()->body, TemplateTypeCheck);
       
   293 
       
   294                 it.value()->body = it.value()->body->compress(context);
       
   295                 processNamedTemplate(it.key(), it.value()->body, TemplateCompress);
       
   296 
       
   297                 it.value()->compileParameters(context);
       
   298             }
       
   299         }
       
   300 
       
   301         /* Type check and compress template rules. */
       
   302         {
       
   303             QHashIterator<QXmlName, TemplateMode::Ptr> it(info->templateRules);
       
   304 
       
   305             /* Since a pattern can exist of AxisStep, its typeCheck() stage
       
   306              * requires a focus. In the case that we're invoked with a name but
       
   307              * no focus, this will yield a compile error, unless we declare a
       
   308              * focus manually. This only needs to be done for the pattern
       
   309              * expression, since the static type of the pattern is used as the
       
   310              * static type for the focus of the template body. */
       
   311             StaticContext::Ptr patternContext;
       
   312             if(hasExternalFocus)
       
   313                 patternContext = context;
       
   314             else
       
   315                 patternContext = StaticContext::Ptr(new StaticFocusContext(BuiltinTypes::node, context));
       
   316 
       
   317             /* For each template pattern. */
       
   318             while(it.hasNext())
       
   319             {
       
   320                 it.next();
       
   321                 const TemplateMode::Ptr &mode = it.value();
       
   322                 const int len = mode->templatePatterns.count();
       
   323                 TemplatePattern::ID currentTemplateID = -1;
       
   324                 bool hasDoneItOnce = false;
       
   325 
       
   326                 /* For each template pattern. */
       
   327                 for(int i = 0; i < len; ++i)
       
   328                 {
       
   329                     /* We can't use references for these two members, since we
       
   330                      * assign to them. */
       
   331                     const TemplatePattern::Ptr &pattern = mode->templatePatterns.at(i);
       
   332                     Expression::Ptr matchPattern(pattern->matchPattern());
       
   333 
       
   334                     processTemplateRule(pattern->templateTarget()->body,
       
   335                                         pattern, mode->name(), TemplateInitial);
       
   336 
       
   337                     matchPattern = matchPattern->typeCheck(patternContext, CommonSequenceTypes::ZeroOrMoreItems);
       
   338                     matchPattern = matchPattern->compress(patternContext);
       
   339                     pattern->setMatchPattern(matchPattern);
       
   340 
       
   341                     if(currentTemplateID == -1 && hasDoneItOnce)
       
   342                     {
       
   343                         currentTemplateID = pattern->id();
       
   344                         continue;
       
   345                     }
       
   346                     else if(currentTemplateID == pattern->id() && hasDoneItOnce)
       
   347                     {
       
   348                         hasDoneItOnce = false;
       
   349                         continue;
       
   350                     }
       
   351 
       
   352                     hasDoneItOnce = true;
       
   353                     currentTemplateID = pattern->id();
       
   354                     Expression::Ptr body(pattern->templateTarget()->body);
       
   355 
       
   356                     /* Patterns for a new template has started, we must
       
   357                      * deal with the body & parameters. */
       
   358                     {
       
   359                         /* TODO type is wrong, it has to be the union of all
       
   360                          * patterns. */
       
   361                         const StaticContext::Ptr focusContext(new StaticFocusContext(matchPattern->staticType()->itemType(),
       
   362                                                                                      context));
       
   363                         body = body->typeCheck(focusContext, CommonSequenceTypes::ZeroOrMoreItems);
       
   364 
       
   365                         pattern->templateTarget()->compileParameters(focusContext);
       
   366                     }
       
   367 
       
   368                     processTemplateRule(body, pattern, mode->name(), TemplateTypeCheck);
       
   369 
       
   370                     body = body->compress(context);
       
   371 
       
   372                     pattern->templateTarget()->body = body;
       
   373                     processTemplateRule(body, pattern, mode->name(), TemplateCompress);
       
   374                 }
       
   375 
       
   376                 mode->finalize();
       
   377             }
       
   378         }
       
   379 
       
   380         /* Add templates in mode #all to all other modes.
       
   381          *
       
   382          * We do this after the templates has been typechecked and compressed,
       
   383          * since otherwise it will be done N times for the built-in templates,
       
   384          * where N is the count of different templates, instead of once. */
       
   385         {
       
   386             const QXmlName nameModeAll(QXmlName(StandardNamespaces::InternalXSLT,
       
   387                                                 StandardLocalNames::all));
       
   388             const TemplateMode::Ptr &modeAll = info->templateRules[nameModeAll];
       
   389 
       
   390             Q_ASSERT_X(modeAll, Q_FUNC_INFO,
       
   391                        "We should at least have the builtin templates.");
       
   392             QHashIterator<QXmlName, TemplateMode::Ptr> it(info->templateRules);
       
   393 
       
   394             while(it.hasNext())
       
   395             {
       
   396                 it.next();
       
   397 
       
   398                 /* Don't add mode #all to mode #all. */
       
   399                 if(it.key()  == nameModeAll)
       
   400                     continue;
       
   401 
       
   402                 it.value()->addMode(modeAll);
       
   403             }
       
   404         }
       
   405     }
       
   406 
       
   407     /* Type check and compress the query body. */
       
   408     {
       
   409         pDebug() << "----- Initial AST build. -----";
       
   410         processTreePass(result, QueryBodyInitial);
       
   411         pDebug() << "------------------------------";
       
   412 
       
   413         pDebug() << "-----     Type Check     -----";
       
   414         registerLastPath(result);
       
   415         result->rewrite(result, result->typeCheck(context, requiredType), context);
       
   416         processTreePass(result, QueryBodyTypeCheck);
       
   417         pDebug() << "------------------------------";
       
   418 
       
   419         pDebug() << "-----      Compress      -----";
       
   420         result->rewrite(result, result->compress(context), context);
       
   421         processTreePass(result, QueryBodyCompression);
       
   422         pDebug() << "------------------------------";
       
   423     }
       
   424 
       
   425     return result;
       
   426 }
       
   427 
       
   428 void ExpressionFactory::registerLastPath(const Expression::Ptr &operand)
       
   429 {
       
   430     OperandsIterator it(operand, OperandsIterator::IncludeParent);
       
   431     Expression::Ptr next(it.next());
       
   432 
       
   433     while(next)
       
   434     {
       
   435         if(next->is(Expression::IDPath))
       
   436         {
       
   437             next->as<Path>()->setLast();
       
   438             next = it.skipOperands();
       
   439         }
       
   440         else
       
   441             next = it.next();
       
   442     }
       
   443 }
       
   444 
       
   445 void ExpressionFactory::processTreePass(const Expression::Ptr &,
       
   446                                         const CompilationStage)
       
   447 {
       
   448 }
       
   449 
       
   450 void ExpressionFactory::processTemplateRule(const Expression::Ptr &body,
       
   451                                             const TemplatePattern::Ptr &pattern,
       
   452                                             const QXmlName &mode,
       
   453                                             const TemplateCompilationStage stage)
       
   454 {
       
   455     Q_UNUSED(body);
       
   456     Q_UNUSED(pattern);
       
   457     Q_UNUSED(mode);
       
   458     Q_UNUSED(stage);
       
   459 }
       
   460 
       
   461 void ExpressionFactory::processNamedTemplate(const QXmlName &name,
       
   462                                              const Expression::Ptr &tree,
       
   463                                              const TemplateCompilationStage stage)
       
   464 {
       
   465     Q_UNUSED(name);
       
   466     Q_UNUSED(tree);
       
   467     Q_UNUSED(stage);
       
   468 }
       
   469 
       
   470 } // namespace QPatternist
       
   471 
       
   472 QT_END_NAMESPACE
       
   473