Change copyrights from Nokia to Digia
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / expr / qexpressionfactory.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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"
49 #include "qgenericstaticcontext_p.h"
50 #include "qoperandsiterator_p.h"
51 #include "qoptimizationpasses_p.h"
52 #include "qparsercontext_p.h"
53 #include "qpath_p.h"
54 #include "qquerytransformparser_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
62 QT_BEGIN_NAMESPACE
63
64 namespace QPatternist {
65
66 /**
67  * @short The entry point to the parser.
68  *
69  * @param info supplies the information the parser & scanner
70  * needs to create expressions. The created expression, if everything
71  * succeeds, can be retrieved via the object @p info points to.
72  * @returns non-negative if the parser fails.
73  * @see ExpressionFactory::createExpression()
74  */
75 extern int XPathparse(QPatternist::ParserContext *const info);
76
77 Expression::Ptr ExpressionFactory::createExpression(const QString &expr,
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
108 Expression::Ptr ExpressionFactory::createExpression(QIODevice *const device,
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
128 Expression::Ptr ExpressionFactory::createExpression(const Tokenizer::Ptr &tokenizer,
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
144     OptimizationPasses::Coordinator::init();
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."),
165                        ReportContext::XPST0003,
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)),
203                                ReportContext::XTSE0650,
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. */
240             processTreePass(typeCheck, UserFunctionTypeCheck);
241             pDebug() << "------------------------------";
242
243             pDebug() << "-----      User Function Compress      -----";
244             const Expression::Ptr comp(typeCheck->compress(effectiveContext));
245             (*it)->setBody(comp);
246             processTreePass(comp, UserFunctionCompression);
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));
272             processTreePass(nev, GlobalVariableTypeCheck);
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         {
386             const QXmlName nameModeAll(QXmlName(StandardNamespaces::InternalXSLT,
387                                                 StandardLocalNames::all));
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. -----";
410         processTreePass(result, QueryBodyInitial);
411         pDebug() << "------------------------------";
412
413         pDebug() << "-----     Type Check     -----";
414         registerLastPath(result);
415         result->rewrite(result, result->typeCheck(context, requiredType), context);
416         processTreePass(result, QueryBodyTypeCheck);
417         pDebug() << "------------------------------";
418
419         pDebug() << "-----      Compress      -----";
420         result->rewrite(result, result->compress(context), context);
421         processTreePass(result, QueryBodyCompression);
422         pDebug() << "------------------------------";
423     }
424
425     return result;
426 }
427
428 void ExpressionFactory::registerLastPath(const Expression::Ptr &operand)
429 {
430     OperandsIterator it(operand, OperandsIterator::IncludeParent);
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
445 void ExpressionFactory::processTreePass(const Expression::Ptr &,
446                                         const CompilationStage)
447 {
448 }
449
450 void ExpressionFactory::processTemplateRule(const Expression::Ptr &body,
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
461 void ExpressionFactory::processNamedTemplate(const QXmlName &name,
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
472 QT_END_NAMESPACE
473