DynamicContext::Ptr UserFunctionCallsite::bindVariables(const DynamicContext::Ptr &context) const { const DynamicContext::Ptr stackContext(context->createStack()); Q_ASSERT(stackContext); const Expression::List::const_iterator end(m_operands.constEnd()); Expression::List::const_iterator it(m_operands.constBegin()); VariableSlotID slot = m_expressionSlotOffset; for(; it != end; ++it) { stackContext->setExpressionVariable(slot, Expression::Ptr(new DynamicContextStore(*it, context))); ++slot; } return stackContext; }
DynamicContext::Ptr Template::createContext(const TemplateInvoker *const invoker, const DynamicContext::Ptr &context, const bool isCallTemplate) const { Q_ASSERT(invoker); Q_ASSERT(context); /* We have: * - xsl:params in the target template (if any) which may provide * default values. * - xsl:with-params in the caller (if any) which provides values. * * We need to, for each parameter: * - If the called template provides no default value and the caller * has no value, it's an error * - If the called template has a default value and the caller provides * none, it should be used * - In any case the caller provides a value, it needs to be used. * * Problems to look out for: * * - Each xsl:param is in scope for the subsequent xsl:params. Hence, * the evaluation of one xsl:param can depend on another xsl:param, * and so on * - The focus for xsl:params is different from the focus for * the xsl:with-params * - The xsl:with-params are not in scope for the xsl:params. */ WithParam::Hash withParams(invoker->withParams()); /** * Parameters or not, we must in any case create a new stack frame * for the template invocation since otherwise we will trash our existing * variables. Hence it's as with calling user functions. * * This is especially reproducible with recursive functions. */ DynamicContext::Ptr newStack(context->createStack()); /* We have no parameters, and we have no further error checking to * do in the case of not being xsl:apply-templates, so we need to do nothing. */ if(templateParameters.isEmpty() && (!isCallTemplate || withParams.isEmpty())) return newStack; const DynamicContext::TemplateParameterHash hashedParams(parametersAsHash()); DynamicContext::TemplateParameterHash sewnTogether(hashedParams); const DynamicContext::TemplateParameterHash::iterator end(sewnTogether.end()); for(DynamicContext::TemplateParameterHash::iterator it(sewnTogether.begin()); it != end; ++it) { Expression::Ptr ¶m = it.value(); WithParam::Ptr &withParam = withParams[it.key()]; if(withParam) param = Expression::Ptr(new DynamicContextStore(withParam->sourceExpression(), context)); else if(!param) { /* Ops, no xsl:with-param and no default value to cover up for it. */ context->error(QtXmlPatterns::tr("The parameter %1 is required, but no corresponding %2 is supplied.") .arg(formatKeyword(context->namePool(), it.key()), formatKeyword(QLatin1String("xsl:with-param"))), ReportContext::XTSE0690, this); } } if(isCallTemplate) { /* Find xsl:with-param that has no corresponding xsl:param. */ /* Optimization: candidate for threading? */ const WithParam::Hash::const_iterator end(withParams.constEnd()); for(WithParam::Hash::const_iterator it(withParams.constBegin()); it != end; ++it) { if(!hashedParams.contains(it.key())) raiseXTSE0680(context, it.key(), this); } } newStack->templateParameterStore() = sewnTogether; return newStack; }