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 //
41 //  W A R N I N G
42 //  -------------
43 //
44 // This file is not part of the Qt API.  It exists purely as an
45 // implementation detail.  This header file may change from version to
46 // version without notice, or even be removed.
47 //
48 // We mean it.
49 
50 #ifndef Patternist_SequenceFNs_H
51 #define Patternist_SequenceFNs_H
52 
53 #include <private/qatomiccomparator_p.h>
54 #include <private/qcomparisonplatform_p.h>
55 #include <private/qliteral_p.h>
56 #include <private/qfunctioncall_p.h>
57 
58 /**
59  * @file
60  * @short Contains classes implementing the functions found in
61  * <a href="http://www.w3.org/TR/xpath-functions/#general-seq-funcs">XQuery 1.0 and
62  * XPath 2.0 Functions and Operators, 15.1 General Functions and Operators on Sequences</a>.
63  *
64  * @todo document that some functions have both eval funcs implented.
65  *
66  * @ingroup Patternist_functions
67  */
68 
69 QT_BEGIN_NAMESPACE
70 
71 namespace QPatternist
72 {
73     /**
74      * @short Implements the function <tt>fn:boolean()</tt>.
75      *
76      * @see EBVExtractor
77      * @ingroup Patternist_functions
78      * @author Frans Englich <frans.englich@nokia.com>
79      */
80     class BooleanFN : public FunctionCall
81     {
82     public:
83         virtual bool evaluateEBV(const DynamicContext::Ptr &context) const;
84 
85         /**
86          * If @p reqType is CommonSequenceTypes::EBV, the type check of
87          * the operand is returned. Hence, this removes redundant calls
88          * to <tt>fn:boolean()</tt>.
89          */
90         virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context,
91                                           const SequenceType::Ptr &reqType);
92     };
93 
94     /**
95      * @short Implements the function <tt>fn:index-of()</tt>.
96      *
97      * @ingroup Patternist_functions
98      * @author Frans Englich <frans.englich@nokia.com>
99      */
100     class IndexOfFN : public FunctionCall,
101                       public ComparisonPlatform<IndexOfFN, false>
102     {
103     public:
IndexOfFN()104         inline IndexOfFN() : ComparisonPlatform<IndexOfFN, false>()
105         {
106         }
107 
108         virtual Item::Iterator::Ptr evaluateSequence(const DynamicContext::Ptr &context) const;
109         virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context,
110                                           const SequenceType::Ptr &reqType);
111 
operatorID()112         inline AtomicComparator::Operator operatorID() const
113         {
114             return AtomicComparator::OperatorEqual;
115         }
116     };
117 
118     /**
119      * @short Implements the functions <tt>fn:exists()</tt> and <tt>fn:empty()</tt>.
120      *
121      * Existence is a template value class. Appropriate implementations are achieved
122      * by instantiating it with either IDExistsFN or IDEmptyFN.
123      *
124      * @ingroup Patternist_functions
125      * @author Frans Englich <frans.englich@nokia.com>
126      */
127     template<const Expression::ID Id>
128     class Existence : public FunctionCall
129     {
130     public:
evaluateEBV(const DynamicContext::Ptr & context)131         virtual bool evaluateEBV(const DynamicContext::Ptr &context) const
132         {
133             if(Id == IDExistsFN)
134                 return !m_operands.first()->evaluateSequence(context)->isEmpty();
135             else
136                 return m_operands.first()->evaluateSequence(context)->isEmpty();
137         }
138 
139         /**
140          * Attempts to rewrite to @c false or @c true by looking at the static
141          * cardinality of its operand.
142          */
compress(const StaticContext::Ptr & context)143         virtual Expression::Ptr compress(const StaticContext::Ptr &context)
144         {
145             // RVCT doesn't like using template parameter in trinary operator when the trinary operator result is
146             // passed directly into another constructor.
147             Q_ASSERT(Id == IDExistsFN || Id == IDEmptyFN);
148 
149             const Expression::Ptr me(FunctionCall::compress(context));
150 
151             if(me != this)
152                 return me;
153 
154             // RVCT doesn't like using template parameter in trinary operator when the trinary operator result is
155             // passed directly into another constructor.
156             Expression::ID tempId = Id;
157             const Cardinality myCard((tempId == IDExistsFN) ? Cardinality::oneOrMore() : Cardinality::empty());
158 
159             const Cardinality card(m_operands.first()->staticType()->cardinality());
160             if(myCard.isMatch(card))
161             { /* Since the dynamic type always is narrower than the static type or equal, and that the
162                  static type is in scope, it means we will always be true. */
163                 return wrapLiteral(CommonValues::BooleanTrue, context, this);
164             }
165             else
166             {
167                 /* Is it even possible to hit? */
168                 if(myCard.canMatch(card))
169                 {
170                     return me;
171                 }
172                 else
173                 { /* We can never hit. */
174                     return wrapLiteral(CommonValues::BooleanFalse, context, this);
175                 }
176             }
177         }
178     };
179 
180     /**
181      * @short Implements the function <tt>fn:distinct-values()</tt>.
182      *
183      * @ingroup Patternist_functions
184      * @author Frans Englich <frans.englich@nokia.com>
185      */
186     class DistinctValuesFN : public FunctionCall,
187                              public ComparisonPlatform<IndexOfFN, false>
188     {
189     public:
DistinctValuesFN()190         inline DistinctValuesFN() : ComparisonPlatform<IndexOfFN, false>()
191         {
192         }
193 
194         virtual Item::Iterator::Ptr evaluateSequence(const DynamicContext::Ptr &context) const;
195         /**
196          * Performs necessary type checks, but also implements the optimization
197          * of rewriting to its operand if the operand's cardinality is zero-or-one
198          * or exactly-one.
199          */
200         virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context,
201                                           const SequenceType::Ptr &reqType);
202         /**
203          * @returns a type whose item type is the type of the first operand, and
204          * a cardinality which is non-empty if the first operand's type is non-empty
205          * and allows exactly-one. The latter is needed for operands which has the
206          * cardinality 2+, since distinct-values possibly removes items from the
207          * source sequence.
208          */
209         virtual SequenceType::Ptr staticType() const;
210 
211     protected:
operatorID()212         inline AtomicComparator::Operator operatorID() const
213         {
214             return AtomicComparator::OperatorEqual;
215         }
216     };
217 
218     /**
219      * @short Implements the function <tt>fn:insert-before()</tt>.
220      *
221      * @todo docs, explain why evaluateSequence and evaluateSingleton is implemented
222      *
223      * @ingroup Patternist_functions
224      * @author Frans Englich <frans.englich@nokia.com>
225      */
226     class InsertBeforeFN : public FunctionCall
227     {
228     public:
229         virtual Item::Iterator::Ptr evaluateSequence(const DynamicContext::Ptr &context) const;
230         virtual Item evaluateSingleton(const DynamicContext::Ptr &context) const;
231 
232         /**
233          * Implements the static enferences rules. The function's static item type
234          * is the union type of the first and third argument, and the cardinality is
235          * the cardinalities of the two operands added together. For example,
236          * insert-before((1, "str"), 1, xs:double(0)) has the static type xs:anyAtomicType+.
237          *
238          * @see <a href="http://www.w3.org/TR/xquery-semantics/#sec_fn_insert_before">XQuery 1.0
239          * and XPath 2.0 Formal Semantics, 7.2.15 The fn:insert-before function</a>
240          */
241         virtual SequenceType::Ptr staticType() const;
242     };
243 
244     /**
245      * @short Implements the function <tt>fn:remove()</tt>.
246      *
247      * @ingroup Patternist_functions
248      * @author Frans Englich <frans.englich@nokia.com>
249      */
250     class RemoveFN : public FunctionCall
251     {
252     public:
253         virtual Item::Iterator::Ptr evaluateSequence(const DynamicContext::Ptr &context) const;
254         virtual Item evaluateSingleton(const DynamicContext::Ptr &context) const;
255 
256         /**
257          * Implements the static enferences rules, "Since one item may be removed
258          * from the sequence, the resulting type is made optional:"
259          *
260          * <tt>statEnv |-  (FN-URI,"remove")(Type, Type1) : prime(Type) * quantifier(Type)?</tt>
261          *
262          * However, because Patternist's type system is more fine grained than Formal Semantics,
263          * the sequence isn't made optional. Instead its minimum length is reduced with one.
264          *
265          * @see <a href="http://www.w3.org/TR/xquery-semantics/#sec_fn_remove">XQuery 1.0
266          * and XPath 2.0 Formal Semantics, 7.2.11 The fn:remove function</a>
267          */
268         virtual SequenceType::Ptr staticType() const;
269     };
270 
271     /**
272      * @short Implements the function <tt>fn:reverse()</tt>.
273      *
274      * @ingroup Patternist_functions
275      * @author Frans Englich <frans.englich@nokia.com>
276      */
277     class ReverseFN : public FunctionCall
278     {
279     public:
280 
281         virtual Item::Iterator::Ptr evaluateSequence(const DynamicContext::Ptr &context) const;
282         virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context,
283                                           const SequenceType::Ptr &reqType);
284 
285         /**
286          * Formally speaking, the type inference is:
287          *
288 @verbatim
289 statEnv |-  (FN-URI,"reverse")(Type) : prime(Type) * quantifier(Type)
290 @endverbatim
291          *
292          * @see <a href="http://www.w3.org/TR/xquery-semantics/#sec_fn_reverse">XQuery 1.0
293          * and XPath 2.0 Formal Semantics, 7.2.12 The fn:reverse function</a>
294          * @returns the static type of the function's first argument.
295          */
296         virtual SequenceType::Ptr staticType() const;
297     };
298 
299     /**
300      * @short Implements the function <tt>fn:subsequence()</tt>.
301      *
302      * @ingroup Patternist_functions
303      * @author Frans Englich <frans.englich@nokia.com>
304      * @todo Type inference can be made stronger for this function
305      */
306     class SubsequenceFN : public FunctionCall
307     {
308     public:
309         SubsequenceFN();
310         virtual Item::Iterator::Ptr evaluateSequence(const DynamicContext::Ptr &context) const;
311         virtual Item evaluateSingleton(const DynamicContext::Ptr &context) const;
312 
313         virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context,
314                                           const SequenceType::Ptr &reqType);
315 
316         /**
317          * This function implements rewrites the SubsequenceFN instance into an
318          * empty sequence if its third argument, the sequence length argument, is
319          * evaluated and is effectively equal or less than zero.
320          */
321         virtual Expression::Ptr compress(const StaticContext::Ptr &context);
322 
323         /**
324          * Partially implements the static type inference rules.
325          *
326          * @see <a href="http://www.w3.org/TR/xquery-semantics/#sec_fn_subsequence">XQuery 1.0
327          * and XPath 2.0 Formal Semantics, 7.2.13 The fn:subsequence function</a>
328          */
329         virtual SequenceType::Ptr staticType() const;
330 
331     private:
332         bool m_hasTypeChecked;
333     };
334 }
335 
336 QT_END_NAMESPACE
337 
338 #endif
339