QilXmlReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / XmlUtils / System / Xml / Xsl / QIL / QilXmlReader.cs / 1 / QilXmlReader.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.IO;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions; 
using System.Reflection;
using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Xsl;
 
namespace System.Xml.Xsl.Qil {

    /// 
    /// Read the output of QilXmlWriter. 
    /// 
    /// This internal class allows roundtripping between the Xml serialization format for 
    /// QIL and the in-memory data structure. 
    internal sealed class QilXmlReader {
        private static Regex  lineInfoRegex = new Regex(@"\[(\d+),(\d+) -- (\d+),(\d+)\]"); 
        private static Regex  typeInfoRegex = new Regex(@"(\w+);([\w|\|]+);(\w+)");
        private static Dictionary nameToFactoryMethod;

        private QilFactory f; 
        private XmlReader r;
        private Stack stk; 
        private bool inFwdDecls; 
        private Dictionary scope, fwdDecls;
 
        static QilXmlReader() {
            nameToFactoryMethod = new Dictionary();

            // Build table that maps QilNodeType name to factory method info 
            foreach (MethodInfo mi in typeof(QilFactory).GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
                ParameterInfo[] parms = mi.GetParameters(); 
                int i; 

                // Only match methods that take QilNode parameters 
                for (i = 0; i < parms.Length; i++) {
                    if (parms[i].ParameterType != typeof(QilNode))
                        break;
                } 

                if (i == parms.Length) { 
                    // Enter the method that takes the maximum number of parameters 
                    if (!nameToFactoryMethod.ContainsKey(mi.Name) || nameToFactoryMethod[mi.Name].GetParameters().Length < parms.Length)
                        nameToFactoryMethod[mi.Name] = mi; 
                }
            }
        }
 
        public QilXmlReader(XmlReader r) {
            this.r = r; 
            this.f = new QilFactory(); 
        }
 
        public QilExpression Read() {
            this.stk = new Stack();
            this.inFwdDecls = false;
            this.scope = new Dictionary(); 
            this.fwdDecls = new Dictionary();
 
            this.stk.Push(f.Sequence()); 

            while (r.Read()) { 
                switch (r.NodeType) {
                    case XmlNodeType.Element:
                        bool emptyElem = r.IsEmptyElement;
 
                        // XmlReader does not give an event for empty elements, so synthesize one
                        if (StartElement() && emptyElem) 
                            EndElement(); 
                        break;
 
                    case XmlNodeType.EndElement:
                        EndElement();
                        break;
 
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace: 
                    case XmlNodeType.XmlDeclaration: 
                    case XmlNodeType.Comment:
                    case XmlNodeType.ProcessingInstruction: 
                        break;

                    default:
                        Debug.Fail("Unexpected event " + r.NodeType + ", value " + r.Value); 
                        break;
                } 
            } 

            Debug.Assert(this.fwdDecls.Keys.Count == 0, "One or more forward declarations were never defined"); 
            Debug.Assert(this.stk.Peek()[0].NodeType == QilNodeType.QilExpression, "Serialized qil tree did not contain a QilExpression node");
            return (QilExpression) this.stk.Peek()[0];
        }
 
        private bool StartElement() {
            QilNode nd; 
            ReaderAnnotation ann = new ReaderAnnotation(); 
            string s;
 
            // Special case certain element names
            s = r.LocalName;
            switch (r.LocalName) {
                case "LiteralString": 
                    nd = f.LiteralString(ReadText());
                    break; 
 
                case "LiteralInt32":
                    nd = f.LiteralInt32(Int32.Parse(ReadText(), CultureInfo.InvariantCulture)); 
                    break;

                case "LiteralInt64":
                    nd = f.LiteralInt64(Int64.Parse(ReadText(), CultureInfo.InvariantCulture)); 
                    break;
 
                case "LiteralDouble": 
                    nd = f.LiteralDouble(Double.Parse(ReadText(), CultureInfo.InvariantCulture));
                    break; 

                case "LiteralDecimal":
                    nd = f.LiteralDecimal(Decimal.Parse(ReadText(), CultureInfo.InvariantCulture));
                    break; 

                case "LiteralType": 
                    nd = f.LiteralType(ParseType(ReadText())); 
                    break;
 
                case "LiteralQName":
                    nd = ParseName(r.GetAttribute("name"));
                    Debug.Assert(nd != null, "LiteralQName element must have a name attribute");
                    Debug.Assert(r.IsEmptyElement, "LiteralQName element must be empty"); 
                    break;
 
                case "For": 
                case "Let":
                case "Parameter": 
                case "Function":
                case "RefTo":
                    ann.Id = r.GetAttribute("id");
                    ann.Name = ParseName(r.GetAttribute("name")); 
                    goto default;
 
                case "XsltInvokeEarlyBound": 
                    ann.ClrNamespace = r.GetAttribute("clrNamespace");
                    goto default; 

                case "ForwardDecls":
                    this.inFwdDecls = true;
                    goto default; 

                default: 
                    // Create sequence 
                    nd = f.Sequence();
                    break; 
            }

            // Save xml type and source line information
            ann.XmlType = ParseType(r.GetAttribute("xmlType"));; 
            nd.SourceLine = ParseLineInfo(r.GetAttribute("lineInfo"));
            nd.Annotation = ann; 
 
            if (nd is QilList) {
                // Push new parent list onto stack 
                this.stk.Push((QilList) nd);
                return true;
            }
 
            // Add node to its parent's list
            this.stk.Peek().Add(nd); 
            return false; 
        }
 
        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);
        } 

        private string ReadText() { 
            string s = string.Empty; 

            if (!r.IsEmptyElement) { 
                while (r.Read()) {
                    switch (r.NodeType) {
                        case XmlNodeType.Text:
                        case XmlNodeType.SignificantWhitespace: 
                        case XmlNodeType.Whitespace:
                            s += r.Value; 
                            continue; 
                    }
 
                    break;
                }
            }
 
            return s;
        } 
 
        private ISourceLineInfo ParseLineInfo(string s) {
            if (s != null && s.Length > 0) { 
                Match m = lineInfoRegex.Match(s);
                Debug.Assert(m.Success && m.Groups.Count == 5, "Malformed lineInfo attribute");
                return new SourceLineInfo("",
                    Int32.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture), 
                    Int32.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture),
                    Int32.Parse(m.Groups[3].Value, CultureInfo.InvariantCulture), 
                    Int32.Parse(m.Groups[4].Value, CultureInfo.InvariantCulture) 
                );
            } 
            return null;
        }

        private XmlQueryType ParseType(string s) { 
            if (s != null && s.Length > 0) {
                Match m = typeInfoRegex.Match(s); 
                Debug.Assert(m.Success && m.Groups.Count == 4, "Malformed Type info"); 

                XmlQueryCardinality qc = new XmlQueryCardinality(m.Groups[1].Value); 
                bool strict = bool.Parse(m.Groups[3].Value);

                string[] codes = m.Groups[2].Value.Split('|');
                XmlQueryType[] types = new XmlQueryType[codes.Length]; 

                for (int i = 0; i < codes.Length; i++) 
                    types[i] = XmlQueryTypeFactory.Type((XmlTypeCode)Enum.Parse(typeof(XmlTypeCode), codes[i]), strict); 

                return XmlQueryTypeFactory.Product(XmlQueryTypeFactory.Choice(types), qc); 
            }
            return null;
        }
 
        private QilName ParseName(string name) {
            string prefix, local, uri; 
            int idx; 

            if (name != null && name.Length > 0) { 
                // If name contains '}' character, then namespace is non-empty
                idx = name.LastIndexOf('}');
                if (idx != -1 && name[0] == '{') {
                    uri = name.Substring(1, idx - 1); 
                    name = name.Substring(idx + 1);
                } 
                else { 
                    uri = string.Empty;
                } 

                // Parse QName
                ValidateNames.ParseQNameThrow(name, out prefix, out local);
 
                return f.LiteralQName(local, uri, prefix);
            } 
            return null; 
        }
 
        private class ReaderAnnotation {
            public string Id;
            public QilName Name;
            public XmlQueryType XmlType; 
            public string ClrNamespace;
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.IO;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions; 
using System.Reflection;
using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Xsl;
 
namespace System.Xml.Xsl.Qil {

    /// 
    /// Read the output of QilXmlWriter. 
    /// 
    /// This internal class allows roundtripping between the Xml serialization format for 
    /// QIL and the in-memory data structure. 
    internal sealed class QilXmlReader {
        private static Regex  lineInfoRegex = new Regex(@"\[(\d+),(\d+) -- (\d+),(\d+)\]"); 
        private static Regex  typeInfoRegex = new Regex(@"(\w+);([\w|\|]+);(\w+)");
        private static Dictionary nameToFactoryMethod;

        private QilFactory f; 
        private XmlReader r;
        private Stack stk; 
        private bool inFwdDecls; 
        private Dictionary scope, fwdDecls;
 
        static QilXmlReader() {
            nameToFactoryMethod = new Dictionary();

            // Build table that maps QilNodeType name to factory method info 
            foreach (MethodInfo mi in typeof(QilFactory).GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
                ParameterInfo[] parms = mi.GetParameters(); 
                int i; 

                // Only match methods that take QilNode parameters 
                for (i = 0; i < parms.Length; i++) {
                    if (parms[i].ParameterType != typeof(QilNode))
                        break;
                } 

                if (i == parms.Length) { 
                    // Enter the method that takes the maximum number of parameters 
                    if (!nameToFactoryMethod.ContainsKey(mi.Name) || nameToFactoryMethod[mi.Name].GetParameters().Length < parms.Length)
                        nameToFactoryMethod[mi.Name] = mi; 
                }
            }
        }
 
        public QilXmlReader(XmlReader r) {
            this.r = r; 
            this.f = new QilFactory(); 
        }
 
        public QilExpression Read() {
            this.stk = new Stack();
            this.inFwdDecls = false;
            this.scope = new Dictionary(); 
            this.fwdDecls = new Dictionary();
 
            this.stk.Push(f.Sequence()); 

            while (r.Read()) { 
                switch (r.NodeType) {
                    case XmlNodeType.Element:
                        bool emptyElem = r.IsEmptyElement;
 
                        // XmlReader does not give an event for empty elements, so synthesize one
                        if (StartElement() && emptyElem) 
                            EndElement(); 
                        break;
 
                    case XmlNodeType.EndElement:
                        EndElement();
                        break;
 
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace: 
                    case XmlNodeType.XmlDeclaration: 
                    case XmlNodeType.Comment:
                    case XmlNodeType.ProcessingInstruction: 
                        break;

                    default:
                        Debug.Fail("Unexpected event " + r.NodeType + ", value " + r.Value); 
                        break;
                } 
            } 

            Debug.Assert(this.fwdDecls.Keys.Count == 0, "One or more forward declarations were never defined"); 
            Debug.Assert(this.stk.Peek()[0].NodeType == QilNodeType.QilExpression, "Serialized qil tree did not contain a QilExpression node");
            return (QilExpression) this.stk.Peek()[0];
        }
 
        private bool StartElement() {
            QilNode nd; 
            ReaderAnnotation ann = new ReaderAnnotation(); 
            string s;
 
            // Special case certain element names
            s = r.LocalName;
            switch (r.LocalName) {
                case "LiteralString": 
                    nd = f.LiteralString(ReadText());
                    break; 
 
                case "LiteralInt32":
                    nd = f.LiteralInt32(Int32.Parse(ReadText(), CultureInfo.InvariantCulture)); 
                    break;

                case "LiteralInt64":
                    nd = f.LiteralInt64(Int64.Parse(ReadText(), CultureInfo.InvariantCulture)); 
                    break;
 
                case "LiteralDouble": 
                    nd = f.LiteralDouble(Double.Parse(ReadText(), CultureInfo.InvariantCulture));
                    break; 

                case "LiteralDecimal":
                    nd = f.LiteralDecimal(Decimal.Parse(ReadText(), CultureInfo.InvariantCulture));
                    break; 

                case "LiteralType": 
                    nd = f.LiteralType(ParseType(ReadText())); 
                    break;
 
                case "LiteralQName":
                    nd = ParseName(r.GetAttribute("name"));
                    Debug.Assert(nd != null, "LiteralQName element must have a name attribute");
                    Debug.Assert(r.IsEmptyElement, "LiteralQName element must be empty"); 
                    break;
 
                case "For": 
                case "Let":
                case "Parameter": 
                case "Function":
                case "RefTo":
                    ann.Id = r.GetAttribute("id");
                    ann.Name = ParseName(r.GetAttribute("name")); 
                    goto default;
 
                case "XsltInvokeEarlyBound": 
                    ann.ClrNamespace = r.GetAttribute("clrNamespace");
                    goto default; 

                case "ForwardDecls":
                    this.inFwdDecls = true;
                    goto default; 

                default: 
                    // Create sequence 
                    nd = f.Sequence();
                    break; 
            }

            // Save xml type and source line information
            ann.XmlType = ParseType(r.GetAttribute("xmlType"));; 
            nd.SourceLine = ParseLineInfo(r.GetAttribute("lineInfo"));
            nd.Annotation = ann; 
 
            if (nd is QilList) {
                // Push new parent list onto stack 
                this.stk.Push((QilList) nd);
                return true;
            }
 
            // Add node to its parent's list
            this.stk.Peek().Add(nd); 
            return false; 
        }
 
        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);
        } 

        private string ReadText() { 
            string s = string.Empty; 

            if (!r.IsEmptyElement) { 
                while (r.Read()) {
                    switch (r.NodeType) {
                        case XmlNodeType.Text:
                        case XmlNodeType.SignificantWhitespace: 
                        case XmlNodeType.Whitespace:
                            s += r.Value; 
                            continue; 
                    }
 
                    break;
                }
            }
 
            return s;
        } 
 
        private ISourceLineInfo ParseLineInfo(string s) {
            if (s != null && s.Length > 0) { 
                Match m = lineInfoRegex.Match(s);
                Debug.Assert(m.Success && m.Groups.Count == 5, "Malformed lineInfo attribute");
                return new SourceLineInfo("",
                    Int32.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture), 
                    Int32.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture),
                    Int32.Parse(m.Groups[3].Value, CultureInfo.InvariantCulture), 
                    Int32.Parse(m.Groups[4].Value, CultureInfo.InvariantCulture) 
                );
            } 
            return null;
        }

        private XmlQueryType ParseType(string s) { 
            if (s != null && s.Length > 0) {
                Match m = typeInfoRegex.Match(s); 
                Debug.Assert(m.Success && m.Groups.Count == 4, "Malformed Type info"); 

                XmlQueryCardinality qc = new XmlQueryCardinality(m.Groups[1].Value); 
                bool strict = bool.Parse(m.Groups[3].Value);

                string[] codes = m.Groups[2].Value.Split('|');
                XmlQueryType[] types = new XmlQueryType[codes.Length]; 

                for (int i = 0; i < codes.Length; i++) 
                    types[i] = XmlQueryTypeFactory.Type((XmlTypeCode)Enum.Parse(typeof(XmlTypeCode), codes[i]), strict); 

                return XmlQueryTypeFactory.Product(XmlQueryTypeFactory.Choice(types), qc); 
            }
            return null;
        }
 
        private QilName ParseName(string name) {
            string prefix, local, uri; 
            int idx; 

            if (name != null && name.Length > 0) { 
                // If name contains '}' character, then namespace is non-empty
                idx = name.LastIndexOf('}');
                if (idx != -1 && name[0] == '{') {
                    uri = name.Substring(1, idx - 1); 
                    name = name.Substring(idx + 1);
                } 
                else { 
                    uri = string.Empty;
                } 

                // Parse QName
                ValidateNames.ParseQNameThrow(name, out prefix, out local);
 
                return f.LiteralQName(local, uri, prefix);
            } 
            return null; 
        }
 
        private class ReaderAnnotation {
            public string Id;
            public QilName Name;
            public XmlQueryType XmlType; 
            public string ClrNamespace;
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK