src/xmlpatterns/functions/qsequencefns.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 "qbuiltintypes_p.h"
       
    43 #include "qcommonsequencetypes_p.h"
       
    44 #include "qcommonvalues_p.h"
       
    45 #include "qdistinctiterator_p.h"
       
    46 #include "qebvextractor_p.h"
       
    47 #include "qemptysequence_p.h"
       
    48 #include "qgenericsequencetype_p.h"
       
    49 #include "qindexofiterator_p.h"
       
    50 #include "qinsertioniterator_p.h"
       
    51 #include "qinteger_p.h"
       
    52 #include "qremovaliterator_p.h"
       
    53 #include "qsequencegeneratingfns_p.h"
       
    54 #include "qsubsequenceiterator_p.h"
       
    55 
       
    56 #include "qsequencefns_p.h"
       
    57 
       
    58 QT_BEGIN_NAMESPACE
       
    59 
       
    60 using namespace QPatternist;
       
    61 
       
    62 bool BooleanFN::evaluateEBV(const DynamicContext::Ptr &context) const
       
    63 {
       
    64     return m_operands.first()->evaluateEBV(context);
       
    65 }
       
    66 
       
    67 Expression::Ptr BooleanFN::typeCheck(const StaticContext::Ptr &context,
       
    68                                      const SequenceType::Ptr &reqType)
       
    69 {
       
    70     return EBVExtractor::typeCheck<FunctionCall>(context, reqType, this);
       
    71 }
       
    72 
       
    73 Item::Iterator::Ptr IndexOfFN::evaluateSequence(const DynamicContext::Ptr &context) const
       
    74 {
       
    75     return Item::Iterator::Ptr(new IndexOfIterator(m_operands.first()->evaluateSequence(context),
       
    76                                                    m_operands.at(1)->evaluateSingleton(context),
       
    77                                                    comparator(), context,
       
    78                                                    ConstPtr(this)));
       
    79 }
       
    80 
       
    81 Expression::Ptr IndexOfFN::typeCheck(const StaticContext::Ptr &context,
       
    82                                      const SequenceType::Ptr &reqType)
       
    83 {
       
    84     const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
       
    85     const ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
       
    86     const ItemType::Ptr t2(m_operands.at(1)->staticType()->itemType());
       
    87 
       
    88     if(*CommonSequenceTypes::Empty == *t1 ||
       
    89        *CommonSequenceTypes::Empty == *t2)
       
    90     {
       
    91         return EmptySequence::create(this, context);
       
    92     }
       
    93     else
       
    94     {
       
    95         prepareComparison(fetchComparator(t1, t2, context));
       
    96         return me;
       
    97     }
       
    98 }
       
    99 
       
   100 Item::Iterator::Ptr DistinctValuesFN::evaluateSequence(const DynamicContext::Ptr &context) const
       
   101 {
       
   102     return Item::Iterator::Ptr(new DistinctIterator(m_operands.first()->evaluateSequence(context),
       
   103                                                     comparator(),
       
   104                                                     ConstPtr(this),
       
   105                                                     context));
       
   106 }
       
   107 
       
   108 Expression::Ptr DistinctValuesFN::typeCheck(const StaticContext::Ptr &context,
       
   109                                             const SequenceType::Ptr &reqType)
       
   110 {
       
   111     const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
       
   112     const ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
       
   113 
       
   114     if(*CommonSequenceTypes::Empty == *t1)
       
   115         return EmptySequence::create(this, context);
       
   116     else if(!m_operands.first()->staticType()->cardinality().allowsMany())
       
   117         return m_operands.first();
       
   118     else if(BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(t1))
       
   119         return me;
       
   120     else
       
   121     {
       
   122         prepareComparison(fetchComparator(t1, t1, context));
       
   123         return me;
       
   124     }
       
   125 }
       
   126 
       
   127 SequenceType::Ptr DistinctValuesFN::staticType() const
       
   128 {
       
   129     const SequenceType::Ptr t(m_operands.first()->staticType());
       
   130     return makeGenericSequenceType(t->itemType(),
       
   131                                    t->cardinality().allowsMany() ? Cardinality::oneOrMore()
       
   132                                                                  : Cardinality::exactlyOne());
       
   133 }
       
   134 
       
   135 Item::Iterator::Ptr InsertBeforeFN::evaluateSequence(const DynamicContext::Ptr &context) const
       
   136 {
       
   137     const Item::Iterator::Ptr target(m_operands.first()->evaluateSequence(context));
       
   138     const Item::Iterator::Ptr inserts(m_operands.at(2)->evaluateSequence(context));
       
   139 
       
   140     xsInteger position = m_operands.at(1)->evaluateSingleton(context).as<Numeric>()->toInteger();
       
   141 
       
   142     if(position < 1)
       
   143         position = 1;
       
   144 
       
   145     return Item::Iterator::Ptr(new InsertionIterator(target, position, inserts));
       
   146 }
       
   147 
       
   148 Item InsertBeforeFN::evaluateSingleton(const DynamicContext::Ptr &context) const
       
   149 {
       
   150     return evaluateSequence(context)->next();
       
   151 }
       
   152 
       
   153 SequenceType::Ptr InsertBeforeFN::staticType() const
       
   154 {
       
   155     const SequenceType::Ptr t1(m_operands.first()->staticType());
       
   156     const SequenceType::Ptr t2(m_operands.last()->staticType());
       
   157 
       
   158     return makeGenericSequenceType(t1->itemType() | t2->itemType(),
       
   159                                    t1->cardinality() + t2->cardinality());
       
   160 }
       
   161 
       
   162 Item::Iterator::Ptr RemoveFN::evaluateSequence(const DynamicContext::Ptr &context) const
       
   163 {
       
   164     const xsInteger pos = m_operands.last()->evaluateSingleton(context).as<Numeric>()->toInteger();
       
   165     Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
       
   166 
       
   167     if(pos < 1)
       
   168         return it;
       
   169 
       
   170     return Item::Iterator::Ptr(new RemovalIterator(it, pos));
       
   171 }
       
   172 
       
   173 Item RemoveFN::evaluateSingleton(const DynamicContext::Ptr &context) const
       
   174 {
       
   175     const xsInteger pos = m_operands.last()->evaluateSingleton(context).as<Numeric>()->toInteger();
       
   176     if(pos <= 1)
       
   177         return Item();
       
   178 
       
   179     return m_operands.first()->evaluateSingleton(context);
       
   180 }
       
   181 
       
   182 SequenceType::Ptr RemoveFN::staticType() const
       
   183 {
       
   184     const SequenceType::Ptr opType(m_operands.first()->staticType());
       
   185     const Cardinality c(opType->cardinality());
       
   186 
       
   187     if(c.minimum() == 0)
       
   188         return makeGenericSequenceType(opType->itemType(), c);
       
   189     else
       
   190     {
       
   191         return makeGenericSequenceType(opType->itemType(),
       
   192                                        Cardinality::fromRange(c.minimum() - 1,
       
   193                                                               c.maximum()));
       
   194     }
       
   195 }
       
   196 
       
   197 Item::Iterator::Ptr ReverseFN::evaluateSequence(const DynamicContext::Ptr &context) const
       
   198 {
       
   199     return m_operands.first()->evaluateSequence(context)->toReversed();
       
   200 }
       
   201 
       
   202 Expression::Ptr ReverseFN::typeCheck(const StaticContext::Ptr &context,
       
   203                                      const SequenceType::Ptr &reqType)
       
   204 {
       
   205     if(m_operands.first()->staticType()->cardinality().allowsMany())
       
   206         return FunctionCall::typeCheck(context, reqType);
       
   207     else
       
   208         return m_operands.first()->typeCheck(context, reqType);
       
   209 }
       
   210 
       
   211 SequenceType::Ptr ReverseFN::staticType() const
       
   212 {
       
   213     return m_operands.first()->staticType();
       
   214 }
       
   215 
       
   216 SubsequenceFN::SubsequenceFN() : m_hasTypeChecked(false)
       
   217 {
       
   218 }
       
   219 
       
   220 Expression::Ptr SubsequenceFN::typeCheck(const StaticContext::Ptr &context,
       
   221                                          const SequenceType::Ptr &reqType)
       
   222 {
       
   223     m_hasTypeChecked = true;
       
   224     return FunctionCall::typeCheck(context, reqType);
       
   225 }
       
   226 
       
   227 Item::Iterator::Ptr SubsequenceFN::evaluateSequence(const DynamicContext::Ptr &context) const
       
   228 {
       
   229     Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
       
   230 
       
   231     xsInteger startingLoc = m_operands.at(1)->evaluateSingleton(context).as<Numeric>()->round()->toInteger();
       
   232     xsInteger length = -1;
       
   233 
       
   234     if(m_operands.count() == 3)
       
   235     {
       
   236         length = m_operands.last()->evaluateSingleton(context).as<Numeric>()->toInteger();
       
   237 
       
   238         if(startingLoc + length < 1 || (startingLoc > (startingLoc + length)))
       
   239             return CommonValues::emptyIterator;
       
   240     }
       
   241 
       
   242     /* F&O, 15.1.10, "If $startingLoc is zero or negative, the
       
   243      * subsequence includes items from the beginning of the $sourceSeq." */
       
   244     if(startingLoc < 1)
       
   245         startingLoc = 1;
       
   246 
       
   247     if(length < 1 && length != -1)
       
   248         return CommonValues::emptyIterator;
       
   249     return Item::Iterator::Ptr(new SubsequenceIterator(it, startingLoc, length));
       
   250 }
       
   251 
       
   252 Item SubsequenceFN::evaluateSingleton(const DynamicContext::Ptr &context) const
       
   253 {
       
   254     return evaluateSequence(context)->next();
       
   255 }
       
   256 
       
   257 Expression::Ptr SubsequenceFN::compress(const StaticContext::Ptr &context)
       
   258 {
       
   259     const Expression::Ptr me(FunctionCall::compress(context));
       
   260     if(me != this)
       
   261         return me;
       
   262 
       
   263     const Expression::Ptr lenArg(m_operands.value(2));
       
   264     if(lenArg && lenArg->isEvaluated())
       
   265     {
       
   266         const xsInteger length = lenArg->as<Literal>()->item().as<Numeric>()->round()->toInteger();
       
   267 
       
   268         if(length <= 0)
       
   269             return EmptySequence::create(this, context);
       
   270     }
       
   271 
       
   272     return me;
       
   273 }
       
   274 
       
   275 SequenceType::Ptr SubsequenceFN::staticType() const
       
   276 {
       
   277     const SequenceType::Ptr opType(m_operands.first()->staticType());
       
   278     const Cardinality opCard(opType->cardinality());
       
   279 
       
   280     /* Optimization: we can do much stronger inference here. If the length is a
       
   281      * constant, we can constrain the range at least upwards of the
       
   282      * cardinality, for instance. */
       
   283 
       
   284     /* The subsequence(expr, 1, 1), add empty-sequence() to the static type.
       
   285      *
       
   286      * Note that we cannot do all these inferences before we've typechecked our
       
   287      * operands. The only known case of where our staticType() is called before
       
   288      * typeCheck() is through xmlpatternsview, although it wouldn't be
       
   289      * surprising if the more exotic paths can achieve that too.
       
   290      */
       
   291     if(m_hasTypeChecked &&
       
   292        m_operands.at(1)->isEvaluated()                                                      &&
       
   293        m_operands.count() == 3                                                              &&
       
   294        m_operands.at(2)->isEvaluated()                                                      &&
       
   295        m_operands.at(1)->as<Literal>()->item().as<Numeric>()->round()->toInteger() == 1     &&
       
   296        m_operands.at(2)->as<Literal>()->item().as<Numeric>()->round()->toInteger() == 1)
       
   297     {
       
   298         return makeGenericSequenceType(opType->itemType(),
       
   299                                        opCard.toWithoutMany());
       
   300     }
       
   301     else
       
   302     {
       
   303         return makeGenericSequenceType(opType->itemType(),
       
   304                                        opCard | Cardinality::zeroOrOne());
       
   305     }
       
   306 }
       
   307 
       
   308 Expression::Ptr DocFN::typeCheck(const StaticContext::Ptr &context,
       
   309                                  const SequenceType::Ptr &reqType)
       
   310 {
       
   311     /* See the doxygen documentation for this function for the explanation
       
   312      * to why this implementation is here, as opposed to in
       
   313      * qsequencegeneratingfns.cpp. */
       
   314 
       
   315     Q_ASSERT(context);
       
   316 
       
   317     prepareStaticBaseURI(context);
       
   318 
       
   319     const Expression::Ptr uriOp(m_operands.first());
       
   320 
       
   321     if(!uriOp->isEvaluated())
       
   322         return Expression::Ptr(FunctionCall::typeCheck(context, reqType));
       
   323 
       
   324     const Item uriItem(uriOp->evaluateSingleton(context->dynamicContext()));
       
   325 
       
   326     if(!uriItem)
       
   327         return EmptySequence::create(this, context)->typeCheck(context, reqType); // TODO test this
       
   328 
       
   329     /* These two lines were previously in a separate function but are now duplicated
       
   330      * in DocFN::evaluateSingleton(), as part of a workaround for solaris-cc-64. */
       
   331     const QUrl mayRela(AnyURI::toQUrl<ReportContext::FODC0005>(uriItem.stringValue(), context, this));
       
   332     const QUrl uri(context->resolveURI(mayRela, staticBaseURI()));
       
   333 
       
   334     /* The URI is supplied statically, so, let's try to be clever. */
       
   335     Q_ASSERT_X(context->resourceLoader(), Q_FUNC_INFO,
       
   336                "No resource loader is set in the StaticContext.");
       
   337     m_type = context->resourceLoader()->announceDocument(uri, ResourceLoader::MayUse);
       
   338 
       
   339     if(m_type)
       
   340     {
       
   341         Q_ASSERT(CommonSequenceTypes::ZeroOrOneDocumentNode->matches(m_type));
       
   342         return Expression::Ptr(FunctionCall::typeCheck(context, reqType));
       
   343     }
       
   344     else
       
   345     {
       
   346         context->error(QtXmlPatterns::tr("It will not be possible to retrieve %1.").arg(formatURI(uri)),
       
   347                        ReportContext::FODC0002, this);
       
   348         return Expression::Ptr();
       
   349     }
       
   350 }
       
   351 
       
   352 QT_END_NAMESPACE