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