src/xmlpatterns/expr/qaxisstep.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 "qitemmappingiterator_p.h"
       
    45 #include "qgenericsequencetype_p.h"
       
    46 #include "qparentnodeaxis_p.h"
       
    47 
       
    48 #include "qaxisstep_p.h"
       
    49 
       
    50 QT_BEGIN_NAMESPACE
       
    51 
       
    52 using namespace QPatternist;
       
    53 
       
    54 namespace QPatternist
       
    55 {
       
    56     /**
       
    57      * This operator is needed for the s_whenAxisNodeKindEmpty array. The @c int constructors
       
    58      * ensure we invoke another operator| such that we don't get an infinite loop.
       
    59      */
       
    60     static inline QXmlNodeModelIndex::NodeKind operator|(const QXmlNodeModelIndex::NodeKind &op1, const QXmlNodeModelIndex::NodeKind &op2)
       
    61     {
       
    62         return QXmlNodeModelIndex::NodeKind(int(op1) | int(op2));
       
    63     }
       
    64 }
       
    65 
       
    66 /**
       
    67  * @note The order is significant. It is of the same order as the values in QXmlNodeModelIndex::Axis is declared.
       
    68  */
       
    69 const QXmlNodeModelIndex::NodeKind AxisStep::s_whenAxisNodeKindEmpty[] =
       
    70 {
       
    71     QXmlNodeModelIndex::Attribute|QXmlNodeModelIndex::Text|QXmlNodeModelIndex::ProcessingInstruction|QXmlNodeModelIndex::Comment|QXmlNodeModelIndex::Namespace,   // child;
       
    72     QXmlNodeModelIndex::Attribute|QXmlNodeModelIndex::Text|QXmlNodeModelIndex::ProcessingInstruction|QXmlNodeModelIndex::Comment|QXmlNodeModelIndex::Namespace,   // descendant;
       
    73     QXmlNodeModelIndex::Document|QXmlNodeModelIndex::Attribute|QXmlNodeModelIndex::Text|QXmlNodeModelIndex::ProcessingInstruction|QXmlNodeModelIndex::Comment|QXmlNodeModelIndex::Namespace,// attribute;
       
    74     QXmlNodeModelIndex::NodeKind(0),                         // self;
       
    75     QXmlNodeModelIndex::NodeKind(0),                         // descendant-or-self;
       
    76     QXmlNodeModelIndex::Document|QXmlNodeModelIndex::Attribute|QXmlNodeModelIndex::Text|QXmlNodeModelIndex::ProcessingInstruction|QXmlNodeModelIndex::Comment|QXmlNodeModelIndex::Namespace,    // namespace;
       
    77     QXmlNodeModelIndex::Document,                                         // following;
       
    78     QXmlNodeModelIndex::Document,                                         // parent;
       
    79     QXmlNodeModelIndex::Document,                                         // ancestor
       
    80     QXmlNodeModelIndex::Document|QXmlNodeModelIndex::Attribute|QXmlNodeModelIndex::Namespace,         // preceding-sibling;
       
    81     QXmlNodeModelIndex::Document|QXmlNodeModelIndex::Attribute|QXmlNodeModelIndex::Namespace,         // following-sibling;
       
    82     QXmlNodeModelIndex::Document,                                         // preceding;
       
    83     QXmlNodeModelIndex::NodeKind(0)                          // ancestor-or-self;
       
    84 };
       
    85 
       
    86 bool AxisStep::isAlwaysEmpty(const QXmlNodeModelIndex::Axis axis, const QXmlNodeModelIndex::NodeKind nodeKind)
       
    87 {
       
    88     return (s_whenAxisNodeKindEmpty[(1 >> axis) - 1] & nodeKind) != 0;
       
    89 }
       
    90 
       
    91 AxisStep::AxisStep(const QXmlNodeModelIndex::Axis a,
       
    92                    const ItemType::Ptr &nt) : m_axis(a),
       
    93                                               m_nodeTest(nt)
       
    94 {
       
    95     Q_ASSERT(m_nodeTest);
       
    96     Q_ASSERT_X(BuiltinTypes::node->xdtTypeMatches(m_nodeTest), Q_FUNC_INFO,
       
    97                "We assume we're a node type.");
       
    98 }
       
    99 
       
   100 Item AxisStep::mapToItem(const QXmlNodeModelIndex &node,
       
   101                          const DynamicContext::Ptr &context) const
       
   102 {
       
   103     Q_ASSERT(!node.isNull());
       
   104     Q_ASSERT(Item(node).isNode());
       
   105     Q_ASSERT(Item(node));
       
   106     Q_UNUSED(context);
       
   107 
       
   108     if(m_nodeTest->itemMatches(Item(node)))
       
   109         return Item(node);
       
   110     else
       
   111         return Item();
       
   112 }
       
   113 
       
   114 Item::Iterator::Ptr AxisStep::evaluateSequence(const DynamicContext::Ptr &context) const
       
   115 {
       
   116     /* If we don't have a focus, it's either a bug or our parent isn't a Path
       
   117      * that have advanced the focus iterator. Hence, attempt to advance the focus on our own. */
       
   118     if(!context->contextItem())
       
   119         context->focusIterator()->next();
       
   120 
       
   121     Q_ASSERT(context->contextItem());
       
   122 
       
   123     const QXmlNodeModelIndex::Iterator::Ptr source(context->contextItem().asNode().iterate(m_axis));
       
   124 
       
   125     return makeItemMappingIterator<Item>(ConstPtr(this), source, context);
       
   126 }
       
   127 
       
   128 Item AxisStep::evaluateSingleton(const DynamicContext::Ptr &context) const
       
   129 {
       
   130     /* If we don't have a focus, it's either a bug or our parent isn't a Path
       
   131      * that have advanced the focus iterator. Hence, attempt to advance the focus on our own. */
       
   132     if(!context->contextItem())
       
   133         context->focusIterator()->next();
       
   134 
       
   135     Q_ASSERT(context->contextItem());
       
   136 
       
   137     const QXmlNodeModelIndex::Iterator::Ptr it(context->contextItem().asNode().iterate(m_axis));
       
   138     QXmlNodeModelIndex next(it->next());
       
   139 
       
   140     while(!next.isNull())
       
   141     {
       
   142         const Item candidate(mapToItem(next, context));
       
   143 
       
   144         if(candidate)
       
   145             return candidate;
       
   146         else
       
   147             next = it->next();
       
   148     };
       
   149 
       
   150     return Item();
       
   151 }
       
   152 
       
   153 Expression::Ptr AxisStep::typeCheck(const StaticContext::Ptr &context,
       
   154                                     const SequenceType::Ptr &reqType)
       
   155 {
       
   156     if(m_axis == QXmlNodeModelIndex::AxisParent && *m_nodeTest == *BuiltinTypes::node)
       
   157     {
       
   158         /* We only rewrite parent::node() to ParentNodeAxis. */
       
   159         return rewrite(Expression::Ptr(new ParentNodeAxis()), context)->typeCheck(context, reqType);
       
   160     }
       
   161     /* TODO temporarily disabled
       
   162     else if(isAlwaysEmpty(m_axis, static_cast<const AnyNodeType *>(m_nodeTest.data())->nodeKind()))
       
   163         return EmptySequence::create(this, context);
       
   164         */
       
   165     else
       
   166         return EmptyContainer::typeCheck(context, reqType);
       
   167 }
       
   168 
       
   169 SequenceType::Ptr AxisStep::staticType() const
       
   170 {
       
   171     Cardinality cardinality;
       
   172 
       
   173     if(m_axis == QXmlNodeModelIndex::AxisSelf || m_axis == QXmlNodeModelIndex::AxisParent)
       
   174         cardinality = Cardinality::zeroOrOne();
       
   175     else
       
   176         cardinality = Cardinality::zeroOrMore();
       
   177 
       
   178     return makeGenericSequenceType(m_nodeTest,
       
   179                                    cardinality);
       
   180 }
       
   181 
       
   182 SequenceType::List AxisStep::expectedOperandTypes() const
       
   183 {
       
   184     SequenceType::List result;
       
   185     result.append(CommonSequenceTypes::ZeroOrMoreNodes);
       
   186     return result;
       
   187 }
       
   188 
       
   189 Expression::Properties AxisStep::properties() const
       
   190 {
       
   191     return RequiresContextItem | DisableElimination;
       
   192 }
       
   193 
       
   194 ItemType::Ptr AxisStep::expectedContextItemType() const
       
   195 {
       
   196     return BuiltinTypes::node;
       
   197 }
       
   198 
       
   199 ExpressionVisitorResult::Ptr AxisStep::accept(const ExpressionVisitor::Ptr &visitor) const
       
   200 {
       
   201     return visitor->visit(this);
       
   202 }
       
   203 
       
   204 QXmlNodeModelIndex::Axis AxisStep::axis() const
       
   205 {
       
   206     return m_axis;
       
   207 }
       
   208 
       
   209 QString AxisStep::axisName(const QXmlNodeModelIndex::Axis axis)
       
   210 {
       
   211     const char *result = 0;
       
   212 
       
   213     switch(axis)
       
   214     {
       
   215         /* These must not be translated. */
       
   216         case QXmlNodeModelIndex::AxisAncestorOrSelf:    result = "ancestor-or-self";    break;
       
   217         case QXmlNodeModelIndex::AxisAncestor:          result = "ancestor";            break;
       
   218         case QXmlNodeModelIndex::AxisAttributeOrTop:    result = "attribute-or-top";    break;
       
   219         case QXmlNodeModelIndex::AxisAttribute:         result = "attribute";           break;
       
   220         case QXmlNodeModelIndex::AxisChildOrTop:        result = "child-or-top";        break;
       
   221         case QXmlNodeModelIndex::AxisChild:             result = "child";               break;
       
   222         case QXmlNodeModelIndex::AxisDescendantOrSelf:  result = "descendant-or-self";  break;
       
   223         case QXmlNodeModelIndex::AxisDescendant:        result = "descendant";          break;
       
   224         case QXmlNodeModelIndex::AxisFollowing:         result = "following";           break;
       
   225         case QXmlNodeModelIndex::AxisFollowingSibling:  result = "following-sibling";   break;
       
   226         case QXmlNodeModelIndex::AxisNamespace:         result = "namespace";           break;
       
   227         case QXmlNodeModelIndex::AxisParent:            result = "parent";              break;
       
   228         case QXmlNodeModelIndex::AxisPreceding:         result = "preceding";           break;
       
   229         case QXmlNodeModelIndex::AxisPrecedingSibling:  result = "preceding-sibling";   break;
       
   230         case QXmlNodeModelIndex::AxisSelf:              result = "self";                break;
       
   231     }
       
   232 
       
   233     Q_ASSERT_X(result, Q_FUNC_INFO, "An unknown axis type was apparently encountered.");
       
   234     return QString::fromLatin1(result);
       
   235 }
       
   236 
       
   237 PatternPriority AxisStep::patternPriority() const
       
   238 {
       
   239     return static_cast<const AnyNodeType *>(m_nodeTest.data())->patternPriority();
       
   240 }
       
   241 
       
   242 Expression::ID AxisStep::id() const
       
   243 {
       
   244     return IDAxisStep;
       
   245 }
       
   246 
       
   247 QT_END_NAMESPACE