Qt 4.8
qexpressionfactory.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QBuffer>
43 #include <QByteArray>
44 
45 #include "qcalltemplate_p.h"
46 #include "qcommonsequencetypes_p.h"
47 #include "qdebug_p.h"
48 #include "qexpression_p.h"
50 #include "qoperandsiterator_p.h"
51 #include "qoptimizationpasses_p.h"
52 #include "qparsercontext_p.h"
53 #include "qpath_p.h"
55 #include "qstaticfocuscontext_p.h"
56 #include "qtokenrevealer_p.h"
57 #include "qxquerytokenizer_p.h"
58 #include "qxslttokenizer_p.h"
59 
60 #include "qexpressionfactory_p.h"
61 
63 
64 namespace QPatternist {
65 
75 extern int XPathparse(QPatternist::ParserContext *const info);
76 
78  const StaticContext::Ptr &context,
79  const QXmlQuery::QueryLanguage lang,
80  const SequenceType::Ptr &requiredType,
81  const QUrl &queryURI,
82  const QXmlName &initialTemplateName)
83 {
84  if(lang == QXmlQuery::XSLT20)
85  {
86  QByteArray query(expr.toUtf8());
87  QBuffer buffer(&query);
88  buffer.open(QIODevice::ReadOnly);
89 
90  return createExpression(&buffer,
91  context,
92  lang,
93  requiredType,
94  queryURI,
95  initialTemplateName);
96  }
97  else
98  {
99  return createExpression(Tokenizer::Ptr(new XQueryTokenizer(expr, queryURI)),
100  context,
101  lang,
102  requiredType,
103  queryURI,
104  initialTemplateName);
105  }
106 }
107 
109  const StaticContext::Ptr &context,
110  const QXmlQuery::QueryLanguage lang,
111  const SequenceType::Ptr &requiredType,
112  const QUrl &queryURI,
113  const QXmlName &initialTemplateName)
114 {
115  Q_ASSERT(device);
116  Q_ASSERT(device->isReadable());
117 
118  Tokenizer::Ptr tokenizer;
119 
120  if(lang == QXmlQuery::XSLT20)
121  tokenizer = Tokenizer::Ptr(new XSLTTokenizer(device, queryURI, context, context->namePool()));
122  else
123  tokenizer = Tokenizer::Ptr(new XQueryTokenizer(QString::fromUtf8(device->readAll()), queryURI));
124 
125  return createExpression(tokenizer, context, lang, requiredType, queryURI, initialTemplateName);
126 }
127 
129  const StaticContext::Ptr &context,
130  const QXmlQuery::QueryLanguage lang,
131  const SequenceType::Ptr &requiredType,
132  const QUrl &queryURI,
133  const QXmlName &initialTemplateName)
134 {
135  Q_ASSERT(context);
136  Q_ASSERT(requiredType);
137  Q_ASSERT(queryURI.isValid());
138 
139  Tokenizer::Ptr effectiveTokenizer(tokenizer);
140 #ifdef Patternist_DEBUG
141  effectiveTokenizer = Tokenizer::Ptr(new TokenRevealer(queryURI, tokenizer));
142 #endif
143 
145 
146  const ParserContext::Ptr info(new ParserContext(context, lang, effectiveTokenizer.data()));
147  info->initialTemplateName = initialTemplateName;
148 
149  effectiveTokenizer->setParserContext(info);
150 
151  const int bisonRetval = XPathparse(info.data());
152 
153  Q_ASSERT_X(bisonRetval == 0, Q_FUNC_INFO,
154  "We shouldn't be able to get an error, because we throw exceptions.");
155  Q_UNUSED(bisonRetval); /* Needed when not compiled in debug mode, since bisonRetval won't
156  * be used in the Q_ASSERT_X above. */
157 
158  Expression::Ptr result(info->queryBody);
159 
160  if(!result)
161  {
162  context->error(QtXmlPatterns::tr("A library module cannot be evaluated "
163  "directly. It must be imported from a "
164  "main module."),
166  QSourceLocation(queryURI, 1, 1));
167  }
168 
169  /* Optimization: I think many things are done in the wrong order below. We
170  * probably want everything typechecked before compressing, since we can
171  * have references all over the place(variable references, template
172  * invocations, function callsites). This could even be a source to bugs.
173  */
174 
175  /* Here, we type check user declared functions and global variables. This
176  * means that variables and functions that are not used are type
177  * checked(which they otherwise wouldn't have been), and those which are
178  * used, are type-checked twice, unfortunately. */
179 
180  const bool hasExternalFocus = context->contextItemType();
181 
182  if(lang == QXmlQuery::XSLT20)
183  {
184  /* Bind xsl:call-template instructions to their template bodies.
185  *
186  * We do this before type checking and compressing them, because a
187  * CallTemplate obviously needs its template before being compressed.
188  *
189  * Also, we do this before type checking and compressing user
190  * functions, since they can contain template call sites.
191  */
192  for(int i = 0; i < info->templateCalls.count(); ++i)
193  {
194  CallTemplate *const site = info->templateCalls.at(i)->as<CallTemplate>();
195  const QXmlName targetName(site->name());
196  const Template::Ptr t(info->namedTemplates.value(targetName));
197 
198  if(t)
199  site->setTemplate(t);
200  else
201  {
202  context->error(QtXmlPatterns::tr("No template by name %1 exists.").arg(formatKeyword(context->namePool(), targetName)),
204  site);
205  }
206  }
207  }
208 
209  /* Type check and compress user functions. */
210  {
211  const UserFunction::List::const_iterator end(info->userFunctions.constEnd());
212  UserFunction::List::const_iterator it(info->userFunctions.constBegin());
213 
214  /* If the query has a focus(which is common, in the case of a
215  * stylesheet), we must ensure that the focus isn't visible in the
216  * function body. */
217  StaticContext::Ptr effectiveContext;
218 
219  if(hasExternalFocus)
220  {
221  effectiveContext = StaticContext::Ptr(new StaticFocusContext(ItemType::Ptr(),
222  context));
223  }
224  else
225  effectiveContext = context;
226 
227  for(; it != end; ++it)
228  {
229  pDebug() << "----- User Function Typecheck -----";
230  registerLastPath((*it)->body());
231 
232  /* We will most likely call body()->typeCheck() again, once for
233  * each callsite. That is, it will be called from
234  * UserFunctionCallsite::typeCheck(), which will be called
235  * indirectly when we check the query body. */
236  const Expression::Ptr typeCheck((*it)->body()->typeCheck(effectiveContext,
237  (*it)->signature()->returnType()));
238  /* We don't have to call (*it)->setBody(typeCheck) here since it's
239  * only used directly below. */
241  pDebug() << "------------------------------";
242 
243  pDebug() << "----- User Function Compress -----";
244  const Expression::Ptr comp(typeCheck->compress(effectiveContext));
245  (*it)->setBody(comp);
247  pDebug() << "------------------------------";
248  }
249  }
250 
251  /* Type check and compress global variables. */
252  {
253  const VariableDeclaration::Stack::const_iterator vend(info->variables.constEnd());
254  VariableDeclaration::Stack::const_iterator vit(info->variables.constBegin());
255  for(; vit != vend; ++vit)
256  {
257  Q_ASSERT(*vit);
258  /* This is a bit murky, the global variable will have it
259  * Expression::typeCheck() function called from all its references,
260  * but we also want to check it here globally, so we do
261  * typechecking using a proper focus. */
262  if((*vit)->type == VariableDeclaration::ExternalVariable)
263  continue;
264 
265  pDebug() << "----- Global Variable Typecheck -----";
266  Q_ASSERT((*vit)->expression());
267  /* We supply ZeroOrMoreItems, meaning the variable can evaluate to anything. */
268  // FIXME which is a source to bugs
269  // TODO What about compressing variables?
270  const Expression::Ptr
271  nev((*vit)->expression()->typeCheck(context, CommonSequenceTypes::ZeroOrMoreItems));
273  pDebug() << "------------------------------";
274  }
275  }
276 
277  /* Do all tests specific to XSL-T. */
278  if(lang == QXmlQuery::XSLT20)
279  {
280  /* Type check and compress named templates. */
281  {
282  pDebug() << "Have " << info->namedTemplates.count() << "named templates";
283 
284  QMutableHashIterator<QXmlName, Template::Ptr> it(info->namedTemplates);
285 
286  while(it.hasNext())
287  {
288  it.next();
289  processNamedTemplate(it.key(), it.value()->body, TemplateInitial);
290 
291  it.value()->body = it.value()->body->typeCheck(context, CommonSequenceTypes::ZeroOrMoreItems);
292  processNamedTemplate(it.key(), it.value()->body, TemplateTypeCheck);
293 
294  it.value()->body = it.value()->body->compress(context);
295  processNamedTemplate(it.key(), it.value()->body, TemplateCompress);
296 
297  it.value()->compileParameters(context);
298  }
299  }
300 
301  /* Type check and compress template rules. */
302  {
303  QHashIterator<QXmlName, TemplateMode::Ptr> it(info->templateRules);
304 
305  /* Since a pattern can exist of AxisStep, its typeCheck() stage
306  * requires a focus. In the case that we're invoked with a name but
307  * no focus, this will yield a compile error, unless we declare a
308  * focus manually. This only needs to be done for the pattern
309  * expression, since the static type of the pattern is used as the
310  * static type for the focus of the template body. */
311  StaticContext::Ptr patternContext;
312  if(hasExternalFocus)
313  patternContext = context;
314  else
315  patternContext = StaticContext::Ptr(new StaticFocusContext(BuiltinTypes::node, context));
316 
317  /* For each template pattern. */
318  while(it.hasNext())
319  {
320  it.next();
321  const TemplateMode::Ptr &mode = it.value();
322  const int len = mode->templatePatterns.count();
323  TemplatePattern::ID currentTemplateID = -1;
324  bool hasDoneItOnce = false;
325 
326  /* For each template pattern. */
327  for(int i = 0; i < len; ++i)
328  {
329  /* We can't use references for these two members, since we
330  * assign to them. */
331  const TemplatePattern::Ptr &pattern = mode->templatePatterns.at(i);
332  Expression::Ptr matchPattern(pattern->matchPattern());
333 
334  processTemplateRule(pattern->templateTarget()->body,
335  pattern, mode->name(), TemplateInitial);
336 
337  matchPattern = matchPattern->typeCheck(patternContext, CommonSequenceTypes::ZeroOrMoreItems);
338  matchPattern = matchPattern->compress(patternContext);
339  pattern->setMatchPattern(matchPattern);
340 
341  if(currentTemplateID == -1 && hasDoneItOnce)
342  {
343  currentTemplateID = pattern->id();
344  continue;
345  }
346  else if(currentTemplateID == pattern->id() && hasDoneItOnce)
347  {
348  hasDoneItOnce = false;
349  continue;
350  }
351 
352  hasDoneItOnce = true;
353  currentTemplateID = pattern->id();
354  Expression::Ptr body(pattern->templateTarget()->body);
355 
356  /* Patterns for a new template has started, we must
357  * deal with the body & parameters. */
358  {
359  /* TODO type is wrong, it has to be the union of all
360  * patterns. */
361  const StaticContext::Ptr focusContext(new StaticFocusContext(matchPattern->staticType()->itemType(),
362  context));
363  body = body->typeCheck(focusContext, CommonSequenceTypes::ZeroOrMoreItems);
364 
365  pattern->templateTarget()->compileParameters(focusContext);
366  }
367 
368  processTemplateRule(body, pattern, mode->name(), TemplateTypeCheck);
369 
370  body = body->compress(context);
371 
372  pattern->templateTarget()->body = body;
373  processTemplateRule(body, pattern, mode->name(), TemplateCompress);
374  }
375 
376  mode->finalize();
377  }
378  }
379 
380  /* Add templates in mode #all to all other modes.
381  *
382  * We do this after the templates has been typechecked and compressed,
383  * since otherwise it will be done N times for the built-in templates,
384  * where N is the count of different templates, instead of once. */
385  {
388  const TemplateMode::Ptr &modeAll = info->templateRules[nameModeAll];
389 
390  Q_ASSERT_X(modeAll, Q_FUNC_INFO,
391  "We should at least have the builtin templates.");
392  QHashIterator<QXmlName, TemplateMode::Ptr> it(info->templateRules);
393 
394  while(it.hasNext())
395  {
396  it.next();
397 
398  /* Don't add mode #all to mode #all. */
399  if(it.key() == nameModeAll)
400  continue;
401 
402  it.value()->addMode(modeAll);
403  }
404  }
405  }
406 
407  /* Type check and compress the query body. */
408  {
409  pDebug() << "----- Initial AST build. -----";
411  pDebug() << "------------------------------";
412 
413  pDebug() << "----- Type Check -----";
414  registerLastPath(result);
415  result->rewrite(result, result->typeCheck(context, requiredType), context);
417  pDebug() << "------------------------------";
418 
419  pDebug() << "----- Compress -----";
420  result->rewrite(result, result->compress(context), context);
422  pDebug() << "------------------------------";
423  }
424 
425  return result;
426 }
427 
429 {
431  Expression::Ptr next(it.next());
432 
433  while(next)
434  {
435  if(next->is(Expression::IDPath))
436  {
437  next->as<Path>()->setLast();
438  next = it.skipOperands();
439  }
440  else
441  next = it.next();
442  }
443 }
444 
446  const CompilationStage)
447 {
448 }
449 
451  const TemplatePattern::Ptr &pattern,
452  const QXmlName &mode,
453  const TemplateCompilationStage stage)
454 {
455  Q_UNUSED(body);
456  Q_UNUSED(pattern);
457  Q_UNUSED(mode);
458  Q_UNUSED(stage);
459 }
460 
462  const Expression::Ptr &tree,
463  const TemplateCompilationStage stage)
464 {
465  Q_UNUSED(name);
466  Q_UNUSED(tree);
467  Q_UNUSED(stage);
468 }
469 
470 } // namespace QPatternist
471 
473 
bool isValid() const
Returns true if the URL is valid; otherwise returns false.
Definition: qurl.cpp:4303
static mach_timebase_info_data_t info
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
A StaticContext that carries a specified static type for the context item, but otherwise delegates to...
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
Definition: qiodevice.cpp:544
Delegates another Tokenizer, and while doing so prints the tokens it delivers to stderr.
QString formatKeyword(const QString &keyword)
static const SequenceType::Ptr ZeroOrMoreItems
#define it(className, varName)
QueryLanguage
Specifies whether you want QXmlQuery to interpret the input to setQuery() as an XQuery or as an XSLT ...
Definition: qxmlquery.h:82
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
Implements the path expression, containing two steps, such as in html/body.
Definition: qpath_p.h:72
Tokenizes XSL-T 2.0 documents.
Contains macros for debugging.
The QBuffer class provides a QIODevice interface for a QByteArray.
Definition: qbuffer.h:57
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
QXmlName name() const
Definition: qcallsite.cpp:53
Expression::Ptr next()
Returns the current Expression and advances the iterator.
void setTemplate(const Template::Ptr &templ)
friend class const_iterator
Definition: qlist.h:264
T * data() const
Returns a pointer to the shared data object.
Definition: qshareddata.h:145
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
const char * name
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
The namespace for the internal API of QtXmlPatterns.
The QSourceLocation class identifies a location in a resource by URI, line, and column.
A hand-written tokenizer which tokenizes XQuery 1.0 & XPath 2.0, and delivers tokens to the Bison gen...
Contains data used when parsing and tokenizing.
static const AnyNodeType::Ptr node
#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 void processTreePass(const Expression::Ptr &tree, const CompilationStage stage)
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
virtual Expression::Ptr createExpression(QIODevice *const device, const StaticContext::Ptr &context, const QXmlQuery::QueryLanguage lang, const SequenceType::Ptr &requiredType, const QUrl &queryURI, const QXmlName &initialTemplateName)
const T * const_iterator
The QVector::const_iterator typedef provides an STL-style const iterator for QVector and QStack...
Definition: qvector.h:245
QExplicitlySharedDataPointer< Tokenizer > Ptr
Definition: qtokenizer_p.h:163
QExplicitlySharedDataPointer< StaticContext > Ptr
int XPathparse(QPatternist::ParserContext *const info)
The entry point to the parser.
static const KeyPair *const end
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
virtual void processTemplateRule(const Expression::Ptr &body, const TemplatePattern::Ptr &pattern, const QXmlName &mode, const TemplateCompilationStage stage)
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static void registerLastPath(const Expression::Ptr &operand)
Implements xsl:call-template.
virtual void processNamedTemplate(const QXmlName &name, const Expression::Ptr &tree, const TemplateCompilationStage stage)
A helper class that iterates a tree of Expression instances. It is not a sub-class of QAbstractXmlFor...
virtual Expression::Ptr createExpression(const QString &expr, const StaticContext::Ptr &context, const QXmlQuery::QueryLanguage lang, const SequenceType::Ptr &requiredType, const QUrl &queryURI, const QXmlName &initialTemplateName)
QNoDebug pDebug()
Definition: qdebug_p.h:99
#define Q_FUNC_INFO
Definition: qglobal.h:1871