ead13ec9ed40f5101aa0e893243a5a95ab416e9c
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / expr / qtemplate.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdynamiccontextstore_p.h"
43 #include "qpatternistlocale_p.h"
44
45 #include "qtemplate_p.h"
46
47 QT_BEGIN_NAMESPACE
48
49 using namespace QPatternist;
50
51 const SourceLocationReflection* Template::actualReflection() const
52 {
53     return this;
54 }
55
56 DynamicContext::TemplateParameterHash Template::parametersAsHash() const
57 {
58     DynamicContext::TemplateParameterHash retval;
59     const int len = templateParameters.count();
60
61     for(int i = 0; i < len; ++i)
62     {
63         const VariableDeclaration::Ptr &at = templateParameters.at(i);
64         retval.insert(at->name, at->expression());
65     }
66
67     return retval;
68 }
69
70 void Template::raiseXTSE0680(const ReportContext::Ptr &context,
71                              const QXmlName &name,
72                              const SourceLocationReflection *const reflection)
73 {
74     context->error(QtXmlPatterns::tr("The parameter %1 is passed, but no corresponding %2 exists.")
75                                      .arg(formatKeyword(context->namePool(), name),
76                                           formatKeyword(QLatin1String("xsl:param"))),
77                    ReportContext::XTSE0680,
78                    reflection);
79 }
80
81 DynamicContext::Ptr Template::createContext(const TemplateInvoker *const invoker,
82                                             const DynamicContext::Ptr &context,
83                                             const bool isCallTemplate) const
84 {
85     Q_ASSERT(invoker);
86     Q_ASSERT(context);
87
88     /* We have:
89      * - xsl:params in the target template (if any) which may provide
90      *   default values.
91      * - xsl:with-params in the caller (if any) which provides values.
92      *
93      * We need to, for each parameter:
94      * - If the called template provides no default value and the caller
95      *   has no value, it's an error
96      * - If the called template has a default value and the caller provides
97      *   none, it should be used
98      * - In any case the caller provides a value, it needs to be used.
99      *
100      * Problems to look out for:
101      *
102      * - Each xsl:param is in scope for the subsequent xsl:params. Hence,
103      *   the evaluation of one xsl:param can depend on another xsl:param,
104      *   and so on
105      * - The focus for xsl:params is different from the focus for
106      *   the xsl:with-params
107      * - The xsl:with-params are not in scope for the xsl:params.
108      */
109
110     WithParam::Hash withParams(invoker->withParams());
111
112     /**
113      * Parameters or not, we must in any case create a new stack frame
114      * for the template invocation since otherwise we will trash our existing
115      * variables. Hence it's as with calling user functions.
116      *
117      * This is especially reproducible with recursive functions.
118      */
119     DynamicContext::Ptr newStack(context->createStack());
120
121     /* We have no parameters, and we have no further error checking to
122      * do in the case of not being xsl:apply-templates, so we need to do nothing. */
123     if(templateParameters.isEmpty() && (!isCallTemplate || withParams.isEmpty()))
124         return newStack;
125
126     const DynamicContext::TemplateParameterHash hashedParams(parametersAsHash());
127     DynamicContext::TemplateParameterHash sewnTogether(hashedParams);
128
129     const DynamicContext::TemplateParameterHash::iterator end(sewnTogether.end());
130
131     for(DynamicContext::TemplateParameterHash::iterator it(sewnTogether.begin());
132         it != end;
133         ++it)
134     {
135         Expression::Ptr &param = it.value();
136
137         WithParam::Ptr &withParam = withParams[it.key()];
138
139         if(withParam)
140             param = Expression::Ptr(new DynamicContextStore(withParam->sourceExpression(), context));
141         else if(!param)
142         {
143             /* Ops, no xsl:with-param and no default value to cover up for it.
144              */
145             context->error(QtXmlPatterns::tr("The parameter %1 is required, but no corresponding %2 is supplied.")
146                                              .arg(formatKeyword(context->namePool(), it.key()),
147                                                   formatKeyword(QLatin1String("xsl:with-param"))),
148                            ReportContext::XTSE0690,
149                            this);
150         }
151     }
152
153     if(isCallTemplate)
154     {
155         /* Find xsl:with-param that has no corresponding xsl:param. */
156         /* Optimization: candidate for threading? */
157
158         const WithParam::Hash::const_iterator end(withParams.constEnd());
159
160         for(WithParam::Hash::const_iterator it(withParams.constBegin()); it != end; ++it)
161         {
162             if(!hashedParams.contains(it.key()))
163                 raiseXTSE0680(context, it.key(), this);
164         }
165
166     }
167
168     newStack->templateParameterStore() = sewnTogether;
169     return newStack;
170 }
171
172 void Template::compileParameters(const StaticContext::Ptr &context)
173 {
174     Q_ASSERT(context);
175
176     const int len = templateParameters.count();
177
178     for(int i = 0; i < len; ++i)
179     {
180         const VariableDeclaration::Ptr &at = templateParameters.at(i);
181
182         /* If our value is required, we don't have a default value. */
183         if(at->expression())
184         {
185             // TODO why do we pass in its own type here?
186             at->setExpression(at->expression()->typeCheck(context, at->expression()->staticType()));
187
188             at->setExpression(at->expression()->compress(context));
189         }
190     }
191 }
192
193 Expression::Properties Template::properties() const
194 {
195     return Expression::DisableElimination; /* We're having issues with recursion detection, so this path currently loops infintely. */
196
197     Expression::Properties collect(body->properties());
198
199     VariableDeclaration::List::const_iterator end(templateParameters.constEnd());
200
201     for(VariableDeclaration::List::const_iterator it(templateParameters.constBegin());
202         it != end;
203         ++it)
204     {
205         if((*it)->expression())
206             collect |= (*it)->expression()->properties();
207     }
208
209     // TODO simplify.
210     return collect & (Expression::RequiresFocus | Expression::IsEvaluated | Expression::DisableElimination);
211 }
212
213 Expression::Properties Template::dependencies() const
214 {
215     return Expression::DisableElimination; /* We're having issues with recursion detection, so this path currently loops infintely. */
216
217     Expression::Properties collect(body->dependencies());
218
219     VariableDeclaration::List::const_iterator end(templateParameters.constEnd());
220
221     for(VariableDeclaration::List::const_iterator it(templateParameters.constBegin());
222         it != end;
223         ++it)
224     {
225         if((*it)->expression())
226             collect |= (*it)->expression()->dependencies();
227     }
228
229     return collect & (Expression::RequiresFocus | Expression::IsEvaluated | Expression::DisableElimination);
230 }
231
232 QT_END_NAMESPACE