private void PrecompileProtoTemplatesHeaders()
{
// All global variables should be in scoupe here.
List<VarPar> paramWithCalls = null;
Dictionary<VarPar, Template> paramToTemplate = null;
Dictionary<VarPar, QilFunction> paramToFunction = null;
foreach (ProtoTemplate tmpl in _compiler.AllTemplates)
{
Debug.Assert(tmpl != null && tmpl.Function == null);
Debug.Assert(tmpl.NodeType == XslNodeType.AttributeSet || tmpl.NodeType == XslNodeType.Template);
QilList args = _f.FormalParameterList();
XslFlags flags = !IsDebug ? tmpl.Flags : XslFlags.FullFocus;
QilList nsList = EnterScope(tmpl);
if ((flags & XslFlags.Current) != 0)
{
args.Add(CreateXslParam(CloneName(_nameCurrent), T.NodeNotRtf));
}
if ((flags & XslFlags.Position) != 0)
{
args.Add(CreateXslParam(CloneName(_namePosition), T.DoubleX));
}
if ((flags & XslFlags.Last) != 0)
{
args.Add(CreateXslParam(CloneName(_nameLast), T.DoubleX));
}
if (IsDebug && nsList != null)
{
// AttributeSet doesn't need this logic because: 1) it doesn't have args; 2) we merge them.
// SimplifiedStylesheet has nsList == null as well.
QilParameter ns = CreateXslParam(CloneName(_nameNamespaces), T.NamespaceS);
ns.DefaultValue = GetNsVar(nsList);
args.Add(ns);
}
Template template = tmpl as Template;
if (template != null)
{
Debug.Assert(tmpl.NodeType == XslNodeType.Template);
CheckSingletonFocus();
_funcFocus.StartFocus(args, flags);
for (int i = 0; i < tmpl.Content.Count; i++)
{
XslNode node = tmpl.Content[i];
if (node.NodeType == XslNodeType.Text)
{
// NOTE: We should take care of a bizarre case when xsl:param comes after TextCtor:
// <xsl:template match="/" xml:space="preserve"> <xsl:param name="par"/>
continue;
}
if (node.NodeType == XslNodeType.Param)
{
VarPar xslPar = (VarPar)node;
EnterScope(xslPar);
if (_scope.IsLocalVariable(xslPar.Name.LocalName, xslPar.Name.NamespaceUri))
{
ReportError(/*[XT0580]*/SR.Xslt_DupLocalVariable, xslPar.Name.QualifiedName);
}
QilParameter param = CreateXslParam(xslPar.Name, ChooseBestType(xslPar));
if (IsDebug)
{
param.Annotation = xslPar;
// Actual compilation will happen in CompileProtoTemplate()
}
else
{
if ((xslPar.DefValueFlags & XslFlags.HasCalls) == 0)
{
param.DefaultValue = CompileVarParValue(xslPar);
}
else
{
// We can't compile param default value here because it contains xsl:call-template and
// we will not be able to compile any calls befor we finish with all headers
// So we compile this default value as a call to helper function. Now we create header for this function
// and preserve this param in paramWithCall list. Later in this function we finaly compile all preserved
// parameters and set resulted default values as helper function definition.
QilList paramFormal = _f.FormalParameterList();
QilList paramActual = _f.ActualParameterList();
for (int j = 0; j < args.Count; j++)
{
QilParameter formal = _f.Parameter(args[j].XmlType);
{
formal.DebugName = ((QilParameter)args[j]).DebugName;
formal.Name = CloneName(((QilParameter)args[j]).Name);
SetLineInfo(formal, args[j].SourceLine);
}
paramFormal.Add(formal);
paramActual.Add(args[j]);
}
// Param doesn't know what implicit args it needs, so we pass all implicit args that was passed to its template.
// let's reflect this fact in parans FocusFlags:
xslPar.Flags |= (template.Flags & XslFlags.FocusFilter);
QilFunction paramFunc = _f.Function(paramFormal,
_f.Boolean((xslPar.DefValueFlags & XslFlags.SideEffects) != 0),
ChooseBestType(xslPar)
);
paramFunc.SourceLine = SourceLineInfo.NoSource;
paramFunc.DebugName = "<xsl:param name=\"" + xslPar.Name.QualifiedName + "\">";
param.DefaultValue = _f.Invoke(paramFunc, paramActual);
// store VarPar here to compile it on next pass:
if (paramWithCalls == null)
{
paramWithCalls = new List<VarPar>();
paramToTemplate = new Dictionary<VarPar, Template>();
paramToFunction = new Dictionary<VarPar, QilFunction>();
}
paramWithCalls.Add(xslPar);
paramToTemplate.Add(xslPar, template);
paramToFunction.Add(xslPar, paramFunc);
}
}
SetLineInfo(param, xslPar.SourceLine);
ExitScope();
_scope.AddVariable(xslPar.Name, param);
args.Add(param);
}
else
{
break;
}
}
_funcFocus.StopFocus();
}
ExitScope();
tmpl.Function = _f.Function(args,
_f.Boolean((tmpl.Flags & XslFlags.SideEffects) != 0),
tmpl is AttributeSet ? T.AttributeS : T.NodeNotRtfS
);
tmpl.Function.DebugName = tmpl.GetDebugName();
Debug.Assert((template != null) == (tmpl.SourceLine != null), "Templates must have line information, and attribute sets must not");
SetLineInfo(tmpl.Function, tmpl.SourceLine ?? SourceLineInfo.NoSource);
_functions.Add(tmpl.Function);
} // foreach (ProtoTemplate tmpl in compiler.AllTemplates)
// Finish compiling postponed parameters (those having calls in their default values)
if (paramWithCalls != null)
{
Debug.Assert(!IsDebug, "In debug mode we don't generate parumWithCalls functions. Otherwise focus flags should be adjusted");
foreach (VarPar par in paramWithCalls)
{
Template tmpl = paramToTemplate[par];
QilFunction func = paramToFunction[par];
CheckSingletonFocus();
_funcFocus.StartFocus(func.Arguments, par.Flags);
EnterScope(tmpl);
EnterScope(par);
foreach (QilParameter arg in func.Arguments)
{
_scope.AddVariable(arg.Name, arg);
}
func.Definition = CompileVarParValue(par);
SetLineInfo(func.Definition, par.SourceLine);
ExitScope();
ExitScope();
_funcFocus.StopFocus();
_functions.Add(func);
}
}
}