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

source code of qtxmlpatterns/src/xmlpatterns/expr/qtemplate.cpp