1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qabstractfloat_p.h"
41#include "qboolean_p.h"
42#include "qbuiltintypes_p.h"
43#include "qcommonsequencetypes_p.h"
44#include "qemptysequence_p.h"
45#include "qfirstitempredicate_p.h"
46#include "qgenericsequencetype_p.h"
47#include "qitemmappingiterator_p.h"
48#include "qliteral_p.h"
49#include "qpatternistlocale_p.h"
50#include "qtruthpredicate_p.h"
51
52#include "qgenericpredicate_p.h"
53
54QT_BEGIN_NAMESPACE
55
56using namespace QPatternist;
57
58GenericPredicate::GenericPredicate(const Expression::Ptr &sourceExpression,
59 const Expression::Ptr &predicate) : PairContainer(sourceExpression,
60 predicate)
61{
62}
63
64Expression::Ptr GenericPredicate::create(const Expression::Ptr &sourceExpression,
65 const Expression::Ptr &predicateExpression,
66 const StaticContext::Ptr &context,
67 const QSourceLocation &location)
68{
69 Q_ASSERT(sourceExpression);
70 Q_ASSERT(predicateExpression);
71 Q_ASSERT(context);
72 const ItemType::Ptr type(predicateExpression->staticType()->itemType());
73
74 if(predicateExpression->is(i: IDIntegerValue) &&
75 predicateExpression->as<Literal>()->item().as<Numeric>()->toInteger() == 1)
76 { /* Handle [1] */
77 return createFirstItem(sourceExpression);
78 }
79 else if(BuiltinTypes::numeric->xdtTypeMatches(other: type))
80 { /* A numeric predicate, other than [1]. */
81 /* TODO at somepoint we'll return a specialized expr here, NumericPredicate or so.
82 * Dependency analysis is a bit tricky, since the contained expression can depend on
83 * some loop component. */
84 return Expression::Ptr(new GenericPredicate(sourceExpression, predicateExpression));
85 }
86 else if(*CommonSequenceTypes::Empty == *type)
87 {
88 return EmptySequence::create(replacementFor: predicateExpression.data(), context);
89 }
90 else if(*BuiltinTypes::item == *type ||
91 *BuiltinTypes::xsAnyAtomicType == *type)
92 {
93 /* The type couldn't be narrowed at compile time, so we use
94 * a generic predicate. This check is before the CommonSequenceTypes::EBV check,
95 * because the latter matches these types as well. */
96 return Expression::Ptr(new GenericPredicate(sourceExpression, predicateExpression));
97 }
98 else if(CommonSequenceTypes::EBV->itemType()->xdtTypeMatches(other: type))
99 {
100 return Expression::Ptr(new TruthPredicate(sourceExpression, predicateExpression));
101 }
102 else
103 {
104 context->error(message: QtXmlPatterns::tr(sourceText: "A value of type %1 cannot be a "
105 "predicate. A predicate must have "
106 "either a numeric type or an "
107 "Effective Boolean Value type.")
108 .arg(a: formatType(np: context->namePool(),
109 type: sourceExpression->staticType())),
110 errorCode: ReportContext::FORG0006, sourceLocation: location);
111 return Expression::Ptr(); /* Silence compiler warning. */
112 }
113}
114
115Expression::Ptr GenericPredicate::createFirstItem(const Expression::Ptr &sourceExpression)
116
117{
118 return Expression::Ptr(new FirstItemPredicate(sourceExpression));
119}
120
121Item GenericPredicate::mapToItem(const Item &item,
122 const DynamicContext::Ptr &context) const
123{
124 const Item::Iterator::Ptr it(m_operand2->evaluateSequence(context));
125 const Item pcateItem(it->next());
126
127 if(!pcateItem)
128 return Item(); /* The predicate evaluated to the empty sequence */
129 else if(pcateItem.isNode())
130 return item;
131 /* Ok, now it must be an AtomicValue */
132 else if(BuiltinTypes::numeric->xdtTypeMatches(other: pcateItem.type()))
133 { /* It's a positional predicate. */
134 if(it->next())
135 {
136 context->error(message: QtXmlPatterns::tr(sourceText: "A positional predicate must "
137 "evaluate to a single numeric "
138 "value."),
139 errorCode: ReportContext::FORG0006, reflection: this);
140 return Item();
141 }
142
143 if(Double::isEqual(a: static_cast<xsDouble>(context->contextPosition()),
144 b: pcateItem.as<Numeric>()->toDouble()))
145 {
146 return item;
147 }
148 else
149 return Item();
150 }
151 else if(Boolean::evaluateEBV(first: pcateItem, e: it, context)) /* It's a truth predicate. */
152 return item;
153 else
154 return Item();
155}
156
157Item::Iterator::Ptr GenericPredicate::evaluateSequence(const DynamicContext::Ptr &context) const
158{
159 const Item::Iterator::Ptr focus(m_operand1->evaluateSequence(context));
160 const DynamicContext::Ptr newContext(context->createFocus());
161 newContext->setFocusIterator(focus);
162
163 return makeItemMappingIterator<Item>(mapper: ConstPtr(this),
164 source: focus,
165 context: newContext);
166}
167
168Item GenericPredicate::evaluateSingleton(const DynamicContext::Ptr &context) const
169{
170 const Item::Iterator::Ptr focus(m_operand1->evaluateSequence(context));
171 const DynamicContext::Ptr newContext(context->createFocus());
172 newContext->setFocusIterator(focus);
173 return mapToItem(item: focus->next(), context: newContext);
174}
175
176SequenceType::List GenericPredicate::expectedOperandTypes() const
177{
178 SequenceType::List result;
179 result.append(t: CommonSequenceTypes::ZeroOrMoreItems);
180 result.append(t: CommonSequenceTypes::ZeroOrMoreItems);
181 return result;
182}
183
184SequenceType::Ptr GenericPredicate::staticType() const
185{
186 const SequenceType::Ptr type(m_operand1->staticType());
187 return makeGenericSequenceType(itemType: type->itemType(),
188 cardinality: type->cardinality() | Cardinality::zeroOrOne());
189}
190
191ExpressionVisitorResult::Ptr GenericPredicate::accept(const ExpressionVisitor::Ptr &visitor) const
192{
193 return visitor->visit(this);
194}
195
196ItemType::Ptr GenericPredicate::newFocusType() const
197{
198 return m_operand1->staticType()->itemType();
199}
200
201Expression::Properties GenericPredicate::properties() const
202{
203 return CreatesFocusForLast;
204}
205
206QString GenericPredicate::description() const
207{
208 return QLatin1String("predicate");
209}
210
211Expression::ID GenericPredicate::id() const
212{
213 return IDGenericPredicate;
214}
215
216QT_END_NAMESPACE
217

source code of qtxmlpatterns/src/xmlpatterns/expr/qgenericpredicate.cpp