Qt 4.8
Public Types | Static Public Functions | Private Functions | Static Private Functions | List of all members
QPatternist::TypeChecker Class Reference

Contains functions that applies Function Conversion Rules and other kinds of compile-time type checking tasks. More...

#include <qtypechecker_p.h>

Public Types

enum  Option { AutomaticallyConvert = 1, CheckFocus = 2, GeneratePromotion }
 
typedef QFlags< OptionOptions
 

Static Public Functions

static Expression::Ptr applyFunctionConversion (const Expression::Ptr &operand, const SequenceType::Ptr &reqType, const StaticContext::Ptr &context, const ReportContext::ErrorCode code=ReportContext::XPTY0004, const Options=Options(AutomaticallyConvert|CheckFocus))
 Builds a pipeline of artificial AST nodes that ensures operand conforms to the type reqType by applying the Function Conversion Rules. More...
 

Private Functions

 TypeChecker ()
 

Static Private Functions

static bool promotionPossible (const ItemType::Ptr &fromType, const ItemType::Ptr &toType, const StaticContext::Ptr &context)
 
static Expression::Ptr typeCheck (Expression *const op, const StaticContext::Ptr &context, const SequenceType::Ptr &reqType)
 
static Expression::Ptr verifyType (const Expression::Ptr &operand, const SequenceType::Ptr &reqSeqType, const StaticContext::Ptr &context, const ReportContext::ErrorCode code, const Options options)
 Implements the type checking and promotion part of the Function Conversion Rules. More...
 
static QString wrongType (const NamePool::Ptr &np, const ItemType::Ptr &reqType, const ItemType::Ptr &opType)
 Centralizes a message-string to reduce work for translators and increase consistency. More...
 

Detailed Description

Contains functions that applies Function Conversion Rules and other kinds of compile-time type checking tasks.

Author
Frans Englich frans.nosp@m..eng.nosp@m.lich@.nosp@m.noki.nosp@m.a.com

Definition at line 71 of file qtypechecker_p.h.

Typedefs

◆ Options

Definition at line 111 of file qtypechecker_p.h.

Enumerations

◆ Option

Enumerator
AutomaticallyConvert 

When set, the function conversion rules are applied.

For instance, this is type promotion and conversions from xs:untypedAtomic to xs:date. This is done for function calls, but not when binding an expression to a variable.

CheckFocus 

Whether the focus should be checked or not.

Sometimes the focus is unknown at the time applyFunctionConversion() is called, and therefore it is of interest to post pone the check to later on.

GeneratePromotion 

When applyFunctionConversion() is passed AutomaticallyConvert and promotion is required, such as from xs:integer to xs:float, there will be no conversion performed, with the assumption that the receiver will call Numeric::toFloat() or similar.

However, when GeneratePromotion is set, code will be generated that performs this conversion regardless of what any receiver do.

This is useful in the case where one Expression only pipes the result of another. The only known case of that as of this writing is when UserFunctionCallsite evaluates its body.

Definition at line 74 of file qtypechecker_p.h.

75  {
84 
92  CheckFocus = 2,
93 
110  };
When set, the function conversion rules are applied.
Whether the focus should be checked or not.

Constructors and Destructors

◆ TypeChecker()

QPatternist::TypeChecker::TypeChecker ( )
inlineprivate

No implementation is provided for this constructor. This class is not supposed to be instantiated.

Functions

◆ applyFunctionConversion()

Expression::Ptr TypeChecker::applyFunctionConversion ( const Expression::Ptr operand,
const SequenceType::Ptr reqType,
const StaticContext::Ptr context,
const ReportContext::ErrorCode  code = ReportContext::XPTY0004,
const Options  options = Options(AutomaticallyConvert | CheckFocus) 
)
static

Builds a pipeline of artificial AST nodes that ensures operand conforms to the type reqType by applying the Function Conversion Rules.

This new Expression is returned, or, if no conversions were necessary, operand as it is.

applyFunctionConversion() also performs various checks, such as if operand needs the focus and that the focus is defined in the context. These checks are largely guided by operand's Expression::properties().

See also
XML Path Language (XPath) 2.0, 3.1.5 Function Calls, more specifically the Function Conversion Rules

Definition at line 67 of file qtypechecker.cpp.

Referenced by QPatternist::Validate::create(), QPatternist::pushVariable(), QPatternist::resolveVariable(), QPatternist::TreatAs::typeCheck(), QPatternist::Path::typeCheck(), QPatternist::Expression::typeCheck(), QPatternist::typeCheckTemplateBody(), and QPatternist::yyparse().

72 {
74  "This test ensures 'code' exists, otherwise codeToString() would assert.");
75  Q_ASSERT(operand);
76  Q_ASSERT(reqType);
77  Q_ASSERT(context);
78 
79  /* Do it in two steps: verify type, and then cardinality. */
80  const Expression::Ptr cardVerified(CardinalityVerifier::verifyCardinality(operand, reqType->cardinality(), context, code));
81  return verifyType(cardVerified, reqType, context, code, options);
82 }
static QString codeToString(const ReportContext::ErrorCode errorCode)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
static Expression::Ptr verifyCardinality(const Expression::Ptr &operand, const Cardinality &card, const StaticContext::Ptr &context, const ReportContext::ErrorCode code=ReportContext::XPTY0004)
static bool isEmpty(const char *str)
virtual Cardinality cardinality() const =0
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
static Expression::Ptr verifyType(const Expression::Ptr &operand, const SequenceType::Ptr &reqSeqType, const StaticContext::Ptr &context, const ReportContext::ErrorCode code, const Options options)
Implements the type checking and promotion part of the Function Conversion Rules. ...
#define Q_FUNC_INFO
Definition: qglobal.h:1871

◆ promotionPossible()

bool TypeChecker::promotionPossible ( const ItemType::Ptr fromType,
const ItemType::Ptr toType,
const StaticContext::Ptr context 
)
staticprivate

Determines whether type promotion is possible from one type to another. False is returned when a promotion is not possible or if a promotion is not needed(as when the types are identical), since that can be considered to not be type promotion.

Returns
true if fromType can be promoted to toType.
See also
XML Path Language (XPath) 2.0, B.1 Type Promotion

Definition at line 84 of file qtypechecker.cpp.

Referenced by verifyType().

87 {
88  /* These types can be promoted to xs:string. xs:untypedAtomic should be
89  * cast when interpreting it formally, but implementing it as a promotion
90  * gives the same result(and is faster). */
91  if(*toType == *BuiltinTypes::xsString &&
92  (BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(fromType) ||
93  BuiltinTypes::xsAnyURI->xdtTypeMatches(fromType)))
94  return true;
95 
96  if(*toType == *BuiltinTypes::xsDouble &&
97  BuiltinTypes::numeric->xdtTypeMatches(fromType))
98  {
99  /* Any numeric can be promoted to xs:double. */
100  return true;
101  }
102 
103  /* xs:decimal/xs:integer can be promoted to xs:float. */
104  if(*toType == *BuiltinTypes::xsFloat && BuiltinTypes::xsDecimal->xdtTypeMatches(fromType))
105 
106  {
107  context->warning(QtXmlPatterns::tr("Promoting %1 to %2 may cause loss of precision.")
108  .arg(formatType(context->namePool(), fromType))
109  .arg(formatType(context->namePool(), BuiltinTypes::xsFloat)));
110  return true;
111  }
112 
113  return false;
114 }
QString formatType(const NamePool::Ptr &np, const T &type)
Formats ItemType and SequenceType.
virtual NamePool::Ptr namePool() const =0
static const AtomicType::Ptr xsString
static const AtomicType::Ptr xsDouble
static const AtomicType::Ptr xsUntypedAtomic
static const AtomicType::Ptr xsFloat
static const AtomicType::Ptr numeric
static const AtomicType::Ptr xsDecimal
void warning(const QString &message, const QSourceLocation &sourceLocation=QSourceLocation())
static const AtomicType::Ptr xsAnyURI

◆ typeCheck()

Expression::Ptr TypeChecker::typeCheck ( Expression *const  op,
const StaticContext::Ptr context,
const SequenceType::Ptr reqType 
)
inlinestaticprivate

Definition at line 116 of file qtypechecker.cpp.

Referenced by verifyType().

119 {
120  return Expression::Ptr(op->typeCheck(context, reqType));
121 }
virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType)
Definition: qexpression.cpp:70
QExplicitlySharedDataPointer< Expression > Ptr
A smart pointer wrapping mutable Expression instances.

◆ verifyType()

Expression::Ptr TypeChecker::verifyType ( const Expression::Ptr operand,
const SequenceType::Ptr reqSeqType,
const StaticContext::Ptr context,
const ReportContext::ErrorCode  code,
const Options  options 
)
staticprivate

Implements the type checking and promotion part of the Function Conversion Rules.

Definition at line 123 of file qtypechecker.cpp.

Referenced by applyFunctionConversion().

128 {
129  const ItemType::Ptr reqType(reqSeqType->itemType());
130  const Expression::Properties props(operand->properties());
131 
132  /* If operand requires a focus, do the necessary type checking for that. */
133  if(props.testFlag(Expression::RequiresFocus) && options.testFlag(CheckFocus))
134  {
135  const ItemType::Ptr contextType(context->contextItemType());
136  if(contextType)
137  {
138  if(props.testFlag(Expression::RequiresContextItem))
139  {
141  "When the Expression sets the RequiresContextItem property, it must "
142  "return a type in expectedContextItemType()");
143  const ItemType::Ptr expectedContextType(operand->expectedContextItemType());
144 
145  /* Allow the empty sequence. We don't want to trigger XPTY0020 on ()/... . */
146  if(!expectedContextType->xdtTypeMatches(contextType) && contextType != CommonSequenceTypes::Empty)
147  {
148  context->error(wrongType(context->namePool(), operand->expectedContextItemType(), contextType),
149  ReportContext::XPTY0020, operand.data());
150  return operand;
151  }
152  }
153  }
154  else
155  {
156  context->error(QtXmlPatterns::tr("The focus is undefined."), ReportContext::XPDY0002, operand.data());
157  return operand;
158  }
159  }
160 
161  SequenceType::Ptr operandSeqType(operand->staticType());
162  ItemType::Ptr operandType(operandSeqType->itemType());
163 
164  /* This returns the operand if the types are identical or if operandType
165  * is a subtype of reqType. */
166  if(reqType->xdtTypeMatches(operandType) || *operandType == *CommonSequenceTypes::Empty)
167  return operand;
168 
169  /* Since we haven't exited yet, it means that the operandType is a super type
170  * of reqType, and that there hence is a path down to it through the
171  * type hierachy -- but that doesn't necessarily mean that a up-cast(down the
172  * hierarchy) would succeed. */
173 
174  Expression::Ptr result(operand);
175 
176  if(reqType->isAtomicType())
177  {
178  const Expression::ID opID = operand->id();
179  if((opID == Expression::IDArgumentReference ||
181  && *BuiltinTypes::item == *operandType)
182  return Expression::Ptr(new ArgumentConverter(result, reqType));
183 
184  if(!operandType->isAtomicType())
185  {
186  result = Expression::Ptr(new Atomizer(result));
187  /* The atomizer might know more about the type. */
188  operandType = result->staticType()->itemType();
189  }
190 
191  if(reqType->xdtTypeMatches(operandType))
192  {
193  /* Atomization was sufficient. Either the expected type is xs:anyAtomicType
194  * or the type the Atomizer knows it returns, matches the required type. */
195  return result;
196  }
197 
198  const bool compatModeEnabled = context->compatModeEnabled();
199 
200  if((options.testFlag(AutomaticallyConvert) && BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(operandType)) ||
201  (compatModeEnabled && BuiltinTypes::xsString->xdtTypeMatches(reqType)))
202  {
203  if(*reqType == *BuiltinTypes::numeric)
204  {
205  result = typeCheck(new UntypedAtomicConverter(result, BuiltinTypes::xsDouble, code),
206  context, reqSeqType);
207  }
208  else
209  result = typeCheck(new UntypedAtomicConverter(result, reqType, code), context, reqSeqType);
210 
211  /* The UntypedAtomicConverter might know more about the type, so reload. */
212  operandType = result->staticType()->itemType();
213  }
214  else if(compatModeEnabled && *reqType == *BuiltinTypes::xsDouble)
215  {
216  const FunctionFactory::Ptr functions(context->functionSignatures());
217  Expression::List numberArgs;
218  numberArgs.append(operand);
219 
220  result = functions->createFunctionCall(QXmlName(StandardNamespaces::fn, StandardLocalNames::number),
221  numberArgs,
222  context,
223  operand.data())->typeCheck(context, reqSeqType);
224  operandType = result->staticType()->itemType();
225  context->wrapExpressionWith(operand.data(), result);
226  }
227 
228  if(reqType->xdtTypeMatches(operandType))
229  return result;
230 
231  /* Test if promotion will solve it; the xdtTypeMatches didn't
232  * do that. */
233  if(options.testFlag(AutomaticallyConvert) && promotionPossible(operandType, reqType, context))
234  {
235  if(options.testFlag(GeneratePromotion))
236  return Expression::Ptr(new UntypedAtomicConverter(result, reqType));
237  else
238  return result;
239  }
240 
241  if(operandType->xdtTypeMatches(reqType))
242  {
243  /* For example, operandType is numeric, and reqType is xs:integer. */
244  return Expression::Ptr(new ItemVerifier(result, reqType, code));
245  }
246  else
247  {
248  context->error(wrongType(context->namePool(), reqType, operandType), code, operand.data());
249  return result;
250  }
251  }
252  else if(reqType->isNodeType())
253  {
254 
256 
257  if(*reqType == *CommonSequenceTypes::EBV->itemType())
258  myCode = ReportContext::FORG0006;
259  else
260  myCode = code;
261 
262  /* empty-sequence() is considered valid because it's ok to do
263  * for example nilled( () ). That is, to pass an empty sequence to a
264  * function requiring for example node()?. */
265  if(*operandType == *CommonSequenceTypes::Empty)
266  return result;
267  else if(!operandType->xdtTypeMatches(reqType))
268  {
269  context->error(wrongType(context->namePool(), reqType, operandType), myCode, operand.data());
270  return result;
271  }
272 
273  /* Operand must be an item. Thus, the sequence can contain both
274  * nodes and atomic values: we have to verify. */
275  return Expression::Ptr(new ItemVerifier(result, reqType, myCode));
276  }
277  else
278  {
279  Q_ASSERT(*reqType == *CommonSequenceTypes::Empty);
280 
281  /* element() doesn't match empty-sequence(), but element()* does. */
282  if(!reqType->xdtTypeMatches(operandType) &&
283  !operandSeqType->cardinality().allowsEmpty())
284  {
285  context->error(wrongType(context->namePool(), reqType, operandType),
286  code, operand.data());
287  return result;
288  }
289  }
290 
291  /* This line should be reached if required type is
292  * EBVType, and the operand is compatible. */
293  return result;
294 }
virtual bool compatModeEnabled() const =0
static Expression::Ptr typeCheck(Expression *const op, const StaticContext::Ptr &context, const SequenceType::Ptr &reqType)
virtual NamePool::Ptr namePool() const =0
virtual ItemType::Ptr expectedContextItemType() const
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
When set, the function conversion rules are applied.
static const AtomicType::Ptr xsString
virtual ID id() const
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
T * data() const
Returns a pointer to the shared data object.
Definition: qshareddata.h:145
void error(const QString &message, const ReportContext::ErrorCode errorCode, const QSourceLocation &sourceLocation)
static const ItemType::Ptr item
static const AtomicType::Ptr xsDouble
Verifies that the items in a sequence an Expression evaluates is of a certain ItemType.
virtual QExplicitlySharedDataPointer< FunctionFactory > functionSignatures() const =0
virtual Expression::List operands() const =0
static const AtomicType::Ptr xsUntypedAtomic
Performs atomization. Effectively, it is an implementation of the fn:data() function.
Definition: qatomizer_p.h:76
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
QExplicitlySharedDataPointer< Expression > Ptr
A smart pointer wrapping mutable Expression instances.
virtual SequenceType::Ptr staticType() const =0
UntypedAtomicConverter for ArgumentReference, if needed.
static const EmptySequenceType::Ptr Empty
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
The QXmlName class represents the name of an XML node, in an efficient, namespace-aware way...
Definition: qxmlname.h:58
virtual Properties properties() const
static const AtomicType::Ptr numeric
virtual ItemType::Ptr contextItemType() const =0
The static type of the context item.
static const SequenceType::Ptr EBV
Casts every item in a sequence obtained from evaluating an Expression, to a requested atomic type...
static QString wrongType(const NamePool::Ptr &np, const ItemType::Ptr &reqType, const ItemType::Ptr &opType)
Centralizes a message-string to reduce work for translators and increase consistency.
The QFlags class provides a type-safe way of storing OR-combinations of enum values.
Definition: qglobal.h:2313
virtual ItemType::Ptr itemType() const =0
void wrapExpressionWith(const SourceLocationReflection *const existingNode, const QExplicitlySharedDataPointer< Expression > &newNode)
Ensures source locations are handled in such a manner that existingNode wraps newNode.
bool is(const ID id) const
static bool promotionPossible(const ItemType::Ptr &fromType, const ItemType::Ptr &toType, const StaticContext::Ptr &context)
Whether the focus should be checked or not.
#define Q_FUNC_INFO
Definition: qglobal.h:1871

◆ wrongType()

QString TypeChecker::wrongType ( const NamePool::Ptr np,
const ItemType::Ptr reqType,
const ItemType::Ptr opType 
)
inlinestaticprivate

Centralizes a message-string to reduce work for translators and increase consistency.

Definition at line 59 of file qtypechecker.cpp.

Referenced by verifyType().

62 {
63  return QtXmlPatterns::tr("Required type is %1, but %2 was found.")
64  .arg(formatType(np, reqType), formatType(np, opType));
65 }
QString formatType(const NamePool::Ptr &np, const T &type)
Formats ItemType and SequenceType.

The documentation for this class was generated from the following files: