source: trunk/src/xmlpatterns/expr/qcastas.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 7.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qitem_p.h"
43#include "qbuiltintypes_p.h"
44#include "qcardinalityverifier_p.h"
45#include "qcommonsequencetypes_p.h"
46#include "qemptysequence_p.h"
47#include "qgenericsequencetype_p.h"
48#include "qliteral_p.h"
49#include "qpatternistlocale_p.h"
50#include "qnamespaceresolver_p.h"
51#include "qqnameconstructor_p.h"
52#include "qqnamevalue_p.h"
53#include "qatomicstring_p.h"
54#include "qvalidationerror_p.h"
55
56#include "qcastas_p.h"
57
58QT_BEGIN_NAMESPACE
59
60using namespace QPatternist;
61
62CastAs::CastAs(const Expression::Ptr &source,
63 const SequenceType::Ptr &tType) : SingleContainer(source),
64 m_targetType(tType)
65{
66 Q_ASSERT(source);
67 Q_ASSERT(tType);
68 Q_ASSERT(!tType->cardinality().allowsMany());
69 Q_ASSERT(tType->itemType()->isAtomicType());
70}
71
72Item CastAs::evaluateSingleton(const DynamicContext::Ptr &context) const
73{
74 Q_ASSERT(context);
75 const Item val(m_operand->evaluateSingleton(context));
76
77 if(val)
78 return cast(val, context);
79 else
80 {
81 /* No item supplied, let's handle the cardinality part. */
82
83 if(m_targetType->cardinality().allowsEmpty())
84 return Item();
85 else
86 {
87 Q_ASSERT(context);
88 context->error(QtXmlPatterns::tr("Type error in cast, expected %1, "
89 "received %2.")
90 .arg(formatType(Cardinality::exactlyOne()))
91 .arg(formatType(Cardinality::empty())),
92 ReportContext::XPTY0004, this);
93 return Item();
94 }
95 }
96}
97
98Expression::Ptr CastAs::typeCheck(const StaticContext::Ptr &context,
99 const SequenceType::Ptr &reqType)
100{
101 checkTargetType(context);
102 const SequenceType::Ptr seqt(m_operand->staticType());
103 ItemType::Ptr t(seqt->itemType());
104
105 /* Special case xs:QName */
106 if(BuiltinTypes::xsQName->xdtTypeMatches(m_targetType->itemType()))
107 {
108 /* Ok, We're casting to xs:QName. */
109 if(m_operand->is(IDStringValue)) /* A valid combination, let's do the cast. */
110 return castToQName(context)->typeCheck(context, reqType);
111 else if(BuiltinTypes::xsQName->xdtTypeMatches(t))
112 return m_operand->typeCheck(context, reqType);
113 else if(seqt->cardinality().isEmpty() && m_targetType->cardinality().allowsEmpty())
114 return EmptySequence::create(this, context);
115 else if(!(seqt->cardinality().isEmpty() && !m_targetType->cardinality().allowsEmpty()))
116 {
117 context->error(QtXmlPatterns::tr("When casting to %1 or types "
118 "derived from it, the source "
119 "value must be of the same type, "
120 "or it must be a string literal. "
121 "Type %2 is not allowed.")
122 .arg(formatType(context->namePool(), BuiltinTypes::xsQName))
123 .arg(formatType(context->namePool(), seqt)),
124 ReportContext::XPTY0004, this);
125 return Expression::Ptr(this);
126 }
127 }
128
129 const Expression::Ptr me(SingleContainer::typeCheck(context, reqType));
130 /* Type may have changed, such as that atomization has been applied. */
131 t = m_operand->staticType()->itemType();
132
133 if(m_targetType->itemType()->xdtTypeMatches(t) &&
134 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t) &&
135 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t))
136 { /* At least casting is superflorous. */
137 if(m_operand->staticType()->cardinality().isMatch(m_targetType->cardinality()))
138 return m_operand; /* The whole cast expression is redundant. */
139 else
140 { /* Only cardinality check is needed, rewrite to CardinalityVerifier. */
141 return Expression::Ptr(new CardinalityVerifier(m_operand,
142 m_targetType->cardinality(),
143 ReportContext::FORG0001));
144 }
145 }
146
147 /* Let the CastingPlatform look up its AtomicCaster. */
148 prepareCasting(context, t);
149
150 return me;
151}
152
153Expression::Ptr CastAs::compress(const StaticContext::Ptr &context)
154{
155 /* Simplify casts to itself. */
156 if(*m_targetType->itemType() == *m_operand->staticType()->itemType())
157 return m_operand->compress(context);
158 else
159 return SingleContainer::compress(context);
160}
161
162Expression::Ptr CastAs::castToQName(const StaticContext::Ptr &context) const
163{
164 /* Apply the whitespace facet by calling trimmed(). */
165 /* We can assume m_operand is an Expression because this is a requirement
166 * for casting to xs:QName. */
167 const QString lexQName(m_operand->as<Literal>()->item().as<AtomicValue>()->stringValue().trimmed());
168
169 const QXmlName
170 expName(QNameConstructor::expandQName<StaticContext::Ptr,
171 ReportContext::FORG0001,
172 ReportContext::FONS0004>(lexQName,
173 context,
174 context->namespaceBindings(), this));
175 return wrapLiteral(toItem(QNameValue::fromValue(context->namePool(), expName)), context, this);
176}
177
178SequenceType::Ptr CastAs::staticType() const
179{
180 if(m_operand->staticType()->cardinality().allowsEmpty())
181 return m_targetType;
182 else
183 return makeGenericSequenceType(m_targetType->itemType(),
184 Cardinality::exactlyOne());
185}
186
187SequenceType::List CastAs::expectedOperandTypes() const
188{
189 SequenceType::List result;
190
191 if(m_targetType->cardinality().allowsEmpty())
192 result.append(CommonSequenceTypes::ZeroOrOneAtomicType);
193 else
194 result.append(CommonSequenceTypes::ExactlyOneAtomicType);
195
196 return result;
197}
198
199ExpressionVisitorResult::Ptr CastAs::accept(const ExpressionVisitor::Ptr &visitor) const
200{
201 return visitor->visit(this);
202}
203
204QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.