src/xmlpatterns/expr/qexpression.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 "qboolean_p.h"
       
    43 #include "qcommonvalues_p.h"
       
    44 #include "qemptysequence_p.h"
       
    45 #include "qliteral_p.h"
       
    46 #include "qliteralsequence_p.h"
       
    47 #include "qoperandsiterator_p.h"
       
    48 #include "qoptimizerframework_p.h"
       
    49 #include "qstaticfocuscontext_p.h"
       
    50 #include "qtypechecker_p.h"
       
    51 
       
    52 #include "qexpression_p.h"
       
    53 
       
    54 QT_BEGIN_NAMESPACE
       
    55 
       
    56 using namespace QPatternist;
       
    57 
       
    58 Expression::~Expression()
       
    59 {
       
    60 }
       
    61 
       
    62 StaticContext::Ptr Expression::finalizeStaticContext(const StaticContext::Ptr &context) const
       
    63 {
       
    64     Q_ASSERT(context);
       
    65     const ItemType::Ptr focusType(newFocusType());
       
    66     Q_ASSERT(focusType);
       
    67     return StaticContext::Ptr(new StaticFocusContext(focusType, context));
       
    68 }
       
    69 
       
    70 Expression::Ptr Expression::typeCheck(const StaticContext::Ptr &context,
       
    71                                       const SequenceType::Ptr &reqType)
       
    72 {
       
    73     Q_ASSERT(reqType);
       
    74     typeCheckOperands(context);
       
    75     return TypeChecker::applyFunctionConversion(Expression::Ptr(this), reqType, context);
       
    76 }
       
    77 
       
    78 void Expression::typeCheckOperands(const StaticContext::Ptr &context)
       
    79 {
       
    80     const Expression::List ops(operands());
       
    81 
       
    82     /* Check if this expression has any operands at all. */
       
    83     if(ops.isEmpty())
       
    84         return; /* We're done, early exit. */
       
    85 
       
    86     const SequenceType::List opTypes(expectedOperandTypes());
       
    87     Expression::List result;
       
    88 
       
    89     /* If we create a focus, we handle the last one specially, so avoid it in the loop. */
       
    90     const bool createsFocus = has(CreatesFocusForLast);
       
    91     const SequenceType::List::const_iterator typeEnd(createsFocus ? --opTypes.constEnd()
       
    92                                                                   : opTypes.constEnd());
       
    93     const Expression::List::const_iterator end(createsFocus ? --ops.constEnd()
       
    94                                                             : ops.constEnd());
       
    95 
       
    96     SequenceType::List::const_iterator reqType(opTypes.constBegin());
       
    97     SequenceType::Ptr t(*reqType);
       
    98     // TODO we assign twice to t here(also below in loop) when ops.size() > 1
       
    99 
       
   100     Expression::List::const_iterator it(ops.constBegin());
       
   101 
       
   102     for(; it != end; ++it)
       
   103     {
       
   104         /* This ensures that the last expectedOperandType stays, and is
       
   105          * used for all other operands. This is used for expressions that
       
   106          * have an infinite amount of operands, such as the concat() function. */
       
   107         if(reqType != typeEnd)
       
   108         {
       
   109             t = *reqType;
       
   110             ++reqType;
       
   111         }
       
   112 
       
   113          /* Let the child & its children typecheck. */
       
   114         result.append((*it)->typeCheck(context, t));
       
   115     }
       
   116 
       
   117     if(createsFocus)
       
   118     {
       
   119         const StaticContext::Ptr newContext(finalizeStaticContext(context));
       
   120         result.append(ops.last()->typeCheck(newContext, opTypes.last()));
       
   121     }
       
   122 
       
   123     setOperands(result);
       
   124 }
       
   125 
       
   126 Expression::Ptr Expression::invokeOptimizers(const Expression::Ptr &expr,
       
   127                                              const StaticContext::Ptr &context)
       
   128 {
       
   129     Q_ASSERT(expr);
       
   130 
       
   131     const OptimizationPass::List opts(expr->optimizationPasses());
       
   132 
       
   133     if(opts.isEmpty()) /* Early exit. */
       
   134     {
       
   135         return expr;
       
   136     }
       
   137 
       
   138     const OptimizationPass::List::const_iterator passEnd(opts.constEnd());
       
   139     const OptimizationPass::List::const_iterator end(opts.constEnd());
       
   140     OptimizationPass::List::const_iterator passIt(opts.constBegin());
       
   141 
       
   142     for(; passIt != passEnd; ++passIt) /* Invoke each optimization pass. */
       
   143     {
       
   144         const OptimizationPass::Ptr pass(*passIt); /* Alias, for readability. */
       
   145         OptimizationPass::ExpressionMarker sourceMarker(pass->sourceExpression);
       
   146 
       
   147         if(pass->startIdentifier && !pass->startIdentifier->matches(expr))
       
   148         {
       
   149             /* This pass specified a start identifier and it did
       
   150              * not match -- let's try the next OptimizationPass. */
       
   151             continue;
       
   152         }
       
   153 
       
   154         const ExpressionIdentifier::List::const_iterator idEnd(pass->operandIdentifiers.constEnd());
       
   155         ExpressionIdentifier::List::const_iterator idIt(pass->operandIdentifiers.constBegin());
       
   156         const Expression::List ops(expr->operands());
       
   157         const Expression::List::const_iterator opEnd(ops.constEnd());
       
   158         Expression::List::const_iterator opIt(ops.constBegin());
       
   159 
       
   160         switch(pass->operandsMatchMethod)
       
   161         {
       
   162             case OptimizationPass::Sequential:
       
   163             {
       
   164                 for(; opIt != opEnd; ++opIt)
       
   165                 {
       
   166                     const Expression::Ptr operand(*opIt); /* Alias, for readability. */
       
   167                     const ExpressionIdentifier::Ptr opIdentifier(*idIt); /* Alias, for readability. */
       
   168                     if(opIdentifier && !opIdentifier->matches(operand))
       
   169                     {
       
   170                         break;
       
   171                     }
       
   172 
       
   173                     ++idIt;
       
   174                 }
       
   175 
       
   176                 if(opIt == opEnd)
       
   177                     break; /* All operands matched, so this pass matched. */
       
   178                 else
       
   179                 {
       
   180                     /* The loop above did not finish which means all operands did not match.
       
   181                        Therefore, this OptimizationPass did not match -- let's try the next one. */
       
   182                     continue;
       
   183                 }
       
   184             }
       
   185             case OptimizationPass::AnyOrder:
       
   186             {
       
   187                 Q_ASSERT_X(ops.count() == 2, Q_FUNC_INFO,
       
   188                            "AnyOrder is currently only supported for Expressions with two operands.");
       
   189                 if(pass->operandIdentifiers.first()->matches(ops.first()) &&
       
   190                    pass->operandIdentifiers.last()->matches(ops.last()))
       
   191                 {
       
   192                     break;
       
   193                 }
       
   194                 else if(pass->operandIdentifiers.first()->matches(ops.last()) &&
       
   195                         pass->operandIdentifiers.last()->matches(ops.first()))
       
   196                 {
       
   197                     sourceMarker.first() = 1;
       
   198                     sourceMarker[1] = 0;
       
   199                     break; /* This pass matched. */
       
   200                 }
       
   201                 else
       
   202                     continue; /* This pass didn't match, let's loop through the next pass. */
       
   203             }
       
   204         }
       
   205 
       
   206         /* Figure out the source Expression, if any. */
       
   207         Expression::List operands;
       
   208         Expression::Ptr sourceExpr;
       
   209 
       
   210         if(!sourceMarker.isEmpty())
       
   211         {
       
   212             const OptimizationPass::ExpressionMarker::const_iterator mEnd(sourceMarker.constEnd());
       
   213             OptimizationPass::ExpressionMarker::const_iterator mIt(sourceMarker.constBegin());
       
   214             sourceExpr = expr;
       
   215 
       
   216             for(; mIt != mEnd; ++mIt)
       
   217             {
       
   218                 Q_ASSERT(*mIt >= 0);
       
   219                 sourceExpr = sourceExpr->operands().at(*mIt);
       
   220             }
       
   221 
       
   222             operands.append(sourceExpr);
       
   223         }
       
   224 
       
   225         if(operands.isEmpty())
       
   226         {
       
   227             Q_ASSERT(pass->resultCreator);
       
   228             return pass->resultCreator->create(Expression::List(), context, expr.data())->compress(context);
       
   229         }
       
   230         else if(pass->resultCreator)
       
   231             return pass->resultCreator->create(operands, context, expr.data())->compress(context);
       
   232         else
       
   233         {
       
   234             return sourceExpr;
       
   235         }
       
   236     }
       
   237 
       
   238     return expr;
       
   239 }
       
   240 
       
   241 Expression::Ptr Expression::compress(const StaticContext::Ptr &context)
       
   242 {
       
   243     if(!compressOperands(context))
       
   244     {
       
   245         /* At least one of the operands cannot be evaluated at compile, so
       
   246          * 'this' Expression cannot const fold. */
       
   247         return invokeOptimizers(Expression::Ptr(this), context);
       
   248     }
       
   249 
       
   250     Expression::Ptr retval;
       
   251 
       
   252     if(hasDependency(DisableElimination))
       
   253         retval = Expression::Ptr(this);
       
   254     else
       
   255         retval = constantPropagate(context);
       
   256 
       
   257     return invokeOptimizers(retval, context);
       
   258 }
       
   259 
       
   260 Expression::Ptr Expression::constantPropagate(const StaticContext::Ptr &context) const
       
   261 {
       
   262     Q_ASSERT(context);
       
   263 
       
   264     /* Optimization: We rewrite literals to literals here, which is pointless.
       
   265      * Maybe we should have a property which says "doesn't disable elimination
       
   266      * but don't eliminate me." */
       
   267     if(staticType()->cardinality().allowsMany())
       
   268     {
       
   269         Item::Iterator::Ptr it(evaluateSequence(context->dynamicContext()));
       
   270         Item::List result;
       
   271         Item item(it->next());
       
   272 
       
   273         while(item)
       
   274         {
       
   275             result.append(item);
       
   276             item = it->next();
       
   277         }
       
   278 
       
   279         switch(result.count())
       
   280         {
       
   281             case 0:
       
   282                 return EmptySequence::create(this, context);
       
   283             case 1:
       
   284                 return rewrite(Expression::Ptr(new Literal(result.first())), context);
       
   285             default:
       
   286                 return rewrite(Expression::Ptr(new LiteralSequence(result)), context);
       
   287         }
       
   288     }
       
   289     else
       
   290     {
       
   291         const Item item(evaluateSingleton(context->dynamicContext()));
       
   292 
       
   293         if(item)
       
   294             return rewrite(Expression::Ptr(new Literal(item)), context);
       
   295         else
       
   296             return EmptySequence::create(this, context);
       
   297     }
       
   298 }
       
   299 
       
   300 Item::Iterator::Ptr Expression::evaluateSequence(const DynamicContext::Ptr &context) const
       
   301 {
       
   302     const Item item(evaluateSingleton(context));
       
   303 
       
   304     if(item)
       
   305         return makeSingletonIterator(item);
       
   306     else
       
   307         return CommonValues::emptyIterator;
       
   308 }
       
   309 
       
   310 Item Expression::evaluateSingleton(const DynamicContext::Ptr &context) const
       
   311 {
       
   312     return Boolean::fromValue(evaluateEBV(context));
       
   313 }
       
   314 
       
   315 bool Expression::evaluateEBV(const DynamicContext::Ptr &context) const
       
   316 {
       
   317     return Boolean::evaluateEBV(evaluateSequence(context), context);
       
   318 }
       
   319 
       
   320 void Expression::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
       
   321 {
       
   322     QAbstractXmlReceiver *const receiver = context->outputReceiver();
       
   323     const Item::Iterator::Ptr it(evaluateSequence(context));
       
   324     Item next(it->next());
       
   325 
       
   326     while(next)
       
   327     {
       
   328         receiver->item(next);
       
   329         next = it->next();
       
   330     }
       
   331 }
       
   332 
       
   333 ItemType::Ptr Expression::expectedContextItemType() const
       
   334 {
       
   335     Q_ASSERT_X(false, Q_FUNC_INFO,
       
   336                "expectedContextItemType() must be overridden when RequiresContextItem is set.");
       
   337     return ItemType::Ptr();
       
   338 }
       
   339 
       
   340 Expression::Properties Expression::properties() const
       
   341 {
       
   342     return Properties();
       
   343 }
       
   344 
       
   345 Expression::Properties Expression::dependencies() const
       
   346 {
       
   347     OperandsIterator it(Ptr(const_cast<Expression *>(this)), OperandsIterator::ExcludeParent);
       
   348     Expression::Ptr next(it.next());
       
   349 
       
   350     Properties dependencies(properties());
       
   351 
       
   352     while(next)
       
   353     {
       
   354         dependencies |= next->dependencies();
       
   355         next = it.next();
       
   356     }
       
   357 
       
   358     return dependencies & (Expression::RequiresFocus | Expression::IsEvaluated | Expression::DisableElimination);
       
   359 }
       
   360 
       
   361 void Expression::announceFocusType(const ItemType::Ptr &itemType)
       
   362 {
       
   363     const Expression::List ops(operands());
       
   364     const int len = ops.count();
       
   365 
       
   366     for(int i = 0; i < len; ++i)
       
   367         ops.at(i)->announceFocusType(itemType);
       
   368 }
       
   369 
       
   370 Expression::Properties Expression::deepProperties() const
       
   371 {
       
   372     Properties props(properties());
       
   373     const Expression::List ops(operands());
       
   374     const int len = ops.count();
       
   375 
       
   376     for(int i = 0; i < len; ++i)
       
   377         props |= ops.at(i)->deepProperties();
       
   378 
       
   379     return props;
       
   380 }
       
   381 
       
   382 Expression::ID Expression::id() const
       
   383 {
       
   384     return IDIgnorableExpression;
       
   385 }
       
   386 
       
   387 OptimizationPass::List Expression::optimizationPasses() const
       
   388 {
       
   389     return OptimizationPass::List();
       
   390 }
       
   391 
       
   392 ItemType::Ptr Expression::newFocusType() const
       
   393 {
       
   394     Q_ASSERT_X(false, Q_FUNC_INFO,
       
   395                "This function must be overridden when CreatesFocusForLast is set.");
       
   396     return ItemType::Ptr();
       
   397 }
       
   398 
       
   399 const SourceLocationReflection *Expression::actualReflection() const
       
   400 {
       
   401     return this;
       
   402 }
       
   403 
       
   404 QString Expression::description() const
       
   405 {
       
   406     return QString::fromLatin1("Expression, id: %1").arg(QString::number(id()));
       
   407 }
       
   408 
       
   409 PatternPriority Expression::patternPriority() const
       
   410 {
       
   411     return 0.5;
       
   412 }
       
   413 
       
   414 QT_END_NAMESPACE