The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Xslt \ DecimalFormatDecl

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Compiler.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System.CodeDom.Compiler;
  16. using System.Collections.Generic;
  17. using System.Collections.ObjectModel;
  18. using System.Diagnostics;
  19. using System.Xml.XPath;
  20. using System.Xml.Xsl.Qil;
  21. using System.Xml.Xsl.XPath;
  22. namespace System.Xml.Xsl.Xslt
  23. {
  24.     using Res = System.Xml.Utils.Res;
  25.     using TypeFactory = XmlQueryTypeFactory;
  26.     using XmlILTrace = System.Xml.Xsl.IlGen.XmlILTrace;
  27.    
  28.     internal enum XslVersion
  29.     {
  30.         Version10 = 0,
  31.         ForwardsCompatible = 1,
  32.         Current = Version10
  33.     }
  34.    
  35.     internal class Compiler
  36.     {
  37.         public XsltSettings Settings;
  38.         public bool IsDebug;
  39.        
  40.         public CompilerResults CompilerResults;
  41.         // Results of the compilation
  42.         public Stylesheet PrincipalStylesheet;
  43.         // Principal stylesheet module
  44.         public int CurrentPrecedence = 0;
  45.         // Decreases by 1 with each import
  46.         public XslNode StartApplyTemplates;
  47.         public Scripts Scripts;
  48.         public Output Output = new Output();
  49.         public List<VarPar> ExternalPars = new List<VarPar>();
  50.         public List<VarPar> GlobalVars = new List<VarPar>();
  51.         public List<WhitespaceRule> WhitespaceRules = new List<WhitespaceRule>();
  52.         public DecimalFormats DecimalFormats = new DecimalFormats();
  53.         public Keys Keys = new Keys();
  54.         public List<ProtoTemplate> AllTemplates = new List<ProtoTemplate>();
  55.        
  56.         public Dictionary<QilName, VarPar> AllGlobalVarPars = new Dictionary<QilName, VarPar>();
  57.         public Dictionary<QilName, Template> NamedTemplates = new Dictionary<QilName, Template>();
  58.         public Dictionary<QilName, AttributeSet> AttributeSets = new Dictionary<QilName, AttributeSet>();
  59.         public Dictionary<string, NsAlias> NsAliases = new Dictionary<string, NsAlias>();
  60.         public Dictionary<QilName, XslFlags> ModeFlags = new Dictionary<QilName, XslFlags>();
  61.        
  62.         public Dictionary<QilName, List<QilFunction>> ApplyTemplatesFunctions = new Dictionary<QilName, List<QilFunction>>();
  63.        
  64.         public Compiler(XsltSettings settings)
  65.         {
  66.             Debug.Assert(CompilerResults == null, "Compiler cannot be reused");
  67.            
  68.             // Keep all intermediate files if tracing is enabled
  69.             TempFileCollection tempFiles = settings.TempFiles ?? new TempFileCollection();
  70.             if (XmlILTrace.IsEnabled) {
  71.                 tempFiles.KeepFiles = true;
  72.             }
  73.            
  74.             Settings = settings;
  75.             IsDebug = settings.IncludeDebugInformation;
  76.            
  77.             CompilerResults = new CompilerResults(tempFiles);
  78.             Scripts = new Scripts(this);
  79.         }
  80.        
  81.         public CompilerResults Compile(object stylesheet, XmlResolver xmlResolver, out QilExpression qil)
  82.         {
  83.             Debug.Assert(stylesheet != null);
  84.             Debug.Assert(PrincipalStylesheet == null, "Compiler cannot be reused");
  85.            
  86.             new XsltLoader().Load(this, stylesheet, xmlResolver);
  87.             qil = QilGenerator.CompileStylesheet(this);
  88.             return CompilerResults;
  89.         }
  90.        
  91.         public Stylesheet CreateStylesheet()
  92.         {
  93.             Stylesheet sheet = new Stylesheet(this, CurrentPrecedence);
  94.             if (CurrentPrecedence-- == 0) {
  95.                 PrincipalStylesheet = sheet;
  96.             }
  97.             return sheet;
  98.         }
  99.        
  100.         public void ApplyNsAliases(ref string prefix, ref string nsUri)
  101.         {
  102.             NsAlias alias;
  103.             if (NsAliases.TryGetValue(nsUri, out alias)) {
  104.                 nsUri = alias.ResultNsUri;
  105.                 prefix = alias.ResultPrefix;
  106.             }
  107.         }
  108.        
  109.         // Returns true in case of redefinition
  110.         public bool SetNsAlias(string ssheetNsUri, string resultNsUri, string resultPrefix, int importPrecedence)
  111.         {
  112.             NsAlias oldNsAlias;
  113.             if (NsAliases.TryGetValue(ssheetNsUri, out oldNsAlias)) {
  114.                 // Namespace alias for this stylesheet namespace URI has already been defined
  115.                 Debug.Assert(importPrecedence <= oldNsAlias.ImportPrecedence, "Stylesheets must be processed in the order of decreasing import precedence");
  116.                 if (importPrecedence < oldNsAlias.ImportPrecedence || resultNsUri == oldNsAlias.ResultNsUri) {
  117.                     // Either the identical definition or lower precedence - ignore it
  118.                     return false;
  119.                 }
  120.                 // Recover by choosing the declaration that occurs later in the stylesheet
  121.             }
  122.             NsAliases[ssheetNsUri] = new NsAlias(resultNsUri, resultPrefix, importPrecedence);
  123.             return oldNsAlias != null;
  124.         }
  125.        
  126.         private void MergeWhitespaceRules(Stylesheet sheet)
  127.         {
  128.             for (int idx = 0; idx <= 2; idx++) {
  129.                 sheet.WhitespaceRules[idx].Reverse();
  130.                 this.WhitespaceRules.AddRange(sheet.WhitespaceRules[idx]);
  131.             }
  132.             sheet.WhitespaceRules = null;
  133.         }
  134.        
  135.         private void MergeAttributeSets(Stylesheet sheet)
  136.         {
  137.             foreach (QilName attSetName in sheet.AttributeSets.Keys) {
  138.                 AttributeSet attSet;
  139.                 if (!this.AttributeSets.TryGetValue(attSetName, out attSet)) {
  140.                     this.AttributeSets[attSetName] = sheet.AttributeSets[attSetName];
  141.                 }
  142.                 else {
  143.                     // Lower import precedence - insert before all previous definitions
  144.                     attSet.MergeContent(sheet.AttributeSets[attSetName]);
  145.                 }
  146.             }
  147.             sheet.AttributeSets = null;
  148.         }
  149.        
  150.         private void MergeGlobalVarPars(Stylesheet sheet)
  151.         {
  152.             foreach (VarPar var in sheet.GlobalVarPars) {
  153.                 Debug.Assert(var.NodeType == XslNodeType.Variable || var.NodeType == XslNodeType.Param);
  154.                 if (!AllGlobalVarPars.ContainsKey(var.Name)) {
  155.                     if (var.NodeType == XslNodeType.Variable) {
  156.                         GlobalVars.Add(var);
  157.                     }
  158.                     else {
  159.                         ExternalPars.Add(var);
  160.                     }
  161.                     AllGlobalVarPars[var.Name] = var;
  162.                 }
  163.             }
  164.             sheet.GlobalVarPars = null;
  165.         }
  166.        
  167.         public void MergeWithStylesheet(Stylesheet sheet)
  168.         {
  169.             MergeWhitespaceRules(sheet);
  170.             MergeAttributeSets(sheet);
  171.             MergeGlobalVarPars(sheet);
  172.         }
  173.        
  174.         public static string ConstructQName(string prefix, string localName)
  175.         {
  176.             if (prefix.Length == 0) {
  177.                 return localName;
  178.             }
  179.             else {
  180.                 return prefix + ':' + localName;
  181.             }
  182.         }
  183.        
  184.         public bool ParseQName(string qname, out string prefix, out string localName, IErrorHelper errorHelper)
  185.         {
  186.             Debug.Assert(qname != null);
  187.             try {
  188.                 ValidateNames.ParseQNameThrow(qname, out prefix, out localName);
  189.                 return true;
  190.             }
  191.             catch (XmlException e) {
  192.                     /*[XT_042]*/                errorHelper.ReportError(e.Message, null);
  193.                 prefix = PhantomNCName;
  194.                 localName = PhantomNCName;
  195.                 return false;
  196.             }
  197.         }
  198.        
  199.         public bool ParseNameTest(string nameTest, out string prefix, out string localName, IErrorHelper errorHelper)
  200.         {
  201.             Debug.Assert(nameTest != null);
  202.             try {
  203.                 ValidateNames.ParseNameTestThrow(nameTest, out prefix, out localName);
  204.                 return true;
  205.             }
  206.             catch (XmlException e) {
  207.                     /*[XT_043]*/                errorHelper.ReportError(e.Message, null);
  208.                 prefix = PhantomNCName;
  209.                 localName = PhantomNCName;
  210.                 return false;
  211.             }
  212.         }
  213.        
  214.         public void ValidatePiName(string name, IErrorHelper errorHelper)
  215.         {
  216.             Debug.Assert(name != null);
  217.             try {
  218.                     /*prefix:*/                    /*localName:*/                    /*ns:*/                ValidateNames.ValidateNameThrow(string.Empty, name, string.Empty, XPathNodeType.ProcessingInstruction, ValidateNames.Flags.AllExceptPrefixMapping);
  219.             }
  220.             catch (XmlException e) {
  221.                     /*[XT_044]*/                errorHelper.ReportError(e.Message, null);
  222.             }
  223.         }
  224.        
  225.         public readonly string PhantomNCName = "error";
  226.         private int phantomNsCounter = 0;
  227.        
  228.         public string CreatePhantomNamespace()
  229.         {
  230.             // Prepend invalid XmlChar to ensure this name would not clash with any namespace name in the stylesheet
  231.             return "\0namespace" + phantomNsCounter++;
  232.         }
  233.        
  234.         public bool IsPhantomNamespace(string namespaceName)
  235.         {
  236.             return namespaceName.Length > 0 && namespaceName[0] == '\0';
  237.         }
  238.        
  239.         public bool IsPhantomName(QilName qname)
  240.         {
  241.             string nsUri = qname.NamespaceUri;
  242.             return nsUri.Length > 0 && nsUri[0] == '\0';
  243.         }
  244.        
  245.         // -------------------------------- Error Handling --------------------------------
  246.        
  247.         private int ErrorCount {
  248.             get { return CompilerResults.Errors.Count; }
  249.             set {
  250.                 Debug.Assert(value <= ErrorCount);
  251.                 for (int idx = ErrorCount - 1; idx >= value; idx--) {
  252.                     CompilerResults.Errors.RemoveAt(idx);
  253.                 }
  254.             }
  255.         }
  256.        
  257.         private int savedErrorCount = -1;
  258.        
  259.         public void EnterForwardsCompatible()
  260.         {
  261.             Debug.Assert(savedErrorCount == -1, "Nested EnterForwardsCompatible calls");
  262.             savedErrorCount = ErrorCount;
  263.         }
  264.        
  265.         // Returns true if no errors were suppressed
  266.         public bool ExitForwardsCompatible(bool fwdCompat)
  267.         {
  268.             Debug.Assert(savedErrorCount != -1, "ExitForwardsCompatible without EnterForwardsCompatible");
  269.             if (fwdCompat && ErrorCount > savedErrorCount) {
  270.                 ErrorCount = savedErrorCount;
  271.                 Debug.Assert((savedErrorCount = -1) < 0);
  272.                 return false;
  273.             }
  274.             Debug.Assert((savedErrorCount = -1) < 0);
  275.             return true;
  276.         }
  277.        
  278.         public CompilerError CreateError(ISourceLineInfo lineInfo, string res, params string[] args)
  279.         {
  280.                 /*errorNumber:*/                /*errorText:*/            return new CompilerError(lineInfo.Uri, lineInfo.StartLine, lineInfo.StartPos, string.Empty, XslTransformException.CreateMessage(res, args));
  281.         }
  282.        
  283.         public void ReportError(ISourceLineInfo lineInfo, string res, params string[] args)
  284.         {
  285.             CompilerError error = CreateError(lineInfo, res, args);
  286.             CompilerResults.Errors.Add(error);
  287.         }
  288.        
  289.         public void ReportWarning(ISourceLineInfo lineInfo, string res, params string[] args)
  290.         {
  291.             int warningLevel = 1;
  292.             if (0 <= Settings.WarningLevel && Settings.WarningLevel < warningLevel) {
  293.                 // Ignore warning
  294.                 return;
  295.             }
  296.             CompilerError error = CreateError(lineInfo, res, args);
  297.             if (Settings.TreatWarningsAsErrors) {
  298.                 error.ErrorText = XslTransformException.CreateMessage(Res.Xslt_WarningAsError, error.ErrorText);
  299.                 CompilerResults.Errors.Add(error);
  300.             }
  301.             else {
  302.                 error.IsWarning = true;
  303.                 CompilerResults.Errors.Add(error);
  304.             }
  305.         }
  306.     }
  307.    
  308.     internal class Output
  309.     {
  310.         public XmlWriterSettings Settings = new XmlWriterSettings();
  311.         public List<XmlQualifiedName> CDataSectionElements = new List<XmlQualifiedName>();
  312.         public string Version;
  313.         public string Encoding;
  314.         public XmlQualifiedName Method;
  315.        
  316.         // All the xsl:output elements occurring in a stylesheet are merged into a single effective xsl:output element.
  317.         // We store the import precedence of each attribute value to catch redefinitions with the same import precedence.
  318.         public const int NeverDeclaredPrec = int.MinValue;
  319.         public int MethodPrec = NeverDeclaredPrec;
  320.         public int VersionPrec = NeverDeclaredPrec;
  321.         public int EncodingPrec = NeverDeclaredPrec;
  322.         public int OmitXmlDeclarationPrec = NeverDeclaredPrec;
  323.         public int StandalonePrec = NeverDeclaredPrec;
  324.         public int DocTypePublicPrec = NeverDeclaredPrec;
  325.         public int DocTypeSystemPrec = NeverDeclaredPrec;
  326.         public int IndentPrec = NeverDeclaredPrec;
  327.         public int MediaTypePrec = NeverDeclaredPrec;
  328.        
  329.         public Output()
  330.         {
  331.             Settings.OutputMethod = XmlOutputMethod.AutoDetect;
  332.             Settings.AutoXmlDeclaration = true;
  333.             Settings.ConformanceLevel = ConformanceLevel.Auto;
  334.             Settings.MergeCDataSections = true;
  335.         }
  336.     }
  337.    
  338.     internal class DecimalFormats : KeyedCollection<XmlQualifiedName, DecimalFormatDecl>
  339.     {
  340.         protected override XmlQualifiedName GetKeyForItem(DecimalFormatDecl format)
  341.         {
  342.             return format.Name;
  343.         }
  344.     }
  345.    
  346.     internal class DecimalFormatDecl
  347.     {
  348.         public readonly XmlQualifiedName Name;
  349.         public readonly string InfinitySymbol;
  350.         public readonly string NanSymbol;
  351.         public readonly char[] Characters;
  352.        
  353.         public static DecimalFormatDecl Default = new DecimalFormatDecl(new XmlQualifiedName(), "Infinity", "NaN", ".,%‰0#;-");
  354.        
  355.         public DecimalFormatDecl(XmlQualifiedName name, string infinitySymbol, string nanSymbol, string characters)
  356.         {
  357.             Debug.Assert(characters.Length == 8);
  358.             this.Name = name;
  359.             this.InfinitySymbol = infinitySymbol;
  360.             this.NanSymbol = nanSymbol;
  361.             this.Characters = characters.ToCharArray();
  362.         }
  363.     }
  364.    
  365.     internal class NsAlias
  366.     {
  367.         public readonly string ResultNsUri;
  368.         public readonly string ResultPrefix;
  369.         public readonly int ImportPrecedence;
  370.        
  371.         public NsAlias(string resultNsUri, string resultPrefix, int importPrecedence)
  372.         {
  373.             this.ResultNsUri = resultNsUri;
  374.             this.ResultPrefix = resultPrefix;
  375.             this.ImportPrecedence = importPrecedence;
  376.         }
  377.     }
  378. }

Developer Fusion