View over a Qil name literal.
Don't construct QIL nodes directly; instead, use the QilFactory.
Inheritance: QilLiteral
Beispiel #1
0
 private void SetArg(IList<XslNode> args, int pos, QilName name, QilNode value)
 {
     VarPar varPar;
     if (args.Count <= pos || args[pos].Name != name)
     {
         varPar = AstFactory.WithParam(name);
         args.Insert(pos, varPar);
     }
     else
     {
         varPar = (VarPar)args[pos];
     }
     varPar.Value = value;
 }
Beispiel #2
0
        private QilNode InvokeApplyFunction(StylesheetLevel sheet, QilName mode, IList<XslNode> actualArgs)
        {
            // Here we create function that has one argument for each with-param in apply-templates
            // We have actualArgs -- list of xsl:with-param(name, value)
            // From it we create:
            // invokeArgs -- values to use with QilInvoke
            // formalArgs -- list of iterators to use with QilFunction
            // actualArgs -- modify it to hold iterators (formalArgs) instead of values to ise in invoke generator inside function budy

            XslFlags flags;
            {
                if (!sheet.ModeFlags.TryGetValue(mode, out flags))
                {
                    flags = 0;
                }
                flags |= XslFlags.Current; // Due to recursive nature of Apply(Templates/Imports) we will need current node any way
            }
            actualArgs = AddRemoveImplicitArgs(actualArgs, flags);

            QilList invokeArgs = _f.ActualParameterList();
            QilFunction applyFunction = null;

            // Look at the list of all functions that have been already built.  If a suitable one is found, reuse it.
            List<QilFunction> functionsForMode;
            if (!sheet.ApplyFunctions.TryGetValue(mode, out functionsForMode))
            {
                functionsForMode = sheet.ApplyFunctions[mode] = new List<QilFunction>();
            }

            foreach (QilFunction func in functionsForMode)
            {
                if (FillupInvokeArgs(func.Arguments, actualArgs, /*ref*/invokeArgs))
                {
                    applyFunction = func;
                    break;
                }
            }

            // If a suitable function has not been found, create it
            if (applyFunction == null)
            {
                invokeArgs.Clear();
                // We wasn't able to find suitable function. Let's build new:
                // 1. Function arguments
                QilList formalArgs = _f.FormalParameterList();
                for (int i = 0; i < actualArgs.Count; i++)
                {
                    Debug.Assert(actualArgs[i].NodeType == XslNodeType.WithParam, "All Sorts was removed in CompileSorts()");
                    VarPar withParam = (VarPar)actualArgs[i];

                    // Add actual arg to 'invokeArgs' array. No need to clone it since it must be
                    // a literal or a reference.
                    invokeArgs.Add(withParam.Value);

                    // Create correspondent formal arg
                    QilParameter formalArg = _f.Parameter(i == 0 ? T.NodeNotRtf : withParam.Value.XmlType);
                    formalArg.Name = CloneName(withParam.Name);
                    formalArgs.Add(formalArg);

                    // Change actual arg value to formalArg for reuse in calling built-in templates rules
                    withParam.Value = formalArg;
                }

                // 2. Function header
                applyFunction = _f.Function(formalArgs,
                    _f.Boolean((flags & XslFlags.SideEffects) != 0),
                    T.NodeNotRtfS
                );
                string attMode = (mode.LocalName.Length == 0) ? string.Empty : " mode=\"" + mode.QualifiedName + '"';
                applyFunction.DebugName = (sheet is RootLevel ? "<xsl:apply-templates" : "<xsl:apply-imports") + attMode + '>';
                functionsForMode.Add(applyFunction);
                _functions.Add(applyFunction);

                // 3. Function body
                Debug.Assert(actualArgs[0].Name == _nameCurrent, "Caller should always pass $current as a first argument to apply-* calls.");
                QilIterator current = (QilIterator)formalArgs[0];

                // 3.1 Built-in templates:
                // 3.1.1 loop over content of current element
                QilLoop loopOnContent;
                {
                    QilIterator iChild = _f.For(_f.Content(current));
                    QilNode filter = _f.Filter(iChild, _f.IsType(iChild, T.Content));
                    filter.XmlType = T.ContentS;    // not attribute

                    LoopFocus curLoopSaved = _curLoop;
                    _curLoop.SetFocus(_f.For(filter));

                    /* Prepare actual arguments */
                    // At XSLT 1.0, if a built-in template rule is invoked with parameters, the parameters are not
                    // passed on to any templates invoked by the built-in rule. At XSLT 2.0, these parameters are
                    // passed through the built-in template rule unchanged.

                    // we can't just modify current/position/last of actualArgs in XSLT 2.0 as we tried before, 
                    // becuase flags for apply-import amy now be different then flags for apply-templates, so 
                    // we may need to add some space for additional position/last arguments
                    QilNode body = InvokeApplyFunction(_compiler.Root, mode, /*actualArgs:*/null);
                    if (IsDebug)
                    {
                        body = _f.Sequence(InvokeOnCurrentNodeChanged(), body);
                    }
                    loopOnContent = _curLoop.ConstructLoop(body);
                    _curLoop = curLoopSaved;
                }

                // 3.1.2 switch on type of current node
                QilTernary builtinTemplates = _f.BaseFactory.Conditional(_f.IsType(current, _elementOrDocumentType),
                    loopOnContent,
                    _f.Conditional(_f.IsType(current, _textOrAttributeType),
                        _f.TextCtor(_f.XPathNodeValue(current)),
                        _f.Sequence()
                    )
                );

                // 3.2 Stylesheet templates
                _matcherBuilder.CollectPatterns(sheet, mode);
                applyFunction.Definition = _matcherBuilder.BuildMatcher(current, actualArgs, /*otherwise:*/builtinTemplates);
            }
            return _f.Invoke(applyFunction, invokeArgs);
        }
        public XmlQueryType CheckLiteralQName(QilName node) {
            CheckLiteralValue(node, typeof(QilName));
            // 

            return XmlQueryTypeFactory.QNameX;
        }
Beispiel #4
0
 protected virtual QilNode VisitLiteralQName(QilName n)
 {
     return(VisitChildren(n));
 }
Beispiel #5
0
        private QilGenerator(bool debug)
        {
            _scope = new CompilerScopeManager<QilIterator>();
            _outputScope = new OutputScopeManager();
            _prefixesInUse = new HybridDictionary();
            _f = new XsltQilFactory(new QilFactory(), debug);
            _xpathBuilder = new XPathBuilder((IXPathEnvironment)this);
            _xpathParser = new XPathParser<QilNode>();
            _ptrnBuilder = new XPathPatternBuilder((IXPathEnvironment)this);
            _ptrnParser = new XPathPatternParser();
            _refReplacer = new ReferenceReplacer(_f.BaseFactory);
            _invkGen = new InvokeGenerator(_f, debug);
            _matcherBuilder = new MatcherBuilder(_f, _refReplacer, _invkGen);
            _singlFocus = new SingletonFocus(_f);
            _funcFocus = new FunctionFocus();
            _curLoop = new LoopFocus(_f);
            _strConcat = new QilStrConcatenator(_f);
            _varHelper = new VariableHelper(_f);

            _elementOrDocumentType = T.DocumentOrElement;
            _textOrAttributeType = T.NodeChoice(XmlNodeKindFlags.Text | XmlNodeKindFlags.Attribute);

            _nameCurrent = _f.QName("current", XmlReservedNs.NsXslDebug);
            _namePosition = _f.QName("position", XmlReservedNs.NsXslDebug);
            _nameLast = _f.QName("last", XmlReservedNs.NsXslDebug);
            _nameNamespaces = _f.QName("namespaces", XmlReservedNs.NsXslDebug);
            _nameInit = _f.QName("init", XmlReservedNs.NsXslDebug);

            _formatterCnt = 0;
        }
 protected virtual QilNode VisitLiteralQName(QilName n) { return VisitChildren(n); }
Beispiel #7
0
        /// <summary>
        /// Load an XmlNavigatorFilter that matches only the specified name and types onto the stack.
        /// </summary>
        private void LoadSelectFilter(XmlNodeKindFlags xmlTypes, QilName ndName)
        {
            if (ndName != null)
            {
                // Push NameFilter
                Debug.Assert(xmlTypes == XmlNodeKindFlags.Element);
                _helper.CallGetNameFilter(_helper.StaticData.DeclareNameFilter(ndName.LocalName, ndName.NamespaceUri));
            }
            else
            {
                // Either type cannot be a union, or else it must be >= union of all Content types
                bool isXmlTypeUnion = IsNodeTypeUnion(xmlTypes);
                Debug.Assert(!isXmlTypeUnion || (xmlTypes & XmlNodeKindFlags.Content) == XmlNodeKindFlags.Content);

                if (isXmlTypeUnion)
                {
                    if ((xmlTypes & XmlNodeKindFlags.Attribute) != 0)
                    {
                        // Union includes attributes, so allow all node kinds
                        _helper.CallGetTypeFilter(XPathNodeType.All);
                    }
                    else
                    {
                        // Filter attributes
                        _helper.CallGetTypeFilter(XPathNodeType.Attribute);
                    }
                }
                else
                {
                    // Filter nodes of all but one type
                    _helper.CallGetTypeFilter(QilXmlToXPathNodeType(xmlTypes));
                }
            }
        }
Beispiel #8
0
 private QilName CloneName(QilName name)
 {
     return (QilName)name.ShallowClone(_f.BaseFactory);
 }
Beispiel #9
0
        /// <summary>
        /// Generate boiler-plate code to create an Xml iterator that uses an XmlNavigatorFilter to filter items.
        /// </summary>
        /// <remarks>
        ///     Iterator iter;
        ///     iter.Create(navCtxt, filter [, orSelf] [, navEnd]);
        /// LabelNext:
        ///     if (!iter.MoveNext())
        ///         goto LabelNextCtxt;
        /// </remarks>
        private void CreateFilteredIterator(QilNode ndCtxt, string iterName, Type iterType, MethodInfo methCreate, MethodInfo methNext,
                                                XmlNodeKindFlags kinds, QilName ndName, TriState orSelf, QilNode ndEnd)
        {
            // Iterator iter;
            LocalBuilder locIter = _helper.DeclareLocal(iterName, iterType);

            // iter.Create(navCtxt, filter [, orSelf], [, navEnd]);
            _helper.Emit(OpCodes.Ldloca, locIter);
            NestedVisitEnsureStack(ndCtxt);
            LoadSelectFilter(kinds, ndName);
            if (orSelf != TriState.Unknown)
                _helper.LoadBoolean(orSelf == TriState.True);
            if (ndEnd != null)
                NestedVisitEnsureStack(ndEnd);
            _helper.Call(methCreate);

            GenerateSimpleIterator(typeof(XPathNavigator), locIter, methNext);
        }
Beispiel #10
0
        /// <summary>
        /// Generate boiler-plate code to create an Xml iterator that controls a nested iterator.
        /// </summary>
        /// <remarks>
        ///     Iterator iter;
        ///     iter.Create(filter [, orSelf]);
        ///         ...nested iterator...
        ///     navInput = nestedNested;
        ///     goto LabelCall;
        /// LabelNext:
        ///     navInput = null;
        /// LabelCall:
        ///     switch (iter.MoveNext(navInput)) {
        ///         case IteratorState.NoMoreNodes: goto LabelNextCtxt;
        ///         case IteratorState.NextInputNode: goto LabelNextNested;
        ///     }
        /// </remarks>
        private void CreateContainerIterator(QilUnary ndDod, string iterName, Type iterType, MethodInfo methCreate, MethodInfo methNext,
                                                   XmlNodeKindFlags kinds, QilName ndName, TriState orSelf)
        {
            // Iterator iter;
            LocalBuilder locIter = _helper.DeclareLocal(iterName, iterType);
            Label lblOnEndNested;
            QilLoop ndLoop = (QilLoop)ndDod.Child;
            Debug.Assert(ndDod.NodeType == QilNodeType.DocOrderDistinct && ndLoop != null);

            // iter.Create(filter [, orSelf]);
            _helper.Emit(OpCodes.Ldloca, locIter);
            LoadSelectFilter(kinds, ndName);
            if (orSelf != TriState.Unknown)
                _helper.LoadBoolean(orSelf == TriState.True);
            _helper.Call(methCreate);

            // Generate nested iterator (branch to lblOnEndNested when iteration is complete)
            lblOnEndNested = _helper.DefineLabel();
            StartNestedIterator(ndLoop, lblOnEndNested);
            StartBinding(ndLoop.Variable);
            EndBinding(ndLoop.Variable);
            EndNestedIterator(ndLoop.Variable);
            _iterCurr.Storage = _iterNested.Storage;

            GenerateContainerIterator(ndDod, locIter, lblOnEndNested, methNext, typeof(XPathNavigator));
        }
Beispiel #11
0
 /// <summary>
 /// Serialize literal QName as three separate attributes.
 /// </summary>
 protected override QilNode VisitLiteralQName(QilName value)
 {
     this.writer.WriteAttributeString("name", value.ToString());
     return(value);
 }
Beispiel #12
0
 protected override QilNode VisitLiteralQName(QilName n)
 {
     return(NoReplace(n));
 }
Beispiel #13
0
 public QilParameter Parameter(QilNode defaultValue, QilName name, XmlQueryType t)
 {
     return(_f.Parameter(defaultValue, name, t));
 }
Beispiel #14
0
 private void VerifyXPathQName(QilName qname)
 {
     Debug.Assert(
         _compiler.IsPhantomName(qname) ||
         qname.NamespaceUri == ResolvePrefix(/*ignoreDefaultNs:*/true, qname.Prefix),
         "QilGenerator must resolve the prefix to the same namespace as XsltLoader"
     );
 }
Beispiel #15
0
 /// <summary>
 /// Generate code for QilNodeType.LiteralQName.
 /// </summary>
 protected override QilNode VisitLiteralQName(QilName ndQName)
 {
     _helper.ConstructLiteralQName(ndQName.LocalName, ndQName.NamespaceUri);
     _iterCurr.Storage = StorageDescriptor.Stack(typeof(XmlQualifiedName), false);
     return ndQName;
 }
Beispiel #16
0
 private QilNode AddDebugVariable(QilName name, QilNode value, QilNode content)
 {
     QilIterator var = _f.Let(value);
     var.DebugName = name.ToString();
     return _f.Loop(var, content);
 }
Beispiel #17
0
 public XmlQueryType CheckLiteralQName(QilName node)
 {
     CheckLiteralValue(node, typeof(QilName));
     // BUGBUG: Xslt constructs invalid QNames, so don't check this
     //Check(ValidateNames.ValidateName(node.Prefix, node.LocalName, node.NamespaceUri, XPathNodeType.Element, ValidateNames.Flags.All), node, "QName is not valid");
     return XmlQueryTypeFactory.QNameX;
 }
Beispiel #18
0
 private QilParameter CreateXslParam(QilName name, XmlQueryType xt)
 {
     QilParameter arg = _f.Parameter(xt);
     arg.DebugName = name.ToString();
     arg.Name = name;
     return arg;
 }
 public QilName LiteralQName(string localName, string namespaceUri, string prefix) {
     QilName n = new QilName(QilNodeType.LiteralQName, localName, namespaceUri, prefix);
     n.XmlType = this.typeCheck.CheckLiteralQName(n);
     TraceNode(n);
     return n;
 }
 protected override QilNode VisitLiteralQName(QilName n) { return NoReplace(n); }
 public static VarPar CreateWithParam(QilName name, QilNode value) {
     VarPar withParam = AstFactory.WithParam(name);
     withParam.Value = value;
     return withParam;
 }
        private QilNode GenerateScriptCall(QilName name, XmlExtensionFunction scrFunc, IList<QilNode> args) {
            XmlQueryType xmlTypeFormalArg;

            for (int i = 0; i < args.Count; i++) {
                xmlTypeFormalArg = scrFunc.GetXmlArgumentType(i);
                switch (xmlTypeFormalArg.TypeCode) {
                    case XmlTypeCode.Boolean:       args[i] = f.ConvertToBoolean(args[i]); break;
                    case XmlTypeCode.Double:        args[i] = f.ConvertToNumber(args[i]); break;
                    case XmlTypeCode.String:        args[i] = f.ConvertToString(args[i]); break;
                    case XmlTypeCode.Node:          args[i] = xmlTypeFormalArg.IsSingleton ? f.ConvertToNode(args[i]) : f.ConvertToNodeSet(args[i]); break;
                    case XmlTypeCode.Item:          break;
                    default: Debug.Fail("This XmlTypeCode should never be inferred from a Clr type: " + xmlTypeFormalArg.TypeCode); break;
                }
            }

            return f.XsltInvokeEarlyBound(name, scrFunc.Method, scrFunc.XmlReturnType, args);
        }
        private QilNode InvokeApplyFunction(Stylesheet sheet, QilName mode, IList<XslNode> actualArgs) {
            // Here we create function that has one argument for each with-param in apply-templates
            // We have actualArgs -- list of xsl:with-param(name, value)
            // From it we create:
            // invokeArgs -- values to use with QilInvoke
            // formalArgs -- list of iterators to use with QilFunction
            // actualArgs -- modify it to hold iterators (formalArgs) instead of values to ise in invoke generator inside function budy

            // Special treatment for current/position/last
            XslFlags flags;
            if (! compiler.ModeFlags.TryGetValue(mode, out flags)) {
                flags = 0;
            }
            if (IsDebug) {
                flags = XslFlags.FullFocus;
            }

            flags |= XslFlags.Current; // Due to recursive nature of Apply(Templates/Imports) we will need current node any way
            Debug.Assert(actualArgs[0].Name == nameCurrent, "Caller should always pass $current as a first argument to apply-* calls.");

            QilList     invokeArgs = f.ActualParameterList();
            QilFunction applyFunction = null;

            // Look at the list of all functions that have been already built.  If a suitable one is found, reuse it.
            Dictionary<QilName, List<QilFunction>> funcTable = (
                sheet == null ? compiler.ApplyTemplatesFunctions : sheet.ApplyImportsFunctions
            );

            List<QilFunction> functionsForMode;
            if (!funcTable.TryGetValue(mode, out functionsForMode)) {
                functionsForMode = funcTable[mode] = new List<QilFunction>();
            }

            foreach (QilFunction func in functionsForMode) {
                if (FillupInvokeArgs(func.Arguments, actualArgs, /*ref*/invokeArgs)) {
                    applyFunction = func;
                    break;
                }
            }

            // If a suitable function has not been found, create it
            if (applyFunction == null) {
                invokeArgs.Clear();
                // We wasn't able to find suitable function. Let's build new:
                // 1. Function arguments
                QilList formalArgs = f.FormalParameterList();
                for (int i = 0; i < actualArgs.Count; i++) {
                    Debug.Assert(actualArgs[i].NodeType == XslNodeType.WithParam, "All Sorts was removed in CompileSorts()");
                    VarPar withParam = (VarPar)actualArgs[i] ;

                    // Add actual arg to 'invokeArgs' array. No need to clone it since it must be
                    // a literal or a reference.
                    invokeArgs.Add(withParam.Value);

                    // Create correspondent formal arg
                    QilParameter formalArg = f.Parameter(i == 0 ? T.NodeNotRtf : withParam.Value.XmlType);
                    formalArg.Name = CloneName(withParam.Name);
                    formalArgs.Add(formalArg);

                    // Change actual arg value to formalArg for reuse in calling built-in templates rules
                    withParam.Value = formalArg;
                }

                // 2. Function header
                applyFunction = f.Function(formalArgs, f.False(), T.NodeNotRtfS);
                string attMode = (mode.LocalName.Length == 0) ? string.Empty : " mode=\"" + mode.QualifiedName + '"';
                applyFunction.DebugName = (sheet == null ? "<xsl:apply-templates" : "<xsl:apply-imports") + attMode + '>';
                functionsForMode.Add(applyFunction);
                this.functions.Add(applyFunction);

                // 3. Function body
                QilIterator current = (QilIterator)formalArgs[0];

                // 3.1 Built-in templates
                QilTernary builtinTemplates = f.BaseFactory.Conditional(f.IsType(current, elementOrDocumentType),
                    // This will be fixed up later
                    f.BaseFactory.Nop(f.BaseFactory.Unknown(T.NodeNotRtfS)),
                    f.Conditional(f.IsType(current, textOrAttributeType),
                        f.TextCtor(f.XPathNodeValue(current)),
                        f.Sequence()
                    )
                );

                // 3.2 Stylesheet templates
                matcherBuilder.CollectPatterns(sheet ?? compiler.PrincipalStylesheet, mode, /*applyImports:*/sheet != null);
                applyFunction.Definition = matcherBuilder.BuildMatcher(current, actualArgs, /*otherwise:*/builtinTemplates);

                // 3.3 Fix up the loop in built-in templates
                QilLoop loopOnContent; {
                    QilIterator iChild = f.For(f.Content(current));
                    QilNode filter = f.Filter(iChild, f.IsType(iChild, T.Content));
                    filter.XmlType = T.ContentS;    // not attribute

                    LoopFocus curLoopSaved = curLoop;
                    curLoop.SetFocus(f.For(filter));
                    if ((flags & XslFlags.Last) != 0) {
                        // Mark that we need last argument
                        curLoop.GetLast();
                    }

                    /* Prepare actual arguments */ {
                        // At XSLT 1.0, if a built-in template rule is invoked with parameters, the parameters are not
                        // passed on to any templates invoked by the built-in rule. At XSLT 2.0, these parameters are
                        // passed through the built-in template rule unchanged.
                        const bool Xslt10Rules = true;
                        if (Xslt10Rules) {
                            List<XslNode> newActualArgs = new List<XslNode>(3);
                            int argNum = 0;
                            if ((flags & XslFlags.Current ) != 0) { newActualArgs.Add(actualArgs[argNum ++]); }
                            if ((flags & XslFlags.Position) != 0) { newActualArgs.Add(actualArgs[argNum ++]); }
                            if ((flags & XslFlags.Last    ) != 0) { newActualArgs.Add(actualArgs[argNum ++]); }
                            actualArgs = newActualArgs;
                        }

                        // Fix values of current, position, and last
                        {
                            int argNum = 0;
                            if ((flags & XslFlags.Current ) != 0) { ((VarPar)actualArgs[argNum ++]).Value = GetCurrentNode    (); }
                            if ((flags & XslFlags.Position) != 0) { ((VarPar)actualArgs[argNum ++]).Value = GetCurrentPosition(); }
                            if ((flags & XslFlags.Last    ) != 0) { ((VarPar)actualArgs[argNum ++]).Value = GetLastPosition   (); }
                        }
                    }
                    loopOnContent = curLoop.ConstructLoop(InvokeApplyFunction(/*sheet:*/null, mode, actualArgs));
                    curLoop = curLoopSaved;
                }

                Debug.Assert(builtinTemplates.Center.NodeType == QilNodeType.Nop);
                ((QilUnary)builtinTemplates.Center).Child = loopOnContent;
            }
            return f.Invoke(applyFunction, invokeArgs);
        }
 public QilParameter Parameter(QilNode defaultValue, QilName name, XmlQueryType t) {
     return f.Parameter(defaultValue, name, t);
 }
Beispiel #25
0
        private void EndElement()
        {
            MethodInfo facMethod = null;

            object[]         facArgs;
            QilList          list;
            QilNode          nd;
            ReaderAnnotation ann;

            list = this.stk.Pop();
            ann  = (ReaderAnnotation)list.Annotation;

            // Special case certain element names
            string s = r.LocalName;

            switch (r.LocalName)
            {
            case "QilExpression": {
                Debug.Assert(list.Count > 0, "QilExpression node requires a Root expression");
                QilExpression qil = f.QilExpression(list[list.Count - 1]);

                // Be flexible on order and presence of QilExpression children
                for (int i = 0; i < list.Count - 1; i++)
                {
                    switch (list[i].NodeType)
                    {
                    case QilNodeType.True:
                    case QilNodeType.False:
                        qil.IsDebug = list[i].NodeType == QilNodeType.True;
                        break;

                    case QilNodeType.FunctionList:
                        qil.FunctionList = (QilList)list[i];
                        break;

                    case QilNodeType.GlobalVariableList:
                        qil.GlobalVariableList = (QilList)list[i];
                        break;

                    case QilNodeType.GlobalParameterList:
                        qil.GlobalParameterList = (QilList)list[i];
                        break;
                    }
                }
                nd = qil;
                break;
            }

            case "ForwardDecls":
                this.inFwdDecls = false;
                return;

            case "Parameter":
            case "Let":
            case "For":
            case "Function": {
                string  id   = ann.Id;
                QilName name = ann.Name;
                Debug.Assert(id != null, r.LocalName + " must have an id attribute");
                Debug.Assert(!this.inFwdDecls || ann.XmlType != null, "Forward decl for " + r.LocalName + " '" + id + "' must have an xmlType attribute");

                // Create node (may be discarded later if it was already declared in forward declarations section)
                switch (r.LocalName)
                {
                case "Parameter":
                    Debug.Assert(list.Count <= (this.inFwdDecls ? 0 : 1), "Parameter '" + id + "' must have 0 or 1 arguments");
                    Debug.Assert(ann.XmlType != null, "Parameter '" + id + "' must have an xmlType attribute");
                    if (this.inFwdDecls || list.Count == 0)
                    {
                        nd = f.Parameter(null, name, ann.XmlType);
                    }
                    else
                    {
                        nd = f.Parameter(list[0], name, ann.XmlType);
                    }
                    break;

                case "Let":
                    Debug.Assert(list.Count == (this.inFwdDecls ? 0 : 1), "Let '" + id + "' must have 0 or 1 arguments");
                    if (this.inFwdDecls)
                    {
                        nd = f.Let(f.Unknown(ann.XmlType));
                    }
                    else
                    {
                        nd = f.Let(list[0]);
                    }
                    break;

                case "For":
                    Debug.Assert(list.Count == 1, "For '" + id + "' must have 1 argument");
                    nd = f.For(list[0]);
                    break;

                default:
                    Debug.Assert(list.Count == (this.inFwdDecls ? 2 : 3), "Function '" + id + "' must have 2 or 3 arguments");
                    if (this.inFwdDecls)
                    {
                        nd = f.Function(list[0], list[1], ann.XmlType);
                    }
                    else
                    {
                        nd = f.Function(list[0], list[1], list[2], ann.XmlType != null ? ann.XmlType : list[1].XmlType);
                    }
                    break;
                }

                // Set DebugName
                if (name != null)
                {
                    ((QilReference)nd).DebugName = name.ToString();
                }

                if (this.inFwdDecls)
                {
                    Debug.Assert(!this.scope.ContainsKey(id), "Multiple nodes have id '" + id + "'");
                    this.fwdDecls[id] = nd;
                    this.scope[id]    = nd;
                }
                else
                {
                    if (this.fwdDecls.ContainsKey(id))
                    {
                        // Replace forward declaration
                        Debug.Assert(r.LocalName == Enum.GetName(typeof(QilNodeType), nd.NodeType), "Id '" + id + "' is not not bound to a " + r.LocalName + " forward decl");
                        nd = this.fwdDecls[id];
                        this.fwdDecls.Remove(id);

                        if (list.Count > 0)
                        {
                            nd[0] = list[0];
                        }
                        if (list.Count > 1)
                        {
                            nd[1] = list[1];
                        }
                    }
                    else
                    {
                        // Put reference in scope
                        Debug.Assert(!this.scope.ContainsKey(id), "Id '" + id + "' is already in scope");
                        this.scope[id] = nd;
                    }
                }
                nd.Annotation = ann;
                break;
            }

            case "RefTo": {
                // Lookup reference
                string id = ann.Id;
                Debug.Assert(id != null, r.LocalName + " must have an id attribute");

                Debug.Assert(this.scope.ContainsKey(id), "Id '" + id + "' is not in scope");
                this.stk.Peek().Add(this.scope[id]);
                return;
            }

            case "Sequence":
                nd = f.Sequence(list);
                break;

            case "FunctionList":
                nd = f.FunctionList(list);
                break;

            case "GlobalVariableList":
                nd = f.GlobalVariableList(list);
                break;

            case "GlobalParameterList":
                nd = f.GlobalParameterList(list);
                break;

            case "ActualParameterList":
                nd = f.ActualParameterList(list);
                break;

            case "FormalParameterList":
                nd = f.FormalParameterList(list);
                break;

            case "SortKeyList":
                nd = f.SortKeyList(list);
                break;

            case "BranchList":
                nd = f.BranchList(list);
                break;

            case "XsltInvokeEarlyBound": {
                Debug.Assert(ann.ClrNamespace != null, "XsltInvokeEarlyBound must have a clrNamespace attribute");
                Debug.Assert(list.Count == 2, "XsltInvokeEarlyBound must have exactly 2 arguments");
                Debug.Assert(list.XmlType != null, "XsltInvokeEarlyBound must have an xmlType attribute");
                MethodInfo mi   = null;
                QilName    name = (QilName)list[0];

                foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
                {
                    Type t = asm.GetType(ann.ClrNamespace);
                    if (t != null)
                    {
                        mi = t.GetMethod(name.LocalName);
                        break;
                    }
                }

                Debug.Assert(mi != null, "Cannot find method " + ann.ClrNamespace + "." + name.ToString());

                nd = f.XsltInvokeEarlyBound(name, f.LiteralObject(mi), list[1], ann.XmlType);
                break;
            }

            default: {
                // Find factory method which will be used to construct the Qil node
                Debug.Assert(nameToFactoryMethod.ContainsKey(r.LocalName), "Method " + r.LocalName + " could not be found on QilFactory");
                facMethod = nameToFactoryMethod[r.LocalName];
                Debug.Assert(facMethod.GetParameters().Length == list.Count, "NodeType " + r.LocalName + " does not allow " + list.Count + " parameters");

                // Create factory method arguments
                facArgs = new object[list.Count];
                for (int i = 0; i < facArgs.Length; i++)
                {
                    facArgs[i] = list[i];
                }

                // Create node and set its properties
                nd = (QilNode)facMethod.Invoke(f, facArgs);
                break;
            }
            }

            nd.SourceLine = list.SourceLine;

            // Add node to its parent's list
            this.stk.Peek().Add(nd);
        }