File: System\Xml\Xsl\XsltOld\Compiler.cs
Project: ndp\fx\src\XmlUtils\System.Data.SqlXml.csproj (System.Data.SqlXml)
//------------------------------------------------------------------------------
// <copyright file="Compiler.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
 
namespace System.Xml.Xsl.XsltOld {
    using Res = System.Xml.Utils.Res;
    using System;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Xml;
    using System.Xml.XPath;
    using System.Xml.Xsl.Runtime;
    using MS.Internal.Xml.XPath;
    using System.Xml.Xsl.XsltOld.Debugger;
    using System.Text;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.IO;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Reflection;
    using System.Security;
    using System.Security.Policy;
    using System.Security.Permissions;
    using Keywords = System.Xml.Xsl.Xslt.KeywordsTable;
    using System.Runtime.Versioning;
 
    internal class Sort {
        internal int          select;
        internal string       lang;
        internal XmlDataType  dataType;
        internal XmlSortOrder order;
        internal XmlCaseOrder caseOrder;
 
        public Sort(int sortkey, String xmllang, XmlDataType datatype, XmlSortOrder xmlorder, XmlCaseOrder xmlcaseorder) {
            select    = sortkey;
            lang      = xmllang;
            dataType  = datatype;
            order     = xmlorder;
            caseOrder = xmlcaseorder;
        }
    }
 
    internal enum ScriptingLanguage {
        JScript,
#if !FEATURE_PAL // visualbasic
        VisualBasic,
#endif // !FEATURE_PAL
        CSharp
    }
 
    internal class Compiler {
        internal const int    InvalidQueryKey   = -1;
 
        internal const double RootPriority   = 0.5;
 
        // cached StringBuilder for AVT parseing
        internal StringBuilder AvtStringBuilder = new StringBuilder();
 
        private int                 stylesheetid; // Root stylesheet has id=0. We are using this in CompileImports to compile BuiltIns
        private InputScope          rootScope;
 
        //
        // Object members
        private XmlResolver         xmlResolver;
 
        //
        // Template being currently compiled
        private TemplateBaseAction  currentTemplate;
        private XmlQualifiedName    currentMode;
        private Hashtable           globalNamespaceAliasTable;
 
        //
        // Current import stack
        private Stack               stylesheets;
 
        private HybridDictionary    documentURIs = new HybridDictionary();
 
        // import/include documents, who is here has its URI in this.documentURIs
        private NavigatorInput      input;
 
        // Atom table & InputScopeManager - cached top of the this.input stack
        private Keywords            atoms;
        private InputScopeManager   scopeManager;
 
        //
        // Compiled stylesheet state
        internal Stylesheet         stylesheet;
        internal Stylesheet         rootStylesheet;
        private RootAction          rootAction;
        private List<TheQuery>      queryStore;
        private QueryBuilder        queryBuilder = new QueryBuilder();
        private int                 rtfCount = 0;
 
        // Used to load Built In templates
        public  bool                AllowBuiltInMode;
        public  static XmlQualifiedName BuiltInMode = new XmlQualifiedName("*", string.Empty);
 
        internal Keywords Atoms {
            get {
                Debug.Assert(this.atoms != null);
                return this.atoms;
            }
        }
 
        internal int Stylesheetid {
            get{ return this.stylesheetid; }
            set { this.stylesheetid = value; }
        }
 
        internal NavigatorInput Document {
            get { return this.input; }
        }
 
        internal NavigatorInput Input {
            get { return this.input; }
        }
 
        internal bool Advance() {
            Debug.Assert(Document != null);
            return Document.Advance();
        }
 
        internal bool Recurse() {
            Debug.Assert(Document != null);
            return Document.Recurse();
        }
 
        internal bool ToParent() {
            Debug.Assert(Document != null);
            return Document.ToParent();
        }
 
        internal Stylesheet CompiledStylesheet {
            get { return this.stylesheet; }
        }
 
        internal RootAction RootAction {
            get { return this.rootAction; }
            set {
                Debug.Assert(this.rootAction == null);
                this.rootAction = value;
                Debug.Assert(this.currentTemplate == null);
                this.currentTemplate = this.rootAction;
            }
        }
 
        internal List<TheQuery> QueryStore {
            get { return this.queryStore; }
        }
 
        public virtual IXsltDebugger Debugger { get { return null; } }
 
        internal string GetUnicRtfId() {
            this.rtfCount++;
            return this.rtfCount.ToString(CultureInfo.InvariantCulture);
        }
 
        //
        // The World of Compile
        //
        internal void Compile(NavigatorInput input, XmlResolver xmlResolver, Evidence evidence) {
            Debug.Assert(input != null);
            Debug.Assert(xmlResolver != null);
//            Debug.Assert(evidence    != null); -- default evidence is null now
            Debug.Assert(this.input == null && this.atoms == null);
            this.xmlResolver = xmlResolver;
 
            PushInputDocument(input);
            this.rootScope  = this.scopeManager.PushScope();
            this.queryStore = new List<TheQuery>();
 
            try {
                this.rootStylesheet = new Stylesheet();
                PushStylesheet(this.rootStylesheet);
 
                Debug.Assert(this.input != null && this.atoms != null);
 
                try {
                    this.CreateRootAction();
                }
                catch (XsltCompileException) {
                    throw;
                }
                catch (Exception e) {
                    throw new XsltCompileException(e, this.Input.BaseURI, this.Input.LineNumber, this.Input.LinePosition);
                }
 
                this.stylesheet.ProcessTemplates();
                this.rootAction.PorcessAttributeSets(this.rootStylesheet);
                this.stylesheet.SortWhiteSpace();
                CompileScript(evidence);
                if (evidence != null) {
                    this.rootAction.permissions = SecurityManager.GetStandardSandbox(evidence);
                }
 
                if (this.globalNamespaceAliasTable != null) {
                    this.stylesheet.ReplaceNamespaceAlias(this);
                    this.rootAction.ReplaceNamespaceAlias(this);
                }
            }
            finally {
                PopInputDocument();
            }
 
            Debug.Assert(this.rootAction != null);
            Debug.Assert(this.stylesheet != null);
            Debug.Assert(this.queryStore != null);
            Debug.Assert(this.input == null && this.atoms == null);
        }
 
        //
        // Input scope compiler's support
        //
 
        internal bool ForwardCompatibility {
            get { return this.scopeManager.CurrentScope.ForwardCompatibility;  }
            set { this.scopeManager.CurrentScope.ForwardCompatibility = value; }
        }
 
        internal bool CanHaveApplyImports {
            get { return this.scopeManager.CurrentScope.CanHaveApplyImports;  }
            set { this.scopeManager.CurrentScope.CanHaveApplyImports = value; }
        }
 
        internal void InsertExtensionNamespace(string value) {
            string[] nsList = ResolvePrefixes(value);
            if (nsList != null) {
                scopeManager.InsertExtensionNamespaces(nsList);
            }
        }
 
        internal void InsertExcludedNamespace(string value) {
            string[] nsList = ResolvePrefixes(value);
            if (nsList != null) {
                scopeManager.InsertExcludedNamespaces(nsList);
            }
        }
 
        internal void InsertExtensionNamespace() {
            InsertExtensionNamespace(Input.Navigator.GetAttribute(Input.Atoms.ExtensionElementPrefixes, Input.Atoms.UriXsl));
        }
 
        internal void InsertExcludedNamespace() {
            InsertExcludedNamespace(Input.Navigator.GetAttribute(Input.Atoms.ExcludeResultPrefixes, Input.Atoms.UriXsl));
        }
 
        internal bool IsExtensionNamespace(String nspace) {
            return this.scopeManager.IsExtensionNamespace(nspace);
        }
 
        internal bool IsExcludedNamespace(String nspace) {
            return this.scopeManager.IsExcludedNamespace(nspace);
        }
 
        internal void PushLiteralScope() {
            PushNamespaceScope();
            string value = Input.Navigator.GetAttribute(Atoms.Version, Atoms.UriXsl);
            if (value.Length != 0) {
                ForwardCompatibility = (value != "1.0");
            }
        }
 
        internal void PushNamespaceScope() {
            this.scopeManager.PushScope();
            NavigatorInput input  = Input;
 
            if (input.MoveToFirstNamespace()) {
                do {
                    this.scopeManager.PushNamespace(input.LocalName, input.Value);
                }
                while(input.MoveToNextNamespace());
                input.ToParent();
            }
        }
 
        protected InputScopeManager  ScopeManager {
            get { return this.scopeManager; }
        }
 
        internal virtual void PopScope() {
            this.currentTemplate.ReleaseVariableSlots(this.scopeManager.CurrentScope.GetVeriablesCount());
            this.scopeManager.PopScope();
        }
 
        internal InputScopeManager CloneScopeManager() {
            return this.scopeManager.Clone();
        }
 
        //
        // Variable support
        //
 
        internal int InsertVariable(VariableAction variable) {
            InputScope varScope;
            if (variable.IsGlobal) {
                Debug.Assert(this.rootAction != null);
                varScope = this.rootScope;
            }
            else {
                Debug.Assert(this.currentTemplate != null);
                Debug.Assert(variable.VarType == VariableType.LocalVariable || variable.VarType == VariableType.LocalParameter || variable.VarType == VariableType.WithParameter);
                varScope = this.scopeManager.VariableScope;
            }
 
            VariableAction oldVar = varScope.ResolveVariable(variable.Name);
            if (oldVar != null) {
                // Other variable with this name is visible in this scope
                if (oldVar.IsGlobal) {
                    if (variable.IsGlobal) {
                        // Global Vars replace each other base on import presidens odred
                        if (variable.Stylesheetid == oldVar.Stylesheetid) {
                            // Both vars are in the same stylesheet
                            throw XsltException.Create(Res.Xslt_DupVarName, variable.NameStr);
                        }
                        else if (variable.Stylesheetid < oldVar.Stylesheetid) {
                            // newly defined var is more importent
                            varScope.InsertVariable(variable);
                            return oldVar.VarKey;
                        }
                        else {
                            // we egnore new variable
                            return InvalidQueryKey; // We didn't add this var, so doesn't matter what VarKey we return;
                        }
                    }
                    else {
                        // local variable can shadow global
                    }
                }
                else {
                    // Local variable never can be "shadowed"
                    throw XsltException.Create(Res.Xslt_DupVarName, variable.NameStr);
                }
            }
 
            varScope.InsertVariable(variable);
            return this.currentTemplate.AllocateVariableSlot();
        }
 
        internal void AddNamespaceAlias(String StylesheetURI, NamespaceInfo AliasInfo){
            if (this.globalNamespaceAliasTable == null) {
                this.globalNamespaceAliasTable = new Hashtable();
            }
            NamespaceInfo duplicate = this.globalNamespaceAliasTable[StylesheetURI] as NamespaceInfo;
            if (duplicate == null || AliasInfo.stylesheetId <= duplicate.stylesheetId) {
                this.globalNamespaceAliasTable[StylesheetURI] = AliasInfo;
            }
        }
 
        internal bool IsNamespaceAlias(String StylesheetURI){
            if (this.globalNamespaceAliasTable == null) {
                return false;
            }
            return this.globalNamespaceAliasTable.Contains(StylesheetURI);
        }
 
        internal NamespaceInfo FindNamespaceAlias(String StylesheetURI) {
            if (this.globalNamespaceAliasTable != null) {
               return (NamespaceInfo)this.globalNamespaceAliasTable[StylesheetURI];
            }
            return null;
        }
 
        internal String ResolveXmlNamespace(String prefix) {
            return this.scopeManager.ResolveXmlNamespace(prefix);
        }
 
        internal String ResolveXPathNamespace(String prefix) {
            return this.scopeManager.ResolveXPathNamespace(prefix);
        }
 
        internal String DefaultNamespace {
            get{ return this.scopeManager.DefaultNamespace; }
        }
 
        internal void InsertKey(XmlQualifiedName name, int MatchKey, int UseKey) {
            this.rootAction.InsertKey(name, MatchKey, UseKey);
        }
 
        internal void AddDecimalFormat(XmlQualifiedName name, DecimalFormat formatinfo) {
            this.rootAction.AddDecimalFormat(name, formatinfo);
        }
 
        //
        // Attribute parsing support
        //
 
        // This function is for processing optional attributes only.  In case of error
        // the value is ignored iff forwards-compatible mode is on.
        private string[] ResolvePrefixes(string tokens) {
            if (tokens == null || tokens.Length == 0) {
                return null;
            }
            string[] nsList = XmlConvert.SplitString(tokens);
 
            try {
                for (int idx = 0; idx < nsList.Length; idx++) {
                    string prefix = nsList[idx];
                    nsList[idx] = scopeManager.ResolveXmlNamespace(prefix == "#default" ? string.Empty : prefix);
                }
            }
            catch (XsltException) {
                // The only exception here might be Res.Xslt_InvalidPrefix
                if (!ForwardCompatibility) {
                    // Rethrow the exception if we're not in forwards-compatible mode
                    throw;
                }
                // Ignore the whole list in forwards-compatible mode
                return null;
            }
            return nsList;
        }
 
        internal bool GetYesNo(string value) {
            Debug.Assert(value != null);
            Debug.Assert((object)value == (object)Input.Value); // this is always true. Why we passing value to this function.
            if (value == "yes") {
                return true;
            }
            if (value == "no") {
                return false;
            }
            throw XsltException.Create(Res.Xslt_InvalidAttrValue, Input.LocalName, value);
        }
 
        internal string GetSingleAttribute(string attributeAtom) {
            NavigatorInput input   = Input;
            string         element = input.LocalName;
            string         value   = null;
 
            if (input.MoveToFirstAttribute()) {
                do {
                    string nspace = input.NamespaceURI;
                    string name   = input.LocalName;
 
                    if (nspace.Length != 0) continue;
 
                    if (Ref.Equal(name, attributeAtom)) {
                        value = input.Value;
                    }
                    else {
                        if (! this.ForwardCompatibility) {
                            throw XsltException.Create(Res.Xslt_InvalidAttribute, name, element);
                        }
                    }
                }
                while (input.MoveToNextAttribute());
                input.ToParent();
            }
 
            if (value == null) {
                throw XsltException.Create(Res.Xslt_MissingAttribute, attributeAtom);
            }
            return value;
        }
 
        internal XmlQualifiedName CreateXPathQName(string qname) {
            string prefix, local;
            PrefixQName.ParseQualifiedName(qname, out prefix, out local);
 
            return new XmlQualifiedName(local, this.scopeManager.ResolveXPathNamespace(prefix));
        }
 
        internal XmlQualifiedName CreateXmlQName(string qname) {
            string prefix, local;
            PrefixQName.ParseQualifiedName(qname, out prefix, out local);
 
            return new XmlQualifiedName(local, this.scopeManager.ResolveXmlNamespace(prefix));
        }
 
        //
        // Input documents management
        //
 
        internal static XPathDocument LoadDocument(XmlTextReaderImpl reader) {
            reader.EntityHandling = EntityHandling.ExpandEntities;
            reader.XmlValidatingReaderCompatibilityMode = true;
            try {
                return new XPathDocument(reader, XmlSpace.Preserve);
            }
            finally {
                reader.Close();
            }
        }
 
        private void AddDocumentURI(string href) {
            Debug.Assert(!this.documentURIs.Contains(href), "Circular references must be checked while processing xsl:include and xsl:import");
            this.documentURIs.Add(href, null);
        }
 
        private void RemoveDocumentURI(string href) {
            Debug.Assert(this.documentURIs.Contains(href), "Attempt to remove href that was not added");
            this.documentURIs.Remove(href);
        }
 
        internal bool IsCircularReference(string href) {
            return this.documentURIs.Contains(href);
        }
 
        [ResourceConsumption(ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.Machine)]
        internal Uri ResolveUri(string relativeUri) {
            Debug.Assert(this.xmlResolver != null);
            string baseUri = this.Input.BaseURI;
            Uri uri = this.xmlResolver.ResolveUri((baseUri.Length != 0) ? this.xmlResolver.ResolveUri(null, baseUri) : null, relativeUri);
            if (uri == null) {
                throw XsltException.Create(Res.Xslt_CantResolve, relativeUri);
            }
            return uri;
        }
 
        [SuppressMessage("Microsoft.Security.Xml", "CA3068:TextReaderImplNeedsSettingsAndResolver", Justification="XmlResolver is set on XmlTextReaderImpl after it is constructed. Entities have expansion limit - exception granted on Feb 6 2018")]
        internal NavigatorInput ResolveDocument(Uri absoluteUri) {
            Debug.Assert(this.xmlResolver != null);
            object input = this.xmlResolver.GetEntity(absoluteUri, null, null);
            string resolved = absoluteUri.ToString();
 
            if (input is Stream) {
                XmlTextReaderImpl tr  = new XmlTextReaderImpl(resolved, (Stream) input); {
                    tr.XmlResolver = this.xmlResolver;
                }
                // reader is closed by Compiler.LoadDocument()
                return new NavigatorInput(Compiler.LoadDocument(tr).CreateNavigator(), resolved, rootScope);
            }
            else if (input is XPathNavigator) {
                return new NavigatorInput((XPathNavigator) input, resolved, rootScope);
            }
            else {
                throw XsltException.Create(Res.Xslt_CantResolve, resolved);
            }
        }
 
        internal void PushInputDocument(NavigatorInput newInput) {
            Debug.Assert(newInput != null);
            string inputUri = newInput.Href;
 
            AddDocumentURI(inputUri);
 
            newInput.Next     = this.input;
            this.input        = newInput;
            this.atoms        = this.input.Atoms;
            this.scopeManager = this.input.InputScopeManager;
        }
 
        internal void PopInputDocument() {
            Debug.Assert(this.input != null);
            Debug.Assert(this.input.Atoms == this.atoms);
 
            NavigatorInput lastInput = this.input;
 
            this.input     = lastInput.Next;
            lastInput.Next = null;
 
            if (this.input != null) {
                this.atoms        = this.input.Atoms;
                this.scopeManager = this.input.InputScopeManager;
            }
            else {
                this.atoms        = null;
                this.scopeManager = null;
            }
 
            RemoveDocumentURI(lastInput.Href);
            lastInput.Close();
        }
 
        //
        // Stylesheet management
        //
 
        internal void PushStylesheet(Stylesheet stylesheet) {
            if (this.stylesheets == null) {
                this.stylesheets = new Stack();
            }
            Debug.Assert(this.stylesheets != null);
 
            this.stylesheets.Push(stylesheet);
            this.stylesheet = stylesheet;
        }
 
        internal Stylesheet PopStylesheet() {
            Debug.Assert(this.stylesheet == this.stylesheets.Peek());
            Stylesheet stylesheet = (Stylesheet) this.stylesheets.Pop();
            this.stylesheet = (Stylesheet) this.stylesheets.Peek();
            return stylesheet;
        }
 
        //
        // Attribute-Set management
        //
 
        internal void AddAttributeSet(AttributeSetAction attributeSet) {
            Debug.Assert(this.stylesheet == this.stylesheets.Peek());
            this.stylesheet.AddAttributeSet(attributeSet);
        }
 
        //
        // Template management
        //
 
        internal void AddTemplate(TemplateAction template) {
            Debug.Assert(this.stylesheet == this.stylesheets.Peek());
            this.stylesheet.AddTemplate(template);
        }
 
        internal void BeginTemplate(TemplateAction template) {
            Debug.Assert(this.currentTemplate != null);
            this.currentTemplate = template;
            this.currentMode     = template.Mode;
            this.CanHaveApplyImports = template.MatchKey != Compiler.InvalidQueryKey;
        }
 
        internal void EndTemplate() {
            Debug.Assert(this.currentTemplate != null);
            this.currentTemplate = this.rootAction;
        }
 
        internal XmlQualifiedName CurrentMode {
            get { return this.currentMode; }
        }
 
        //
        // Query management
        //
        internal int AddQuery(string xpathQuery) {
            return AddQuery(xpathQuery, /*allowVars:*/true, /*allowKey*/true, false);
        }
 
        internal int AddQuery(string xpathQuery, bool allowVar, bool allowKey, bool isPattern) {
            Debug.Assert(this.queryStore != null);
 
            CompiledXpathExpr expr;
            try {
                expr = new CompiledXpathExpr(
                    (isPattern
                        ? this.queryBuilder.BuildPatternQuery(xpathQuery, allowVar, allowKey)
                        : this.queryBuilder.Build(            xpathQuery, allowVar, allowKey)
                    ),
                    xpathQuery,
                    false
                );
            } catch (XPathException e) {
                if (! ForwardCompatibility) {
                    throw XsltException.Create(Res.Xslt_InvalidXPath,  new string[] { xpathQuery }, e);
                }
                expr = new ErrorXPathExpression(xpathQuery, this.Input.BaseURI, this.Input.LineNumber, this.Input.LinePosition);
            }
            this.queryStore.Add(new TheQuery(expr, this.scopeManager));
            return this.queryStore.Count - 1;
        }
 
        internal int AddStringQuery(string xpathQuery) {
            string modifiedQuery = XmlCharType.Instance.IsOnlyWhitespace(xpathQuery) ? xpathQuery : "string(" + xpathQuery + ")";
            return AddQuery(modifiedQuery);
        }
 
        internal int AddBooleanQuery(string xpathQuery) {
            string modifiedQuery = XmlCharType.Instance.IsOnlyWhitespace(xpathQuery) ? xpathQuery : "boolean(" + xpathQuery + ")";
            return AddQuery(modifiedQuery);
        }
 
        //
        // Script support
        //
        Hashtable[] _typeDeclsByLang = new Hashtable[] { new Hashtable(), new Hashtable(), new Hashtable() };
        ArrayList   scriptFiles = new ArrayList();
        // Namespaces we always import when compiling
        private static string[] _defaultNamespaces = new string[] {
            "System",
            "System.Collections",
            "System.Text",
            "System.Text.RegularExpressions",
            "System.Xml",
            "System.Xml.Xsl",
            "System.Xml.XPath",
        };
 
        private static int scriptClassCounter = 0;
        private static string GenerateUniqueClassName() {
            return "ScriptClass_" + System.Threading.Interlocked.Increment(ref scriptClassCounter);
        }
 
        internal void AddScript(string source, ScriptingLanguage lang, string ns, string fileName, int lineNumber) {
            ValidateExtensionNamespace(ns);
 
            for (ScriptingLanguage langTmp = ScriptingLanguage.JScript; langTmp <= ScriptingLanguage.CSharp; langTmp ++) {
                Hashtable typeDecls = _typeDeclsByLang[(int)langTmp];
                if (lang == langTmp) {
                    CodeTypeDeclaration scriptClass = (CodeTypeDeclaration)typeDecls[ns];
                    if (scriptClass == null) {
                        scriptClass = new CodeTypeDeclaration(GenerateUniqueClassName());
                        scriptClass.TypeAttributes = TypeAttributes.Public;
                        typeDecls.Add(ns, scriptClass);
                    }
                    CodeSnippetTypeMember scriptSnippet = new CodeSnippetTypeMember(source);
                    if (lineNumber > 0) {
                        scriptSnippet.LinePragma = new CodeLinePragma(fileName, lineNumber);
                        scriptFiles.Add(fileName);
                    }
                    scriptClass.Members.Add(scriptSnippet);
                }
                else if (typeDecls.Contains(ns)) {
                    throw XsltException.Create(Res.Xslt_ScriptMixedLanguages, ns);
                }
            }
        }
 
        private static void ValidateExtensionNamespace(string nsUri) {
            if (nsUri.Length == 0 || nsUri == XmlReservedNs.NsXslt) {
                throw XsltException.Create(Res.Xslt_InvalidExtensionNamespace);
            }
            XmlConvert.ToUri(nsUri);
        }
 
        private void FixCompilerError(CompilerError e) {
            foreach(string scriptFile in this.scriptFiles) {
                if (e.FileName == scriptFile) {
                    return; // Yes! this error is in our code sippet.
                }
            }
            e.FileName = string.Empty;
        }
 
        CodeDomProvider ChooseCodeDomProvider(ScriptingLanguage lang) {
            return (
                lang == ScriptingLanguage.JScript     ? (CodeDomProvider) Activator.CreateInstance(Type.GetType("Microsoft.JScript.JScriptCodeProvider, " + AssemblyRef.MicrosoftJScript), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null) :
#if !FEATURE_PAL // visualbasic
                lang == ScriptingLanguage.VisualBasic ? (CodeDomProvider) new Microsoft.VisualBasic.VBCodeProvider() :
#endif
                /*CSharp | default */                   (CodeDomProvider) new Microsoft.CSharp.CSharpCodeProvider()
            );
        }
 
        private void CompileScript(Evidence evidence) {
            for (ScriptingLanguage lang = ScriptingLanguage.JScript; lang <= ScriptingLanguage.CSharp; lang ++) {
                int idx = (int)lang;
                if (_typeDeclsByLang[idx].Count > 0) {
                    CompileAssembly(lang, _typeDeclsByLang[idx], lang.ToString(), evidence);
                }
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        // SxS: This method does not take any resource name and does not expose any resources to the caller.
        // It's OK to suppress the SxS warning.
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)]
        private void CompileAssembly(ScriptingLanguage lang, Hashtable typeDecls, string nsName, Evidence evidence) {
            nsName = "Microsoft.Xslt.CompiledScripts." + nsName;
            CodeNamespace msXslt = new CodeNamespace(nsName);
 
            // Add all the default namespaces
            foreach(string ns in _defaultNamespaces) {
                msXslt.Imports.Add(new CodeNamespaceImport(ns));
            }
 
#if !FEATURE_PAL // visualbasic
            if (lang == ScriptingLanguage.VisualBasic) {
                msXslt.Imports.Add(new CodeNamespaceImport("Microsoft.VisualBasic"));
            }
#endif //!FEATURE_PAL
 
            foreach(CodeTypeDeclaration scriptClass in typeDecls.Values) {
                msXslt.Types.Add(scriptClass);
            }
 
            CodeCompileUnit unit = new CodeCompileUnit(); {
                unit.Namespaces.Add(msXslt);
                // This settings have sense for Visual Basic only.
                // We can consider in future to allow user set them in <xsl:script option="???"> attribute.
                unit.UserData["AllowLateBound"]             = true;  // Allow variables to be undeclared
                unit.UserData["RequireVariableDeclaration"] = false; // Allow variables to be declared untyped
            }
 
            // We want the assemblies generated for scripts to stick to the old security model
            unit.AssemblyCustomAttributes.Add(
                new CodeAttributeDeclaration(
                    new CodeTypeReference(typeof(System.Security.SecurityRulesAttribute)),
                    new CodeAttributeArgument(
                        new CodeFieldReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(System.Security.SecurityRuleSet)), "Level1"))));
 
            CompilerParameters compilParams = new CompilerParameters(); {
                try {
                    new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Assert();
                    try {
                        compilParams.GenerateInMemory = true;
#pragma warning disable 618
                        compilParams.Evidence = evidence;
#pragma warning restore 618
                        compilParams.ReferencedAssemblies.Add(typeof(XPathNavigator).Module.FullyQualifiedName);
                        compilParams.ReferencedAssemblies.Add("system.dll");
#if !FEATURE_PAL // visualbasic
                        if (lang == ScriptingLanguage.VisualBasic) {
                            compilParams.ReferencedAssemblies.Add("microsoft.visualbasic.dll");
                        }
#endif // !FEATURE_PAL
                    }
                    finally {
                        CodeAccessPermission.RevertAssert();
                    }
                } catch { throw; }
            }
 
            CompilerResults results = ChooseCodeDomProvider(lang).CompileAssemblyFromDom(compilParams, unit);
            if (results.Errors.HasErrors) {
                StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
                foreach (CompilerError e in results.Errors) {
                    FixCompilerError(e);
                    stringWriter.WriteLine(e.ToString());
                }
                throw XsltException.Create(Res.Xslt_ScriptCompileErrors, stringWriter.ToString());
            }
            Assembly assembly = results.CompiledAssembly;
            foreach(DictionaryEntry entry in typeDecls) {
                string ns = (string)entry.Key;
                CodeTypeDeclaration scriptClass = (CodeTypeDeclaration)entry.Value;
                this.stylesheet.ScriptObjectTypes.Add(ns, assembly.GetType(nsName + "." + scriptClass.Name));
            }
        }
 
        public string GetNsAlias(ref string prefix) {
            Debug.Assert(
                Ref.Equal(this.input.LocalName, this.input.Atoms.StylesheetPrefix) ||
                Ref.Equal(this.input.LocalName, this.input.Atoms.ResultPrefix)
            );
            if (prefix == "#default") {
                prefix = string.Empty;
                return this.DefaultNamespace;
            }
            else {
                if (! PrefixQName.ValidatePrefix(prefix)) {
                    throw XsltException.Create(Res.Xslt_InvalidAttrValue, this.input.LocalName, prefix);
                }
                return this.ResolveXPathNamespace(prefix);
            }
        }
 
        // AVT's compilation.
        // CompileAvt() returns ArrayList of TextEvent & AvtEvent
 
        private static void getTextLex(string avt, ref int start, StringBuilder lex) {
            Debug.Assert(avt.Length != start, "Empty string not supposed here");
            Debug.Assert(lex.Length == 0    , "Builder shoud to be reset here");
            int avtLength = avt.Length;
            int i;
            for (i = start; i < avtLength; i ++) {
                char ch = avt[i];
                if (ch == '{') {
                    if (i + 1 < avtLength && avt[i + 1] == '{') { // "{{"
                        i ++;
                    }
                    else {
                        break;
                    }
                }
                else if (ch == '}') {
                    if (i + 1 < avtLength && avt[i + 1] == '}') { // "}}"
                        i ++;
                    }
                    else {
                        throw XsltException.Create(Res.Xslt_SingleRightAvt, avt);
                    }
                }
                lex.Append(ch);
            }
            start = i;
        }
 
        private static void getXPathLex(string avt, ref int start, StringBuilder lex) {
            // AVT parser states
            const int InExp       = 0;      // Inside AVT expression
            const int InLiteralA  = 1;      // Inside literal in expression, apostrophe delimited
            const int InLiteralQ  = 2;      // Inside literal in expression, quote delimited
            Debug.Assert(avt.Length != start, "Empty string not supposed here");
            Debug.Assert(lex.Length == 0    , "Builder shoud to be reset here");
            Debug.Assert(avt[start] == '{'  , "We calling getXPathLex() only after we realy meet {");
            int avtLength = avt.Length;
            int state  = InExp;
            for (int i = start + 1; i < avtLength; i ++) {
                char ch = avt[i];
                switch(state) {
                case InExp :
                    switch (ch) {
                    case '{' :
                        throw XsltException.Create(Res.Xslt_NestedAvt, avt);
                    case '}' :
                        i ++; // include '}'
                        if (i == start + 2) { // empty XPathExpresion
                            throw XsltException.Create(Res.Xslt_EmptyAvtExpr, avt);
                        }
                        lex.Append(avt, start + 1, i - start - 2); // avt without {}
                        start = i;
                        return;
                    case '\'' :
                        state = InLiteralA;
                        break;
                    case '"' :
                        state = InLiteralQ;
                        break;
                    }
                    break;
                case InLiteralA :
                    if (ch == '\'') {
                        state = InExp;
                    }
                    break;
                case InLiteralQ :
                    if (ch == '"') {
                        state = InExp;
                    }
                    break;
                }
            }
 
            // if we meet end of string before } we have an error
            throw XsltException.Create(state == InExp ? Res.Xslt_OpenBracesAvt : Res.Xslt_OpenLiteralAvt, avt);
        }
 
        private static bool GetNextAvtLex(string avt, ref int start, StringBuilder lex, out bool isAvt) {
            Debug.Assert(start <= avt.Length);
#if DEBUG
            int saveStart = start;
#endif
            isAvt = false;
            if (start == avt.Length) {
                return false;
            }
            lex.Length = 0;
            getTextLex(avt, ref start, lex);
            if (lex.Length == 0) {
                isAvt = true;
                getXPathLex(avt, ref start, lex);
            }
#if DEBUG
            Debug.Assert(saveStart < start, "We have to read something. Otherwise it's dead loop.");
#endif
            return true;
        }
 
        internal ArrayList CompileAvt(string avtText, out bool constant) {
            Debug.Assert(avtText != null);
            ArrayList list = new ArrayList();
 
            constant = true;
            /* Parse input.Value as AVT */ {
                int  pos = 0;
                bool isAvt;
                while (GetNextAvtLex(avtText, ref pos, this.AvtStringBuilder, out isAvt)) {
                    string lex = this.AvtStringBuilder.ToString();
                    if (isAvt) {
                        list.Add(new AvtEvent(this.AddStringQuery(lex)));
                        constant = false;
                    }
                    else {
                        list.Add(new TextEvent(lex));
                    }
                }
            }
            Debug.Assert(!constant || list.Count <= 1, "We can't have more then 1 text event if now {avt} found");
            return list;
        }
 
        internal ArrayList CompileAvt(string avtText) {
            bool constant;
            return CompileAvt(avtText, out constant);
        }
 
        // Compiler is a class factory for some actions:
        // CompilerDbg override all this methods:
 
        public virtual ApplyImportsAction CreateApplyImportsAction() {
            ApplyImportsAction action = new ApplyImportsAction();
            action.Compile(this);
            return action;
        }
 
        public virtual ApplyTemplatesAction CreateApplyTemplatesAction() {
            ApplyTemplatesAction action = new ApplyTemplatesAction();
            action.Compile(this);
            return action;
        }
 
        public virtual AttributeAction CreateAttributeAction() {
            AttributeAction action = new AttributeAction();
            action.Compile(this);
            return action;
        }
 
        public virtual AttributeSetAction CreateAttributeSetAction() {
            AttributeSetAction action = new AttributeSetAction();
            action.Compile(this);
            return action;
        }
 
        public virtual CallTemplateAction CreateCallTemplateAction() {
            CallTemplateAction action = new CallTemplateAction();
            action.Compile(this);
            return action;
        }
 
        public virtual ChooseAction CreateChooseAction() {//!!! don't need to be here
            ChooseAction action = new ChooseAction();
            action.Compile(this);
            return action;
        }
 
        public virtual CommentAction CreateCommentAction() {
            CommentAction action = new CommentAction();
            action.Compile(this);
            return action;
        }
 
        public virtual CopyAction CreateCopyAction() {
            CopyAction action = new CopyAction();
            action.Compile(this);
            return action;
        }
 
        public virtual CopyOfAction CreateCopyOfAction() {
            CopyOfAction action = new CopyOfAction();
            action.Compile(this);
            return action;
        }
 
        public virtual ElementAction CreateElementAction() {
            ElementAction action = new ElementAction();
            action.Compile(this);
            return action;
        }
 
        public virtual ForEachAction CreateForEachAction() {
            ForEachAction action = new ForEachAction();
            action.Compile(this);
            return action;
        }
 
        public virtual IfAction CreateIfAction(IfAction.ConditionType type) {
            IfAction action = new IfAction(type);
            action.Compile(this);
            return action;
        }
 
        public virtual MessageAction CreateMessageAction() {
            MessageAction action = new MessageAction();
            action.Compile(this);
            return action;
        }
 
        public virtual NewInstructionAction CreateNewInstructionAction() {
            NewInstructionAction action = new NewInstructionAction();
            action.Compile(this);
            return action;
        }
 
        public virtual NumberAction CreateNumberAction() {
            NumberAction action = new NumberAction();
            action.Compile(this);
            return action;
        }
 
        public virtual ProcessingInstructionAction CreateProcessingInstructionAction() {
            ProcessingInstructionAction action = new ProcessingInstructionAction();
            action.Compile(this);
            return action;
        }
 
        public virtual void CreateRootAction() {
            this.RootAction = new RootAction();
            this.RootAction.Compile(this);
        }
 
        public virtual SortAction CreateSortAction() {
            SortAction action = new SortAction();
            action.Compile(this);
            return action;
        }
 
        public virtual TemplateAction CreateTemplateAction() {
            TemplateAction action = new TemplateAction();
            action.Compile(this);
            return action;
        }
 
        public virtual TemplateAction CreateSingleTemplateAction() {
            TemplateAction action = new TemplateAction();
            action.CompileSingle(this);
            return action;
        }
 
        public virtual TextAction CreateTextAction() {
            TextAction action = new TextAction();
            action.Compile(this);
            return action;
        }
 
        public virtual UseAttributeSetsAction CreateUseAttributeSetsAction() {
            UseAttributeSetsAction action = new UseAttributeSetsAction();
            action.Compile(this);
            return action;
        }
 
        public virtual ValueOfAction CreateValueOfAction() {
            ValueOfAction action = new ValueOfAction();
            action.Compile(this);
            return action;
        }
 
        public virtual VariableAction CreateVariableAction(VariableType type) {
            VariableAction action = new VariableAction(type);
            action.Compile(this);
            if (action.VarKey != InvalidQueryKey) {
                return action;
            }
            else {
                return null;
            }
        }
 
        public virtual WithParamAction CreateWithParamAction() {
            WithParamAction action = new WithParamAction();
            action.Compile(this);
            return action;
        }
 
        // Compiler is a class factory for some events:
        // CompilerDbg override all this methods:
 
        public virtual BeginEvent CreateBeginEvent() {
            return new BeginEvent(this);
        }
 
        public virtual TextEvent CreateTextEvent() {
            return new TextEvent(this);
        }
 
        public XsltException UnexpectedKeyword() {
            XPathNavigator nav = this.Input.Navigator.Clone();
            string thisName = nav.Name;
            nav.MoveToParent();
            string parentName = nav.Name;
            return XsltException.Create(Res.Xslt_UnexpectedKeyword, thisName, parentName);
        }
 
        internal class ErrorXPathExpression : CompiledXpathExpr {
            private string baseUri;
            private int lineNumber, linePosition;
            public ErrorXPathExpression(string expression, string baseUri, int lineNumber, int linePosition)
                :  base(null, expression, false)
            {
                this.baseUri      = baseUri;
                this.lineNumber   = lineNumber;
                this.linePosition = linePosition;
            }
 
            public override XPathExpression Clone() { return this; }
            public override void CheckErrors() {
                throw new XsltException(Res.Xslt_InvalidXPath, new string[] { Expression }, baseUri, linePosition, lineNumber, null);
            }
        }
    }
}