CompilerScopeManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / Xslt / CompilerScopeManager.cs / 1305376 / CompilerScopeManager.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System.Diagnostics; 

namespace System.Xml.Xsl.Xslt { 
    using QilName = System.Xml.Xsl.Qil.QilName;

    // Compiler scope manager keeps track of
    //   Variable declarations 
    //   Namespace declarations
    //   Extension and excluded namespaces 
    internal sealed class CompilerScopeManager { 
        public enum ScopeFlags {
            BackwardCompatibility = 0x1, 
            ForwardCompatibility = 0x2,
            CanHaveApplyImports = 0x4,
            NsDecl   = 0x10,                   // NS declaration
            NsExcl   = 0x20,                   // NS Extencion (null for ExcludeAll) 
            Variable = 0x40,
 
            CompatibilityFlags = BackwardCompatibility | ForwardCompatibility, 
            InheritedFlags = CompatibilityFlags | CanHaveApplyImports,
            ExclusiveFlags = NsDecl | NsExcl | Variable 
        }

        public struct ScopeRecord {
            public int    scopeCount; 
            public ScopeFlags flags;
            public string ncName;     // local-name for variable, prefix for namespace, null for extension or excluded namespace 
            public string nsUri;      // namespace uri 
            public V      value;      // value for variable, null for namespace
 
            // Exactly one of these three properties is true for every given record
            public bool IsVariable      { get { return (flags & ScopeFlags.Variable) != 0; } }
            public bool IsNamespace     { get { return (flags & ScopeFlags.NsDecl  ) != 0; } }
//          public bool IsExNamespace   { get { return (flags & ScopeFlags.NsExcl  ) != 0; } } 
        }
 
        // Number of predefined records minus one 
        private const int       LastPredefRecord = 0;
 
        private ScopeRecord[]   records = new ScopeRecord[32];
        private int             lastRecord = LastPredefRecord;

        // This is cache of records[lastRecord].scopeCount field; 
        // most often we will have PushScope()/PopScope pare over the same record.
        // It has sence to avoid adresing this field through array access. 
        private int             lastScopes = 0; 

        public CompilerScopeManager() { 
            // The prefix 'xml' is by definition bound to the namespace name http://www.w3.org/XML/1998/namespace
            records[0].flags  = ScopeFlags.NsDecl;
            records[0].ncName = "xml";
            records[0].nsUri  = XmlReservedNs.NsXml; 
        }
 
        public CompilerScopeManager(KeywordsTable atoms) { 
            records[0].flags  = ScopeFlags.NsDecl;
            records[0].ncName = atoms.Xml; 
            records[0].nsUri  = atoms.UriXml;
        }

        public void EnterScope() { 
            lastScopes++;
        } 
 
        public void ExitScope() {
            if (0 < lastScopes) { 
                lastScopes--;
            } else {
                while (records[--lastRecord].scopeCount == 0) {
                } 
                lastScopes = records[lastRecord].scopeCount;
                lastScopes--; 
            } 
        }
 
        [Conditional("DEBUG")]
        public void CheckEmpty() {
            ExitScope();
            Debug.Assert(lastRecord == 0 && lastScopes == 0, "PushScope() and PopScope() calls are unbalanced"); 
        }
 
        // returns true if ns decls was added to scope 
        public bool EnterScope(NsDecl nsDecl) {
            lastScopes++; 

            bool hasNamespaces = false;
            bool excludeAll    = false;
            for (; nsDecl != null;  nsDecl = nsDecl.Prev) { 
                if (nsDecl.NsUri == null) {
                    Debug.Assert(nsDecl.Prefix == null, "NS may be null only when prefix is null where it is used for extension-element-prefixes='#all'"); 
                    excludeAll = true; 
                } else if (nsDecl.Prefix == null) {
                    AddExNamespace(nsDecl.NsUri); 
                } else {
                    hasNamespaces = true;
                    AddNsDeclaration(nsDecl.Prefix, nsDecl.NsUri);
                } 
            }
            if (excludeAll) { 
                // #all should be on the top of the stack, becase all NSs on this element should be excluded as well 
                AddExNamespace(null);
            } 
            return hasNamespaces;
        }

        private void AddRecord() { 
            // Store cached fields:
            records[lastRecord].scopeCount = lastScopes; 
            // Extend record buffer: 
            if (++lastRecord == records.Length) {
                ScopeRecord[] newRecords = new ScopeRecord[lastRecord * 2]; 
                Array.Copy(records, 0, newRecords, 0, lastRecord);
                records = newRecords;
            }
            // reset scope count: 
            lastScopes = 0;
        } 
 
        private void AddRecord(ScopeFlags flag, string ncName, string uri, V value) {
            Debug.Assert(flag == (flag & ScopeFlags.ExclusiveFlags) && (flag & (flag - 1)) == 0 && flag != 0, "One exclusive flag"); 
            Debug.Assert(uri != null || ncName == null, "null, null means exclude '#all'");

            ScopeFlags flags = records[lastRecord].flags;
            bool canReuseLastRecord = (lastScopes == 0) && (flags & ScopeFlags.ExclusiveFlags) == 0; 
            if (!canReuseLastRecord) {
                AddRecord(); 
                flags &= ScopeFlags.InheritedFlags; 
            }
 
            records[lastRecord].flags   = flags | flag;
            records[lastRecord].ncName  = ncName;
            records[lastRecord].nsUri   = uri;
            records[lastRecord].value   = value; 
        }
 
        private void SetFlag(ScopeFlags flag, bool value) { 
            Debug.Assert(flag == (flag & ScopeFlags.InheritedFlags) && (flag & (flag - 1)) == 0 && flag != 0, "one inherited flag");
            ScopeFlags flags = records[lastRecord].flags; 
            if (((flags & flag) != 0) != value) {
                // lastScopes == records[lastRecord].scopeCount;          // we know this because we are cashing it.
                bool canReuseLastRecord = lastScopes == 0;                // last record is from last scope
                if (!canReuseLastRecord) { 
                    AddRecord();
                    flags &= ScopeFlags.InheritedFlags; 
                } 
                if (flag == ScopeFlags.CanHaveApplyImports) {
                    flags ^= flag; 
                } else {
                    flags &= ~ScopeFlags.CompatibilityFlags;
                    if (value) {
                        flags |= flag; 
                    }
                } 
                records[lastRecord].flags = flags; 
            }
            Debug.Assert((records[lastRecord].flags & ScopeFlags.CompatibilityFlags) != ScopeFlags.CompatibilityFlags, 
                "BackwardCompatibility and ForwardCompatibility flags are mutually exclusive"
            );
        }
 
        // Add variable to the current scope.  Returns false in case of duplicates.
        public void AddVariable(QilName varName, V value) { 
            Debug.Assert(varName.LocalName != null && varName.NamespaceUri != null); 
            AddRecord(ScopeFlags.Variable, varName.LocalName, varName.NamespaceUri, value);
        } 

        // Since the prefix might be redefined in an inner scope, we search in descending order in [to, from]
        // If interval is empty (from < to), the function returns null.
        private string LookupNamespace(string prefix, int from, int to) { 
            Debug.Assert(prefix != null);
            for (int record = from; to <= record; --record) { 
                string recPrefix, recNsUri; 
                ScopeFlags flags = GetName(ref records[record], out recPrefix, out recNsUri);
                if ( 
                    (flags & ScopeFlags.NsDecl) != 0 &&
                    recPrefix == prefix
                ) {
                    return recNsUri; 
                }
            } 
            return null; 
        }
 
        public string LookupNamespace(string prefix) {
            return LookupNamespace(prefix, lastRecord, 0);
        }
 
        private static ScopeFlags GetName(ref ScopeRecord re, out string prefix, out string nsUri) {
            prefix = re.ncName; 
            nsUri  = re.nsUri; 
            return re.flags;
        } 

        public void AddNsDeclaration(string prefix, string nsUri) {
            AddRecord(ScopeFlags.NsDecl, prefix, nsUri, default(V));
        } 

        public void AddExNamespace(string nsUri) { 
            AddRecord(ScopeFlags.NsExcl, null, nsUri, default(V)); 
        }
 
        public bool IsExNamespace(string nsUri) {
            Debug.Assert(nsUri != null);
            int exAll = 0;
            for (int record = lastRecord; 0 <= record; record--) { 
                string recPrefix, recNsUri;
                ScopeFlags flags = GetName(ref records[record], out recPrefix, out recNsUri); 
                if ((flags & ScopeFlags.NsExcl) != 0) { 
                    Debug.Assert(recPrefix == null);
                    if (recNsUri == nsUri) { 
                        return true;               // This namespace is excluded
                    }
                    if (recNsUri == null) {
                        exAll = record;            // #all namespaces below are excluded 
                    }
                } else if ( 
                    exAll != 0 && 
                    (flags & ScopeFlags.NsDecl) != 0 &&
                    recNsUri == nsUri 
                ) {
                    // We need to check that this namespace wasn't undefined before last "#all"
                    bool undefined = false;
                    for (int prev = record + 1; prev < exAll; prev++) { 
                        string prevPrefix, prevNsUri;
                        ScopeFlags prevFlags = GetName(ref records[prev], out prevPrefix, out prevNsUri); 
                        if ( 
                            (flags & ScopeFlags.NsDecl) != 0 &&
                            prevPrefix == recPrefix 
                        ) {
                            // We don't care if records[prev].nsUri == records[record].nsUri.
                            // In this case the namespace was already undefined above.
                            undefined = true; 
                            break;
                        } 
                    } 
                    if (!undefined) {
                        return true; 
                    }
                }
            }
            return false; 
        }
 
        private int SearchVariable(string localName, string uri) { 
            Debug.Assert(localName != null);
            for (int record = lastRecord; 0 <= record; --record) { 
                string recLocal, recNsUri;
                ScopeFlags flags = GetName(ref records[record], out recLocal, out recNsUri);
                if (
                    (flags & ScopeFlags.Variable) != 0 && 
                    recLocal == localName &&
                    recNsUri == uri 
                ) { 
                    return record;
                } 
            }
            return -1;
        }
 
        public V LookupVariable(string localName, string uri) {
            int record = SearchVariable(localName, uri); 
            return (record < 0) ? default(V) : records[record].value; 
        }
 
        public bool IsLocalVariable(string localName, string uri) {
            int record = SearchVariable(localName, uri);
            while (0 <= --record) {
                if (records[record].scopeCount != 0) { 
                    return true;
                } 
            } 
            return false;
        } 

        public bool ForwardCompatibility {
            get { return (records[lastRecord].flags & ScopeFlags.ForwardCompatibility) != 0; }
            set { SetFlag(ScopeFlags.ForwardCompatibility, value); } 
        }
 
        public bool BackwardCompatibility { 
            get { return (records[lastRecord].flags & ScopeFlags.BackwardCompatibility) != 0; }
            set { SetFlag(ScopeFlags.BackwardCompatibility, value); } 
        }

        public bool CanHaveApplyImports {
            get { return (records[lastRecord].flags & ScopeFlags.CanHaveApplyImports) != 0; } 
            set { SetFlag(ScopeFlags.CanHaveApplyImports, value); }
        } 
 
        public NamespaceEnumerator GetEnumerator() {
            return new NamespaceEnumerator(this); 
        }

        internal struct NamespaceEnumerator {
            CompilerScopeManager scope; 
            int                     lastRecord;
            int                     currentRecord; 
 
            public NamespaceEnumerator(CompilerScopeManager scope) {
                this.scope      = scope; 
                this.lastRecord = scope.lastRecord;
                this.currentRecord = lastRecord + 1;
            }
 
            public void Reset() {
                currentRecord = lastRecord + 1; 
            } 

            public bool MoveNext() { 
                while (LastPredefRecord < --currentRecord) {
                    if (scope.records[currentRecord].IsNamespace) {
                        // This is a namespace declaration
                        if (scope.LookupNamespace(scope.records[currentRecord].ncName, lastRecord, currentRecord + 1) == null) { 
                            // Its prefix has not been redefined later in [currentRecord + 1, lastRecord]
                            return true; 
                        } 
                    }
                } 
                return false;
            }

            public ScopeRecord Current { 
                get {
                    Debug.Assert(LastPredefRecord <= currentRecord && currentRecord <= scope.lastRecord, "MoveNext() either was not called or returned false"); 
                    Debug.Assert(scope.records[currentRecord].IsNamespace); 
                    return scope.records[currentRecord];
                } 
            }
        }
    }
} 

// 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