Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,424 @@
//------------------------------------------------------------------------------
// <copyright file="Compiler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Xml.XPath;
using System.Xml.Xsl.Qil;
using System.Xml.Xsl.XPath;
using System.Runtime.Versioning;
namespace System.Xml.Xsl.Xslt {
using Res = System.Xml.Utils.Res;
using TypeFactory = XmlQueryTypeFactory;
#if DEBUG
using XmlILTrace = System.Xml.Xsl.IlGen.XmlILTrace;
#endif
internal enum XslVersion {
Version10 = 0,
ForwardsCompatible = 1,
Current = Version10,
}
// RootLevel is underdeveloped consept currently. I plane to move here more collections from Compiler.
// Compiler is like a stylesheet in some sense. it has a lot of properties of stylesheet. Instead of
// inhereting from Styleseet (or StylesheetLevel) I desided to agregate special subclass of StylesheetLevel.
// One more reason to for this design is to normolize apply-templates and apply-imports to one concept:
// apply-templates is apply-imports(compiler.Root).
// For now I don't create new files for these new classes to simplify integrations WebData <-> WebData_xsl
internal class RootLevel : StylesheetLevel {
public RootLevel(Stylesheet principal) {
base.Imports = new Stylesheet[] { principal };
}
}
internal class Compiler {
public XsltSettings Settings;
public bool IsDebug;
public string ScriptAssemblyPath;
public int Version; // 0 - Auto; 1 - XSLT 1.0; 2 - XSLT 2.0
public string inputTypeAnnotations; // null - "unspecified"; "preserve"; "strip"
public CompilerResults CompilerResults; // Results of the compilation
public int CurrentPrecedence = 0; // Decreases by 1 with each import
public XslNode StartApplyTemplates;
public RootLevel Root;
public Scripts Scripts;
public Output Output = new Output();
public List<VarPar> ExternalPars = new List<VarPar>();
public List<VarPar> GlobalVars = new List<VarPar>();
public List<WhitespaceRule> WhitespaceRules = new List<WhitespaceRule>();
public DecimalFormats DecimalFormats = new DecimalFormats();
public Keys Keys = new Keys();
public List<ProtoTemplate> AllTemplates = new List<ProtoTemplate>();
public Dictionary<QilName, VarPar> AllGlobalVarPars = new Dictionary<QilName, VarPar>();
public Dictionary<QilName, Template> NamedTemplates = new Dictionary<QilName, Template>();
public Dictionary<QilName, AttributeSet> AttributeSets = new Dictionary<QilName, AttributeSet>();
public Dictionary<string, NsAlias> NsAliases = new Dictionary<string, NsAlias>();
private Dictionary<string, int> moduleOrder = new Dictionary<string,int>();
public Compiler(XsltSettings settings, bool debug, string scriptAssemblyPath) {
Debug.Assert(CompilerResults == null, "Compiler cannot be reused");
// Keep all intermediate files if tracing is enabled
TempFileCollection tempFiles = settings.TempFiles ?? new TempFileCollection();
#if DEBUG
if (XmlILTrace.IsEnabled) {
tempFiles.KeepFiles = true;
}
#endif
Settings = settings;
IsDebug = settings.IncludeDebugInformation | debug;
ScriptAssemblyPath = scriptAssemblyPath;
CompilerResults = new CompilerResults(tempFiles);
Scripts = new Scripts(this);
}
[ResourceConsumption(ResourceScope.Machine)]
[ResourceExposure(ResourceScope.Machine)]
public CompilerResults Compile(object stylesheet, XmlResolver xmlResolver, out QilExpression qil) {
Debug.Assert(stylesheet != null);
Debug.Assert(Root == null, "Compiler cannot be reused");
new XsltLoader().Load(this, stylesheet, xmlResolver);
qil = QilGenerator.CompileStylesheet(this);
SortErrors();
return CompilerResults;
}
public Stylesheet CreateStylesheet() {
Stylesheet sheet = new Stylesheet(this, CurrentPrecedence);
if (CurrentPrecedence-- == 0) {
Root = new RootLevel(sheet);
}
return sheet;
}
public void AddModule(string baseUri) {
if (!moduleOrder.ContainsKey(baseUri)) {
moduleOrder[baseUri] = moduleOrder.Count;
}
}
public void ApplyNsAliases(ref string prefix, ref string nsUri) {
NsAlias alias;
if (NsAliases.TryGetValue(nsUri, out alias)) {
nsUri = alias.ResultNsUri;
prefix = alias.ResultPrefix;
}
}
// Returns true in case of redefinition
public bool SetNsAlias(string ssheetNsUri, string resultNsUri, string resultPrefix, int importPrecedence) {
NsAlias oldNsAlias;
if (NsAliases.TryGetValue(ssheetNsUri, out oldNsAlias)) {
// Namespace alias for this stylesheet namespace URI has already been defined
Debug.Assert(importPrecedence <= oldNsAlias.ImportPrecedence, "Stylesheets must be processed in the order of decreasing import precedence");
if (importPrecedence < oldNsAlias.ImportPrecedence || resultNsUri == oldNsAlias.ResultNsUri) {
// Either the identical definition or lower precedence - ignore it
return false;
}
// Recover by choosing the declaration that occurs later in the stylesheet
}
NsAliases[ssheetNsUri] = new NsAlias(resultNsUri, resultPrefix, importPrecedence);
return oldNsAlias != null;
}
private void MergeWhitespaceRules(Stylesheet sheet) {
for (int idx = 0; idx <= 2; idx++) {
sheet.WhitespaceRules[idx].Reverse();
this.WhitespaceRules.AddRange(sheet.WhitespaceRules[idx]);
}
sheet.WhitespaceRules = null;
}
private void MergeAttributeSets(Stylesheet sheet) {
foreach (QilName attSetName in sheet.AttributeSets.Keys) {
AttributeSet attSet;
if (!this.AttributeSets.TryGetValue(attSetName, out attSet)) {
this.AttributeSets[attSetName] = sheet.AttributeSets[attSetName];
} else {
// Lower import precedence - insert before all previous definitions
attSet.MergeContent(sheet.AttributeSets[attSetName]);
}
}
sheet.AttributeSets = null;
}
private void MergeGlobalVarPars(Stylesheet sheet) {
foreach (VarPar var in sheet.GlobalVarPars) {
Debug.Assert(var.NodeType == XslNodeType.Variable || var.NodeType == XslNodeType.Param);
if (!AllGlobalVarPars.ContainsKey(var.Name)) {
if (var.NodeType == XslNodeType.Variable) {
GlobalVars.Add(var);
} else {
ExternalPars.Add(var);
}
AllGlobalVarPars[var.Name] = var;
}
}
sheet.GlobalVarPars = null;
}
public void MergeWithStylesheet(Stylesheet sheet) {
MergeWhitespaceRules(sheet);
MergeAttributeSets(sheet);
MergeGlobalVarPars(sheet);
}
public static string ConstructQName(string prefix, string localName) {
if (prefix.Length == 0) {
return localName;
} else {
return prefix + ':' + localName;
}
}
public bool ParseQName(string qname, out string prefix, out string localName, IErrorHelper errorHelper) {
Debug.Assert(qname != null);
try {
ValidateNames.ParseQNameThrow(qname, out prefix, out localName);
return true;
}
catch (XmlException e) {
errorHelper.ReportError(/*[XT_042]*/e.Message, null);
prefix = PhantomNCName;
localName = PhantomNCName;
return false;
}
}
public bool ParseNameTest(string nameTest, out string prefix, out string localName, IErrorHelper errorHelper) {
Debug.Assert(nameTest != null);
try {
ValidateNames.ParseNameTestThrow(nameTest, out prefix, out localName);
return true;
}
catch (XmlException e) {
errorHelper.ReportError(/*[XT_043]*/e.Message, null);
prefix = PhantomNCName;
localName = PhantomNCName;
return false;
}
}
public void ValidatePiName(string name, IErrorHelper errorHelper) {
Debug.Assert(name != null);
try {
ValidateNames.ValidateNameThrow(
/*prefix:*/string.Empty, /*localName:*/name, /*ns:*/string.Empty,
XPathNodeType.ProcessingInstruction, ValidateNames.Flags.AllExceptPrefixMapping
);
}
catch (XmlException e) {
errorHelper.ReportError(/*[XT_044]*/e.Message, null);
}
}
public readonly string PhantomNCName = "error";
private int phantomNsCounter = 0;
public string CreatePhantomNamespace() {
// Prepend invalid XmlChar to ensure this name would not clash with any namespace name in the stylesheet
return "\0namespace" + phantomNsCounter++;
}
public bool IsPhantomNamespace(string namespaceName) {
return namespaceName.Length > 0 && namespaceName[0] == '\0';
}
public bool IsPhantomName(QilName qname) {
string nsUri = qname.NamespaceUri;
return nsUri.Length > 0 && nsUri[0] == '\0';
}
// -------------------------------- Error Handling --------------------------------
private int ErrorCount {
get {
return CompilerResults.Errors.Count;
}
set {
Debug.Assert(value <= ErrorCount);
for (int idx = ErrorCount - 1; idx >= value; idx--) {
CompilerResults.Errors.RemoveAt(idx);
}
}
}
private int savedErrorCount = -1;
public void EnterForwardsCompatible() {
Debug.Assert(savedErrorCount == -1, "Nested EnterForwardsCompatible calls");
savedErrorCount = ErrorCount;
}
// Returns true if no errors were suppressed
public bool ExitForwardsCompatible(bool fwdCompat) {
Debug.Assert(savedErrorCount != -1, "ExitForwardsCompatible without EnterForwardsCompatible");
if (fwdCompat && ErrorCount > savedErrorCount) {
ErrorCount = savedErrorCount;
Debug.Assert((savedErrorCount = -1) < 0);
return false;
}
Debug.Assert((savedErrorCount = -1) < 0);
return true;
}
public CompilerError CreateError(ISourceLineInfo lineInfo, string res, params string[] args) {
AddModule(lineInfo.Uri);
return new CompilerError(
lineInfo.Uri, lineInfo.Start.Line, lineInfo.Start.Pos, /*errorNumber:*/string.Empty,
/*errorText:*/XslTransformException.CreateMessage(res, args)
);
}
public void ReportError(ISourceLineInfo lineInfo, string res, params string[] args) {
CompilerError error = CreateError(lineInfo, res, args);
CompilerResults.Errors.Add(error);
}
public void ReportWarning(ISourceLineInfo lineInfo, string res, params string[] args) {
int warningLevel = 1;
if (0 <= Settings.WarningLevel && Settings.WarningLevel < warningLevel) {
// Ignore warning
return;
}
CompilerError error = CreateError(lineInfo, res, args);
if (Settings.TreatWarningsAsErrors) {
error.ErrorText = XslTransformException.CreateMessage(Res.Xslt_WarningAsError, error.ErrorText);
CompilerResults.Errors.Add(error);
} else {
error.IsWarning = true;
CompilerResults.Errors.Add(error);
}
}
private void SortErrors() {
CompilerErrorCollection errorColl = this.CompilerResults.Errors;
if (errorColl.Count > 1) {
CompilerError[] errors = new CompilerError[errorColl.Count];
errorColl.CopyTo(errors, 0);
Array.Sort<CompilerError>(errors, new CompilerErrorComparer(this.moduleOrder));
errorColl.Clear();
errorColl.AddRange(errors);
}
}
private class CompilerErrorComparer : IComparer<CompilerError> {
Dictionary<string, int> moduleOrder;
public CompilerErrorComparer(Dictionary<string, int> moduleOrder) {
this.moduleOrder = moduleOrder;
}
public int Compare(CompilerError x, CompilerError y) {
if ((object)x == (object)y)
return 0;
if (x == null)
return -1;
if (y == null)
return 1;
int result = moduleOrder[x.FileName].CompareTo(moduleOrder[y.FileName]);
if (result != 0)
return result;
result = x.Line.CompareTo(y.Line);
if (result != 0)
return result;
result = x.Column.CompareTo(y.Column);
if (result != 0)
return result;
result = x.IsWarning.CompareTo(y.IsWarning);
if (result != 0)
return result;
result = string.CompareOrdinal(x.ErrorNumber, y.ErrorNumber);
if (result != 0)
return result;
return string.CompareOrdinal(x.ErrorText, y.ErrorText);
}
}
}
internal class Output {
public XmlWriterSettings Settings;
public string Version;
public string Encoding;
public XmlQualifiedName Method;
// All the xsl:output elements occurring in a stylesheet are merged into a single effective xsl:output element.
// We store the import precedence of each attribute value to catch redefinitions with the same import precedence.
public const int NeverDeclaredPrec = int.MinValue;
public int MethodPrec = NeverDeclaredPrec;
public int VersionPrec = NeverDeclaredPrec;
public int EncodingPrec = NeverDeclaredPrec;
public int OmitXmlDeclarationPrec = NeverDeclaredPrec;
public int StandalonePrec = NeverDeclaredPrec;
public int DocTypePublicPrec = NeverDeclaredPrec;
public int DocTypeSystemPrec = NeverDeclaredPrec;
public int IndentPrec = NeverDeclaredPrec;
public int MediaTypePrec = NeverDeclaredPrec;
public Output() {
Settings = new XmlWriterSettings();
Settings.OutputMethod = XmlOutputMethod.AutoDetect;
Settings.AutoXmlDeclaration = true;
Settings.ConformanceLevel = ConformanceLevel.Auto;
Settings.MergeCDataSections = true;
}
}
internal class DecimalFormats : KeyedCollection<XmlQualifiedName, DecimalFormatDecl> {
protected override XmlQualifiedName GetKeyForItem(DecimalFormatDecl format) {
return format.Name;
}
}
internal class DecimalFormatDecl {
public readonly XmlQualifiedName Name;
public readonly string InfinitySymbol;
public readonly string NanSymbol;
public readonly char[] Characters;
public static DecimalFormatDecl Default = new DecimalFormatDecl(new XmlQualifiedName(), "Infinity", "NaN", ".,%\u20300#;-");
public DecimalFormatDecl(XmlQualifiedName name, string infinitySymbol, string nanSymbol, string characters) {
Debug.Assert(characters.Length == 8);
this.Name = name;
this.InfinitySymbol = infinitySymbol;
this.NanSymbol = nanSymbol;
this.Characters = characters.ToCharArray();
}
}
internal class NsAlias {
public readonly string ResultNsUri;
public readonly string ResultPrefix;
public readonly int ImportPrecedence;
public NsAlias(string resultNsUri, string resultPrefix, int importPrecedence) {
this.ResultNsUri = resultNsUri;
this.ResultPrefix = resultPrefix;
this.ImportPrecedence = importPrecedence;
}
}
}

View File

@@ -0,0 +1,353 @@
//------------------------------------------------------------------------------
// <copyright file="CompilerScopeManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
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<V> {
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); }
}
internal System.Collections.Generic.IEnumerable<ScopeRecord> GetActiveRecords() {
int currentRecord = this.lastRecord + 1;
// This logic comes from NamespaceEnumerator.MoveNext but also returns variables
while (LastPredefRecord < --currentRecord) {
if (records[currentRecord].IsNamespace) {
// This is a namespace declaration
if (LookupNamespace(records[currentRecord].ncName, lastRecord, currentRecord + 1) != null) {
continue;
}
// Its prefix has not been redefined later in [currentRecord + 1, lastRecord]
}
yield return records[currentRecord];
}
}
public NamespaceEnumerator GetEnumerator() {
return new NamespaceEnumerator(this);
}
internal struct NamespaceEnumerator {
CompilerScopeManager<V> scope;
int lastRecord;
int currentRecord;
public NamespaceEnumerator(CompilerScopeManager<V> 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];
}
}
}
}
}

View File

@@ -0,0 +1,201 @@
//------------------------------------------------------------------------------
// <copyright file="Focus.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Xsl.XPath;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.Xslt {
using T = XmlQueryTypeFactory;
// <spec>http://www.w3.org/TR/xslt20/#dt-singleton-focus</spec>
internal enum SingletonFocusType {
// No context set
// Used to prevent bugs
None,
// Document node of the document containing the initial context node
// Used while compiling global variables and params
InitialDocumentNode,
// Initial context node for the transformation
// Used while compiling initial apply-templates
InitialContextNode,
// Context node is specified by iterator
// Used while compiling keys
Iterator,
}
internal struct SingletonFocus : IFocus {
private XPathQilFactory f;
private SingletonFocusType focusType;
private QilIterator current;
public SingletonFocus(XPathQilFactory f) {
this.f = f;
focusType = SingletonFocusType.None;
current = null;
}
public void SetFocus(SingletonFocusType focusType) {
Debug.Assert(focusType != SingletonFocusType.Iterator);
this.focusType = focusType;
}
public void SetFocus(QilIterator current) {
if (current != null) {
this.focusType = SingletonFocusType.Iterator;
this.current = current;
} else {
this.focusType = SingletonFocusType.None;
this.current = null;
}
}
[Conditional("DEBUG")]
private void CheckFocus() {
Debug.Assert(focusType != SingletonFocusType.None, "Focus is not set, call SetFocus first");
}
public QilNode GetCurrent() {
CheckFocus();
switch (focusType) {
case SingletonFocusType.InitialDocumentNode: return f.Root(f.XmlContext());
case SingletonFocusType.InitialContextNode : return f.XmlContext();
default:
Debug.Assert(focusType == SingletonFocusType.Iterator && current != null, "Unexpected singleton focus type");
return current;
}
}
public QilNode GetPosition() {
CheckFocus();
return f.Double(1);
}
public QilNode GetLast() {
CheckFocus();
return f.Double(1);
}
}
internal struct FunctionFocus : IFocus {
private bool isSet;
private QilParameter current, position, last;
public void StartFocus(IList<QilNode> args, XslFlags flags) {
Debug.Assert(! IsFocusSet, "Focus was already set");
int argNum = 0;
if ((flags & XslFlags.Current) != 0) {
this.current = (QilParameter)args[argNum ++];
Debug.Assert(this.current.Name.NamespaceUri == XmlReservedNs.NsXslDebug && this.current.Name.LocalName == "current");
}
if ((flags & XslFlags.Position) != 0) {
this.position = (QilParameter)args[argNum ++];
Debug.Assert(this.position.Name.NamespaceUri == XmlReservedNs.NsXslDebug && this.position.Name.LocalName == "position");
}
if ((flags & XslFlags.Last) != 0) {
this.last = (QilParameter)args[argNum ++];
Debug.Assert(this.last.Name.NamespaceUri == XmlReservedNs.NsXslDebug && this.last.Name.LocalName == "last");
}
this.isSet = true;
}
public void StopFocus() {
Debug.Assert(IsFocusSet, "Focus was not set");
isSet = false;
this.current = this.position = this.last = null;
}
public bool IsFocusSet {
get { return this.isSet; }
}
public QilNode GetCurrent() {
Debug.Assert(this.current != null, "---- current() is not expected in this function");
return this.current;
}
public QilNode GetPosition() {
Debug.Assert(this.position != null, "---- position() is not expected in this function");
return this.position;
}
public QilNode GetLast() {
Debug.Assert(this.last != null, "---- last() is not expected in this function");
return this.last;
}
}
internal struct LoopFocus : IFocus {
private XPathQilFactory f;
private QilIterator current, cached, last;
public LoopFocus(XPathQilFactory f) {
this.f = f;
current = cached = last = null;
}
public void SetFocus(QilIterator current) {
this.current = current;
cached = last = null;
}
public bool IsFocusSet {
get { return current != null; }
}
public QilNode GetCurrent() {
return current;
}
public QilNode GetPosition() {
return f.XsltConvert(f.PositionOf(current), T.DoubleX);
}
public QilNode GetLast() {
if (last == null) {
// Create a let that will be fixed up later in ConstructLoop or by LastFixupVisitor
last = f.Let(f.Double(0));
}
return last;
}
public void EnsureCache() {
if (cached == null) {
cached = f.Let(current.Binding);
current.Binding = cached;
}
}
public void Sort(QilNode sortKeys) {
if (sortKeys != null) {
// If sorting is required, cache the input node-set to support last() within sort key expressions
EnsureCache();
// The rest of the loop content must be compiled in the context of already sorted node-set
current = f.For(f.Sort(current, sortKeys));
}
}
public QilLoop ConstructLoop(QilNode body) {
QilLoop result;
if (last != null) {
// last() encountered either in the sort keys or in the body of the current loop
EnsureCache();
last.Binding = f.XsltConvert(f.Length(cached), T.DoubleX);
}
result = f.BaseFactory.Loop(current, body);
if (last != null) {
result = f.BaseFactory.Loop(last, result);
}
if (cached != null) {
result = f.BaseFactory.Loop(cached, result);
}
return result;
}
}
}

View File

@@ -0,0 +1,16 @@
//------------------------------------------------------------------------------
// <copyright file="IErrorHelper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">antonl</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Xsl {
internal interface IErrorHelper {
void ReportError(string res, params string[] args);
void ReportWarning(string res, params string[] args);
}
}

View File

@@ -0,0 +1,148 @@
//------------------------------------------------------------------------------
// <copyright file="InvokeGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.Xslt {
using T = XmlQueryTypeFactory;
/**
InvokeGenerator is one of the trikest peaces here.
ARGS:
QilFunction func -- Functions which should be invoked. Arguments of this function (formalArgs) are Let nodes
anotated with names and default valies.
Problem 1 is that default values can contain references to previouse args of this function.
Problem 2 is that default values shouldn't contain fixup nodes.
ArrayList actualArgs -- Array of QilNodes anotated with names. When name of formalArg match name actualArg last one
is used as invokeArg, otherwise formalArg's default value is cloned and used.
**/
internal class InvokeGenerator : QilCloneVisitor {
private bool debug;
private Stack<QilIterator> iterStack;
private QilList formalArgs;
private QilList invokeArgs;
private int curArg; // this.Clone() depends on this value
private XsltQilFactory fac;
public InvokeGenerator(XsltQilFactory f, bool debug) : base(f.BaseFactory) {
this.debug = debug;
this.fac = f;
this.iterStack = new Stack<QilIterator>();
}
public QilNode GenerateInvoke(QilFunction func, IList<XslNode> actualArgs) {
iterStack.Clear();
formalArgs = func.Arguments;
invokeArgs = fac.ActualParameterList();
// curArg is an instance variable used in Clone() method
for (curArg = 0; curArg < formalArgs.Count; curArg ++) {
// Find actual value for a given formal arg
QilParameter formalArg = (QilParameter)formalArgs[curArg];
QilNode invokeArg = FindActualArg(formalArg, actualArgs);
// If actual value was not specified, use the default value and copy its debug comment
if (invokeArg == null) {
if (debug) {
if (formalArg.Name.NamespaceUri == XmlReservedNs.NsXslDebug) {
Debug.Assert(formalArg.Name.LocalName == "namespaces", "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs()");
Debug.Assert(formalArg.DefaultValue != null, "PrecompileProtoTemplatesHeaders() set it");
invokeArg = Clone(formalArg.DefaultValue);
} else {
invokeArg = fac.DefaultValueMarker();
}
} else {
Debug.Assert(formalArg.Name.NamespaceUri != XmlReservedNs.NsXslDebug, "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs(). We don't have $namespaces in !debug.");
invokeArg = Clone(formalArg.DefaultValue);
}
}
XmlQueryType formalType = formalArg.XmlType;
XmlQueryType invokeType = invokeArg.XmlType;
// Possible arg types: anyType, node-set, string, boolean, and number
fac.CheckXsltType(formalArg);
fac.CheckXsltType(invokeArg);
if (!invokeType.IsSubtypeOf(formalType)) {
// This may occur only if inferred type of invokeArg is XslFlags.None
Debug.Assert(invokeType == T.ItemS, "Actual argument type is not a subtype of formal argument type");
invokeArg = fac.TypeAssert(invokeArg, formalType);
}
invokeArgs.Add(invokeArg);
}
// Create Invoke node and wrap it with previous parameter declarations
QilNode invoke = fac.Invoke(func, invokeArgs);
while (iterStack.Count != 0)
invoke = fac.Loop(iterStack.Pop(), invoke);
return invoke;
}
private QilNode FindActualArg(QilParameter formalArg, IList<XslNode> actualArgs) {
QilName argName = formalArg.Name;
Debug.Assert(argName != null);
foreach (XslNode actualArg in actualArgs) {
if (actualArg.Name.Equals(argName)) {
return ((VarPar)actualArg).Value;
}
}
return null;
}
// ------------------------------------ QilCloneVisitor -------------------------------------
protected override QilNode VisitReference(QilNode n) {
QilNode replacement = FindClonedReference(n);
// If the reference is internal for the subtree being cloned, return it as is
if (replacement != null) {
return replacement;
}
// Replacement was not found, thus the reference is external for the subtree being cloned.
// The case when it refers to one of previous arguments (xsl:param can refer to previous
// xsl:param's) must be taken care of.
for (int prevArg = 0; prevArg < curArg; prevArg++) {
Debug.Assert(formalArgs[prevArg] != null, "formalArg must be in the list");
Debug.Assert(invokeArgs[prevArg] != null, "This arg should be compiled already");
// Is this a reference to prevArg?
if (n == formalArgs[prevArg]) {
// If prevArg is a literal, just clone it
if (invokeArgs[prevArg] is QilLiteral) {
return invokeArgs[prevArg].ShallowClone(fac.BaseFactory);
}
// If prevArg is not an iterator, cache it in an iterator, and return it
if (!(invokeArgs[prevArg] is QilIterator)) {
QilIterator var = fac.BaseFactory.Let(invokeArgs[prevArg]);
iterStack.Push(var);
invokeArgs[prevArg] = var;
}
Debug.Assert(invokeArgs[prevArg] is QilIterator);
return invokeArgs[prevArg];
}
}
// This is a truly external reference, return it as is
return n;
}
protected override QilNode VisitFunction(QilFunction n) {
// No need to change function references
return n;
}
}
}

View File

@@ -0,0 +1,111 @@
//------------------------------------------------------------------------------
// <copyright file="KeyMatchBuilder.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.XPath;
using MS.Internal.Xml;
using System.Xml.Xsl.XPath;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.Xslt {
internal class KeyMatchBuilder : XPathBuilder, XPathPatternParser.IPatternBuilder {
private int depth = 0;
PathConvertor convertor;
public KeyMatchBuilder(IXPathEnvironment env) : base(env) {
convertor = new PathConvertor(env.Factory);
}
public override void StartBuild() {
Debug.Assert(0 <= depth && depth <= 1, "this shouldn't happen");
if (depth == 0) {
base.StartBuild();
}
depth ++;
}
public override QilNode EndBuild(QilNode result) {
depth --;
Debug.Assert(0 <= depth && depth <= 1, "this shouldn't happen");
if (result == null) { // special door to clean builder state in exception handlers
return base.EndBuild(result);
}
if (depth == 0) {
Debug.Assert(base.numFixupLast == 0);
Debug.Assert(base.numFixupPosition == 0);
result = convertor.ConvertReletive2Absolute(result, base.fixupCurrent);
result = base.EndBuild(result);
}
return result;
}
// -------------------------------------- GetPredicateBuilder() ---------------------------------------
public virtual IXPathBuilder<QilNode> GetPredicateBuilder(QilNode ctx) {
return this;
}
// This code depends on particula shapes that XPathBuilder generates.
// It works only on pathes.
// ToDo: We can do better here.
internal class PathConvertor : QilReplaceVisitor {
new XPathQilFactory f;
QilNode fixup;
public PathConvertor(XPathQilFactory f) : base (f.BaseFactory) {
this.f = f;
}
public QilNode ConvertReletive2Absolute(QilNode node, QilNode fixup) {
QilDepthChecker.Check(node);
Debug.Assert(node != null);
Debug.Assert(fixup != null);
this.fixup = fixup;
return this.Visit(node);
}
// transparantly passing through Union and DocOrder
protected override QilNode Visit(QilNode n) {
if (
n.NodeType == QilNodeType.Union ||
n.NodeType == QilNodeType.DocOrderDistinct ||
n.NodeType == QilNodeType.Filter ||
n.NodeType == QilNodeType.Loop
) {
return base.Visit(n);
}
return n;
}
// Filers that travers Content being converted to global travers:
// Filter($j= ... Filter($i = Content(fixup), ...)) -> Filter($j= ... Filter($i = Loop($j = DesendentOrSelf(Root(fixup)), Content($j), ...)))
protected override QilNode VisitLoop(QilLoop n) {
if (n.Variable.Binding.NodeType == QilNodeType.Root || n.Variable.Binding.NodeType == QilNodeType.Deref) {
// This is absolute path already. We shouldn't touch it
return n;
}
if (n.Variable.Binding.NodeType == QilNodeType.Content) {
// This is "begin" of reletive path. Let's rewrite it as absolute:
QilUnary content = (QilUnary)n.Variable.Binding;
Debug.Assert(content.Child == this.fixup, "Unexpected content node");
QilIterator it = f.For(f.DescendantOrSelf(f.Root(this.fixup)));
content.Child = it;
n.Variable.Binding = f.Loop(it, content);
return n;
}
n.Variable.Binding = Visit(n.Variable.Binding);
return n;
}
protected override QilNode VisitFilter(QilLoop n) {
return VisitLoop(n);
}
}
}
}

View File

@@ -0,0 +1,253 @@
//------------------------------------------------------------------------------
// <copyright file="Keywords.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Xml;
namespace System.Xml.Xsl.Xslt {
internal class KeywordsTable {
public XmlNameTable NameTable;
public string AnalyzeString;
public string ApplyImports;
public string ApplyTemplates;
public string Assembly;
public string Attribute;
public string AttributeSet;
public string CallTemplate;
public string CaseOrder;
public string CDataSectionElements;
public string Character;
public string CharacterMap;
public string Choose;
public string Comment;
public string Copy;
public string CopyOf;
public string Count;
public string DataType;
public string DecimalFormat;
public string DecimalSeparator;
public string DefaultCollation;
public string DefaultValidation;
public string Digit;
public string DisableOutputEscaping;
public string DocTypePublic;
public string DocTypeSystem;
public string Document;
public string Element;
public string Elements;
public string Encoding;
public string ExcludeResultPrefixes;
public string ExtensionElementPrefixes;
public string Fallback;
public string ForEach;
public string ForEachGroup;
public string Format;
public string From;
public string Function;
public string GroupingSeparator;
public string GroupingSize;
public string Href;
public string Id;
public string If;
public string ImplementsPrefix;
public string Import;
public string ImportSchema;
public string Include;
public string Indent;
public string Infinity;
public string Key;
public string Lang;
public string Language;
public string LetterValue;
public string Level;
public string Match;
public string MatchingSubstring;
public string MediaType;
public string Message;
public string Method;
public string MinusSign;
public string Mode;
public string Name;
public string Namespace;
public string NamespaceAlias;
public string NaN;
public string NextMatch;
public string NonMatchingSubstring;
public string Number;
public string OmitXmlDeclaration;
public string Order;
public string Otherwise;
public string Output;
public string OutputCharacter;
public string OutputVersion;
public string Param;
public string PatternSeparator;
public string Percent;
public string PerformSort;
public string PerMille;
public string PreserveSpace;
public string Priority;
public string ProcessingInstruction;
public string Required;
public string ResultDocument;
public string ResultPrefix;
public string Script;
public string Select;
public string Separator;
public string Sequence;
public string Sort;
public string Space;
public string Standalone;
public string StripSpace;
public string Stylesheet;
public string StylesheetPrefix;
public string Template;
public string Terminate;
public string Test;
public string Text;
public string Transform;
public string UrnMsxsl;
public string UriXml;
public string UriXsl;
public string UriWdXsl;
public string Use;
public string UseAttributeSets;
public string UseWhen;
public string Using;
public string Value;
public string ValueOf;
public string Variable;
public string Version;
public string When;
public string WithParam;
public string Xml;
public string Xmlns;
public string XPathDefaultNamespace;
public string ZeroDigit;
public KeywordsTable(XmlNameTable nt) {
this.NameTable = nt;
AnalyzeString = nt.Add("analyze-string");
ApplyImports = nt.Add("apply-imports");
ApplyTemplates = nt.Add("apply-templates");
Assembly = nt.Add("assembly");
Attribute = nt.Add("attribute");
AttributeSet = nt.Add("attribute-set");
CallTemplate = nt.Add("call-template");
CaseOrder = nt.Add("case-order");
CDataSectionElements = nt.Add("cdata-section-elements");
Character = nt.Add("character");
CharacterMap = nt.Add("character-map");
Choose = nt.Add("choose");
Comment = nt.Add("comment");
Copy = nt.Add("copy");
CopyOf = nt.Add("copy-of");
Count = nt.Add("count");
DataType = nt.Add("data-type");
DecimalFormat = nt.Add("decimal-format");
DecimalSeparator = nt.Add("decimal-separator");
DefaultCollation = nt.Add("default-collation");
DefaultValidation = nt.Add("default-validation");
Digit = nt.Add("digit");
DisableOutputEscaping = nt.Add("disable-output-escaping");
DocTypePublic = nt.Add("doctype-public");
DocTypeSystem = nt.Add("doctype-system");
Document = nt.Add("document");
Element = nt.Add("element");
Elements = nt.Add("elements");
Encoding = nt.Add("encoding");
ExcludeResultPrefixes = nt.Add("exclude-result-prefixes");
ExtensionElementPrefixes = nt.Add("extension-element-prefixes");
Fallback = nt.Add("fallback");
ForEach = nt.Add("for-each");
ForEachGroup = nt.Add("for-each-group");
Format = nt.Add("format");
From = nt.Add("from");
Function = nt.Add("function");
GroupingSeparator = nt.Add("grouping-separator");
GroupingSize = nt.Add("grouping-size");
Href = nt.Add("href");
Id = nt.Add("id");
If = nt.Add("if");
ImplementsPrefix = nt.Add("implements-prefix");
Import = nt.Add("import");
ImportSchema = nt.Add("import-schema");
Include = nt.Add("include");
Indent = nt.Add("indent");
Infinity = nt.Add("infinity");
Key = nt.Add("key");
Lang = nt.Add("lang");
Language = nt.Add("language");
LetterValue = nt.Add("letter-value");
Level = nt.Add("level");
Match = nt.Add("match");
MatchingSubstring = nt.Add("matching-substring");
MediaType = nt.Add("media-type");
Message = nt.Add("message");
Method = nt.Add("method");
MinusSign = nt.Add("minus-sign");
Mode = nt.Add("mode");
Name = nt.Add("name");
Namespace = nt.Add("namespace");
NamespaceAlias = nt.Add("namespace-alias");
NaN = nt.Add("NaN");
NextMatch = nt.Add("next-match");
NonMatchingSubstring = nt.Add("non-matching-substring");
Number = nt.Add("number");
OmitXmlDeclaration = nt.Add("omit-xml-declaration");
Otherwise = nt.Add("otherwise");
Order = nt.Add("order");
Output = nt.Add("output");
OutputCharacter = nt.Add("output-character");
OutputVersion = nt.Add("output-version");
Param = nt.Add("param");
PatternSeparator = nt.Add("pattern-separator");
Percent = nt.Add("percent");
PerformSort = nt.Add("perform-sort");
PerMille = nt.Add("per-mille");
PreserveSpace = nt.Add("preserve-space");
Priority = nt.Add("priority");
ProcessingInstruction = nt.Add("processing-instruction");
Required = nt.Add("required");
ResultDocument = nt.Add("result-document");
ResultPrefix = nt.Add("result-prefix");
Script = nt.Add("script");
Select = nt.Add("select");
Separator = nt.Add("separator");
Sequence = nt.Add("sequence");
Sort = nt.Add("sort");
Space = nt.Add("space");
Standalone = nt.Add("standalone");
StripSpace = nt.Add("strip-space");
Stylesheet = nt.Add("stylesheet");
StylesheetPrefix = nt.Add("stylesheet-prefix");
Template = nt.Add("template");
Terminate = nt.Add("terminate");
Test = nt.Add("test");
Text = nt.Add("text");
Transform = nt.Add("transform");
UrnMsxsl = nt.Add(XmlReservedNs.NsMsxsl);
UriXml = nt.Add(XmlReservedNs.NsXml);
UriXsl = nt.Add(XmlReservedNs.NsXslt);
UriWdXsl = nt.Add(XmlReservedNs.NsWdXsl);
Use = nt.Add("use");
UseAttributeSets = nt.Add("use-attribute-sets");
UseWhen = nt.Add("use-when");
Using = nt.Add("using");
Value = nt.Add("value");
ValueOf = nt.Add("value-of");
Variable = nt.Add("variable");
Version = nt.Add("version");
When = nt.Add("when");
WithParam = nt.Add("with-param");
Xml = nt.Add("xml");
Xmlns = nt.Add("xmlns");
XPathDefaultNamespace = nt.Add("xpath-default-namespace");
ZeroDigit = nt.Add("zero-digit");
}
}
}

View File

@@ -0,0 +1,139 @@
//------------------------------------------------------------------------------
// <copyright file="OutputScopeManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml;
using System.Collections;
namespace System.Xml.Xsl.Xslt {
internal class OutputScopeManager {
public struct ScopeReord {
public int scopeCount;
public string prefix;
public string nsUri;
}
ScopeReord[] records = new ScopeReord[32];
int lastRecord = 0;
int lastScopes = 0; // This is cash 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.
public OutputScopeManager() {
Reset();
}
public void Reset() {
// AddNamespace(null, null); -- lookup barier
records[0].prefix = null;
records[0].nsUri = null;
PushScope();
}
public void PushScope() {
lastScopes ++;
}
public void PopScope() {
if (0 < lastScopes) {
lastScopes --;
}
else {
while(records[-- lastRecord].scopeCount == 0) ;
lastScopes = records[lastRecord].scopeCount;
lastScopes --;
}
}
// This can be ns declaration or ns exclussion. Las one when prefix == null;
public void AddNamespace(string prefix, string uri) {
Debug.Assert(prefix != null);
Debug.Assert(uri != null);
// uri = nameTable.Add(uri);
AddRecord(prefix, uri);
}
private void AddRecord(string prefix, string uri) {
records[lastRecord].scopeCount = lastScopes;
lastRecord ++;
if (lastRecord == records.Length) {
ScopeReord[] newRecords = new ScopeReord[lastRecord * 2];
Array.Copy(records, 0, newRecords, 0, lastRecord);
records = newRecords;
}
lastScopes = 0;
records[lastRecord].prefix = prefix;
records[lastRecord].nsUri = uri;
}
// There are some cases where we can't predict namespace content. To garantee correct results we should output all
// literal namespaces once again.
// <xsl:element name="{}" namespace="{}"> all prefixes should be invalidated
// <xsl:element name="{}" namespace="FOO"> all prefixes should be invalidated
// <xsl:element name="foo:A" namespace="{}"> prefixe "foo" should be invalidated
// <xsl:element name="foo:{}" namespace="{}"> prefixe "foo" should be invalidated
// <xsl:element name="foo:A" namespace="FOO"> no invalidations reqired
// <xsl:attribute name="{}" namespace="FOO"> all prefixes should be invalidated but not default ""
// <xsl:attribute name="foo:A" namespace="{}"> all prefixes should be invalidated but not default ""
// <xsl:element name="foo:A" namespace="FOO"> We can try to invalidate only foo prefix, but there to many thinks to consider here.
// So for now if attribute has non-null namespace it invalidates all prefixes in the
// scope of its element.
//
// <xsl:copy-of select="@*|namespace::*"> all prefixes are invalidated for the current element scope
// <xsl:copy-of select="/|*|text()|etc."> no invalidations needed
// <xsl:copy> if the node is either attribute or namespace, all prefixes are invalidated for the current element scope
// if the node is element, new scope is created, and all prefixes are invalidated
// otherwise, no invalidations needed
//// We need following methods:
//public void InvalidatePrefix(string prefix) {
// Debug.Assert(prefix != null);
// if (LookupNamespace(prefix) == null) { // This is optimisation. May be better just add this record?
// return;
// }
// AddRecord(prefix, null);
//}
public void InvalidateAllPrefixes() {
if (records[lastRecord].prefix == null) {
return; // Averything was invalidated already. Nothing to do.
}
AddRecord(null, null);
}
public void InvalidateNonDefaultPrefixes() {
string defaultNs = LookupNamespace(string.Empty);
if (defaultNs == null) { // We don't know default NS anyway.
InvalidateAllPrefixes();
}
else {
if (
records[lastRecord ].prefix.Length == 0 &&
records[lastRecord - 1].prefix == null
) {
return; // Averything was already done
}
AddRecord(null, null);
AddRecord(string.Empty, defaultNs);
}
}
public string LookupNamespace(string prefix) {
Debug.Assert(prefix != null);
for (
int record = lastRecord; // from last record
records[record].prefix != null; // till lookup barrier
-- record // in reverce direction
) {
Debug.Assert(0 < record, "first record is lookup bariaer, so we don't need to check this condition runtime");
if (records[record].prefix == prefix) {
return records[record].nsUri;
}
}
return null;
}
}
}

View File

@@ -0,0 +1 @@
d29bc0ca3bfac5ac64dab6111fbe9b18fbf1a03d

View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
// <copyright file="QilStrConcatenator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Diagnostics;
using System.Xml;
using System.Text;
using System.Xml.Schema;
using System.Xml.Xsl.XPath;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.Xslt {
internal class QilStrConcatenator {
private XPathQilFactory f;
private StringBuilder builder;
private QilList concat;
private bool inUse = false;
public QilStrConcatenator(XPathQilFactory f) {
this.f = f;
builder = new StringBuilder();
}
public void Reset() {
Debug.Assert(! inUse);
inUse = true;
builder.Length = 0;
concat = null;
}
private void FlushBuilder() {
if (concat == null) {
concat = f.BaseFactory.Sequence();
}
if (builder.Length != 0) {
concat.Add(f.String(builder.ToString()));
builder.Length = 0;
}
}
public void Append(string value) {
Debug.Assert(inUse, "Reset() wasn't called");
builder.Append(value);
}
public void Append(char value) {
Debug.Assert(inUse, "Reset() wasn't called");
builder.Append(value);
}
public void Append(QilNode value) {
Debug.Assert(inUse, "Reset() wasn't called");
if (value != null) {
Debug.Assert(value.XmlType.TypeCode == XmlTypeCode.String);
if (value.NodeType == QilNodeType.LiteralString) {
builder.Append((string)(QilLiteral)value);
} else {
FlushBuilder();
concat.Add(value);
}
}
}
public QilNode ToQil() {
Debug.Assert(inUse); // If we want allow multiple calls to ToQil() this logic should be changed
inUse = false;
if (concat == null) {
return f.String(builder.ToString());
} else {
FlushBuilder();
return f.StrConcat(concat);
}
}
}
}

View File

@@ -0,0 +1,389 @@
//------------------------------------------------------------------------------
// <copyright file="Scripts.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
// <spec>http://devdiv/Documents/Whidbey/CLR/CurrentSpecs/BCL/CodeDom%20Activation.doc</spec>
//------------------------------------------------------------------------------
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Security.Permissions;
using System.Threading;
using System.Xml.Xsl.IlGen;
using System.Xml.Xsl.Runtime;
using System.Runtime.Versioning;
namespace System.Xml.Xsl.Xslt {
using Res = System.Xml.Utils.Res;
internal class ScriptClass {
public string ns;
public CompilerInfo compilerInfo;
public StringCollection refAssemblies;
public StringCollection nsImports;
public CodeTypeDeclaration typeDecl;
public bool refAssembliesByHref;
public Dictionary<string, string> scriptUris;
// These two fields are used to report a compile error when its position is outside
// of all user code snippets in the generated temporary file
public string endUri;
public Location endLoc;
public ScriptClass(string ns, CompilerInfo compilerInfo) {
this.ns = ns;
this.compilerInfo = compilerInfo;
this.refAssemblies = new StringCollection();
this.nsImports = new StringCollection();
this.typeDecl = new CodeTypeDeclaration(GenerateUniqueClassName());
this.refAssembliesByHref = false;
this.scriptUris = new Dictionary<string, string>(
#if !FEATURE_CASE_SENSITIVE_FILESYSTEM
StringComparer.OrdinalIgnoreCase
#endif
);
}
private static long scriptClassCounter = 0;
private static string GenerateUniqueClassName() {
return "Script" + Interlocked.Increment(ref scriptClassCounter);
}
public void AddScriptBlock(string source, string uriString, int lineNumber, Location end) {
CodeSnippetTypeMember scriptSnippet = new CodeSnippetTypeMember(source);
string fileName = SourceLineInfo.GetFileName(uriString);
if (lineNumber > 0) {
scriptSnippet.LinePragma = new CodeLinePragma(fileName, lineNumber);
scriptUris[fileName] = uriString;
}
typeDecl.Members.Add(scriptSnippet);
this.endUri = uriString;
this.endLoc = end;
}
public ISourceLineInfo EndLineInfo {
get {
return new SourceLineInfo(this.endUri, this.endLoc, this.endLoc);
}
}
}
internal class Scripts {
private const string ScriptClassesNamespace = "System.Xml.Xsl.CompiledQuery";
private Compiler compiler;
private List<ScriptClass> scriptClasses = new List<ScriptClass>();
private Dictionary<string, Type> nsToType = new Dictionary<string, Type>();
private XmlExtensionFunctionTable extFuncs = new XmlExtensionFunctionTable();
public Scripts(Compiler compiler) {
this.compiler = compiler;
}
public Dictionary<string, Type> ScriptClasses {
get { return nsToType; }
}
public XmlExtensionFunction ResolveFunction(string name, string ns, int numArgs, IErrorHelper errorHelper) {
Type type;
if (nsToType.TryGetValue(ns, out type)) {
try {
return extFuncs.Bind(name, ns, numArgs, type, XmlQueryRuntime.EarlyBoundFlags);
}
catch (XslTransformException e) {
errorHelper.ReportError(e.Message);
}
}
return null;
}
public ScriptClass GetScriptClass(string ns, string language, IErrorHelper errorHelper) {
#if CONFIGURATION_DEP
CompilerInfo compilerInfo;
try {
compilerInfo = CodeDomProvider.GetCompilerInfo(language);
Debug.Assert(compilerInfo != null);
}
catch (ConfigurationException) {
// There is no CodeDom provider defined for this language
errorHelper.ReportError(/*[XT_010]*/Res.Xslt_ScriptInvalidLanguage, language);
return null;
}
foreach (ScriptClass scriptClass in scriptClasses) {
if (ns == scriptClass.ns) {
// Use object comparison because CompilerInfo.Equals may throw
if (compilerInfo != scriptClass.compilerInfo) {
errorHelper.ReportError(/*[XT_011]*/Res.Xslt_ScriptMixedLanguages, ns);
return null;
}
return scriptClass;
}
}
ScriptClass newScriptClass = new ScriptClass(ns, compilerInfo);
newScriptClass.typeDecl.TypeAttributes = TypeAttributes.Public;
scriptClasses.Add(newScriptClass);
return newScriptClass;
#else
return null;
#endif
}
//------------------------------------------------
// Compilation
//------------------------------------------------
public void CompileScripts() {
List<ScriptClass> scriptsForLang = new List<ScriptClass>();
for (int i = 0; i < scriptClasses.Count; i++) {
// If the script is already compiled, skip it
if (scriptClasses[i] == null)
continue;
// Group together scripts with the same CompilerInfo
CompilerInfo compilerInfo = scriptClasses[i].compilerInfo;
scriptsForLang.Clear();
for (int j = i; j < scriptClasses.Count; j++) {
// Use object comparison because CompilerInfo.Equals may throw
if (scriptClasses[j] != null && scriptClasses[j].compilerInfo == compilerInfo) {
scriptsForLang.Add(scriptClasses[j]);
scriptClasses[j] = null;
}
}
Assembly assembly = CompileAssembly(scriptsForLang);
if (assembly != null) {
foreach (ScriptClass script in scriptsForLang) {
Type clrType = assembly.GetType(ScriptClassesNamespace + Type.Delimiter + script.typeDecl.Name);
if (clrType != null) {
nsToType.Add(script.ns, clrType);
}
}
}
}
}
// Namespaces we always import when compiling
private static readonly string[] defaultNamespaces = new string[] {
"System",
"System.Collections",
"System.Text",
"System.Text.RegularExpressions",
"System.Xml",
"System.Xml.Xsl",
"System.Xml.XPath",
};
// 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.
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
private Assembly CompileAssembly(List<ScriptClass> scriptsForLang) {
TempFileCollection allTempFiles = compiler.CompilerResults.TempFiles;
CompilerErrorCollection allErrors = compiler.CompilerResults.Errors;
ScriptClass lastScript = scriptsForLang[scriptsForLang.Count - 1];
CodeDomProvider provider;
bool isVB = false;
try {
provider = lastScript.compilerInfo.CreateProvider();
}
catch (ConfigurationException e) {
// The CodeDom provider type could not be located, or some error in machine.config
allErrors.Add(compiler.CreateError(lastScript.EndLineInfo, /*[XT_041]*/Res.Xslt_ScriptCompileException, e.Message));
return null;
}
#if !FEATURE_PAL // visualbasic
isVB = provider is Microsoft.VisualBasic.VBCodeProvider;
#endif // !FEATURE_PAL
CodeCompileUnit[] codeUnits = new CodeCompileUnit[scriptsForLang.Count];
CompilerParameters compilParams = lastScript.compilerInfo.CreateDefaultCompilerParameters();
//
compilParams.ReferencedAssemblies.Add(typeof(System.Xml.Res).Assembly.Location);
compilParams.ReferencedAssemblies.Add("System.dll");
if (isVB) {
compilParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
}
bool refAssembliesByHref = false;
for (int idx = 0; idx < scriptsForLang.Count; idx++) {
ScriptClass script = scriptsForLang[idx];
CodeNamespace scriptNs = new CodeNamespace(ScriptClassesNamespace);
// Add imported namespaces
foreach (string ns in defaultNamespaces) {
scriptNs.Imports.Add(new CodeNamespaceImport(ns));
}
if (isVB) {
scriptNs.Imports.Add(new CodeNamespaceImport("Microsoft.VisualBasic"));
}
foreach (string ns in script.nsImports) {
scriptNs.Imports.Add(new CodeNamespaceImport(ns));
}
scriptNs.Types.Add(script.typeDecl);
CodeCompileUnit unit = new CodeCompileUnit(); {
unit.Namespaces.Add(scriptNs);
if (isVB) {
// This settings have sense for Visual Basic only. In future releases we may allow to specify
// them explicitly in the msxsl:script element.
unit.UserData["AllowLateBound"] = true; // Allow variables to be declared untyped
unit.UserData["RequireVariableDeclaration"] = false; // Allow variables to be undeclared
}
// Put SecurityTransparentAttribute and SecurityRulesAttribute on the first CodeCompileUnit only
if (idx == 0) {
unit.AssemblyCustomAttributes.Add(new CodeAttributeDeclaration("System.Security.SecurityTransparentAttribute"));
// 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"))));
}
}
codeUnits[idx] = unit;
foreach (string name in script.refAssemblies) {
compilParams.ReferencedAssemblies.Add(name);
}
refAssembliesByHref |= script.refAssembliesByHref;
}
XsltSettings settings = compiler.Settings;
compilParams.WarningLevel = settings.WarningLevel >= 0 ? settings.WarningLevel : compilParams.WarningLevel;
compilParams.TreatWarningsAsErrors = settings.TreatWarningsAsErrors;
compilParams.IncludeDebugInformation = compiler.IsDebug;
string asmPath = compiler.ScriptAssemblyPath;
if (asmPath != null && scriptsForLang.Count < scriptClasses.Count) {
asmPath = Path.ChangeExtension(asmPath, "." + GetLanguageName(lastScript.compilerInfo) + Path.GetExtension(asmPath));
}
compilParams.OutputAssembly = asmPath;
string tempDir = (settings.TempFiles != null) ? settings.TempFiles.TempDir : null;
compilParams.TempFiles = new TempFileCollection(tempDir);
// We need only .dll and .pdb, but there is no way to specify that
bool keepFiles = (compiler.IsDebug && asmPath == null);
#if DEBUG
keepFiles = keepFiles || XmlILTrace.IsEnabled;
#endif
keepFiles = keepFiles && !settings.CheckOnly;
compilParams.TempFiles.KeepFiles = keepFiles;
// If GenerateInMemory == true, then CodeDom loads the compiled assembly using Assembly.Load(byte[])
// instead of Assembly.Load(AssemblyName). That means the assembly will be loaded in the anonymous
// context (http://blogs.msdn.com/[....]/archive/2003/05/29/57143.aspx), and its dependencies can only
// be loaded from the Load context or using AssemblyResolve event. However we want to use the LoadFrom
// context to preload all dependencies specified by <ms:assembly href="uri-reference"/>, so we turn off
// GenerateInMemory here.
compilParams.GenerateInMemory = (asmPath == null && !compiler.IsDebug && !refAssembliesByHref) || settings.CheckOnly;
CompilerResults results;
try {
results = provider.CompileAssemblyFromDom(compilParams, codeUnits);
}
catch (ExternalException e) {
// Compiler might have created temporary files
results = new CompilerResults(compilParams.TempFiles);
results.Errors.Add(compiler.CreateError(lastScript.EndLineInfo, /*[XT_041]*/Res.Xslt_ScriptCompileException, e.Message));
}
if (!settings.CheckOnly) {
foreach (string fileName in results.TempFiles) {
allTempFiles.AddFile(fileName, allTempFiles.KeepFiles);
}
}
foreach (CompilerError error in results.Errors) {
FixErrorPosition(error, scriptsForLang);
compiler.AddModule(error.FileName);
}
allErrors.AddRange(results.Errors);
return results.Errors.HasErrors ? null : results.CompiledAssembly;
}
private int assemblyCounter = 0;
private string GetLanguageName(CompilerInfo compilerInfo) {
Regex alphaNumeric = new Regex("^[0-9a-zA-Z]+$");
foreach (string name in compilerInfo.GetLanguages()) {
if (alphaNumeric.IsMatch(name))
return name;
}
return "script" + (++assemblyCounter).ToString(CultureInfo.InvariantCulture);
}
// The position of a compile error may be outside of all user code snippets (for example, in case of
// unclosed '{'). In that case filename would be the name of the temporary file, and not the name
// of the stylesheet file. Exposing the path of the temporary file is considered to be a security issue,
// so here we check that filename is amongst user files.
private static void FixErrorPosition(CompilerError error, List<ScriptClass> scriptsForLang) {
string fileName = error.FileName;
string uri;
foreach (ScriptClass script in scriptsForLang) {
// We assume that CodeDom provider returns absolute paths (VSWhidbey 289665).
// Note that casing may be different.
if (script.scriptUris.TryGetValue(fileName, out uri)) {
// The error position is within one of user stylesheets, its URI may be reported
error.FileName = uri;
return;
}
}
// Error is outside user code snippeets, we should hide filename for security reasons.
// Return filename and position of the end of the last script block for the given class.
int idx, scriptNumber;
ScriptClass errScript = scriptsForLang[scriptsForLang.Count - 1];
// Normally temporary source files are named according to the scheme "<random name>.<script number>.
// <language extension>". Try to extract the middle part to find the relevant script class. In case
// of a non-standard CodeDomProvider, use the last script class.
fileName = Path.GetFileNameWithoutExtension(fileName);
if ((idx = fileName.LastIndexOf('.')) >= 0)
if (int.TryParse(fileName.Substring(idx + 1), NumberStyles.None, NumberFormatInfo.InvariantInfo, out scriptNumber))
if ((uint)scriptNumber < scriptsForLang.Count) {
errScript = scriptsForLang[scriptNumber];
}
error.FileName = errScript.endUri;
error.Line = errScript.endLoc.Line;
error.Column = errScript.endLoc.Pos;
}
}
}

View File

@@ -0,0 +1,120 @@
//------------------------------------------------------------------------------
// <copyright file="Stylesheet.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.Xslt {
internal class StylesheetLevel {
public Stylesheet[] Imports = null;
// If (this is Stylesheet) {
// ModeFlags and ApplyFunctions are abblout apply-imports
// } else {
// ModeFlags and ApplyFunctions are abblout apply-templates
// }
// mode -> FocusFlags; Used to generate and call apply-imports/apply-template functions
public Dictionary<QilName, XslFlags> ModeFlags = new Dictionary<QilName, XslFlags>();
// mode -> xsl:apply-import functions for that mode
public Dictionary<QilName, List<QilFunction>> ApplyFunctions = new Dictionary<QilName, List<QilFunction>>();
}
internal class Stylesheet : StylesheetLevel {
private Compiler compiler;
public List<Uri> ImportHrefs = new List<Uri>();
public List<XslNode> GlobalVarPars = new List<XslNode>();
// xsl:attribute-set/@name -> AttributeSet
public Dictionary<QilName, AttributeSet> AttributeSets = new Dictionary<QilName, AttributeSet>();
private int importPrecedence;
private int orderNumber = 0;
/*
WhitespaceRules[0] - rules with default priority 0
WhitespaceRules[1] - rules with default priority -0.25
WhitespaceRules[2] - rules with default priority -0.5
*/
public List<WhitespaceRule>[] WhitespaceRules = new List<WhitespaceRule>[3];
public List<Template> Templates = new List<Template>(); // Templates defined on this level. Empty for RootLevel.
// xsl:template/@mode -> list of @match'es
public Dictionary<QilName, List<TemplateMatch>> TemplateMatches = new Dictionary<QilName, List<TemplateMatch>>();
public void AddTemplateMatch(Template template, QilLoop filter) {
List<TemplateMatch> matchesForMode;
if (!TemplateMatches.TryGetValue(template.Mode, out matchesForMode)) {
matchesForMode = TemplateMatches[template.Mode] = new List<TemplateMatch>();
}
matchesForMode.Add(new TemplateMatch(template, filter));
}
public void SortTemplateMatches() {
foreach (QilName mode in TemplateMatches.Keys) {
TemplateMatches[mode].Sort(TemplateMatch.Comparer);
}
}
public Stylesheet(Compiler compiler, int importPrecedence) {
this.compiler = compiler;
this.importPrecedence = importPrecedence;
WhitespaceRules[0] = new List<WhitespaceRule>();
WhitespaceRules[1] = new List<WhitespaceRule>();
WhitespaceRules[2] = new List<WhitespaceRule>();
}
public int ImportPrecedence { get { return importPrecedence; } }
public void AddWhitespaceRule(int index, WhitespaceRule rule) {
WhitespaceRules[index].Add(rule);
}
public bool AddVarPar(VarPar var) {
Debug.Assert(var.NodeType == XslNodeType.Variable || var.NodeType == XslNodeType.Param);
Debug.Assert(var.Name.NamespaceUri != null, "Name must be resolved in XsltLoader");
foreach (XslNode prevVar in GlobalVarPars) {
if (prevVar.Name.Equals(var.Name)) {
// [ERR XT0630] It is a static error if a stylesheet contains more than one binding
// of a global variable with the same name and same import precedence, unless it also
// contains another binding with the same name and higher import precedence.
return compiler.AllGlobalVarPars.ContainsKey(var.Name);
}
}
GlobalVarPars.Add(var);
return true;
}
public bool AddTemplate(Template template) {
Debug.Assert(template.ImportPrecedence == 0);
template.ImportPrecedence = this.importPrecedence;
template.OrderNumber = this.orderNumber++;
compiler.AllTemplates.Add(template);
if (template.Name != null) {
Template old;
if (!compiler.NamedTemplates.TryGetValue(template.Name, out old)) {
compiler.NamedTemplates[template.Name] = template;
} else {
Debug.Assert(template.ImportPrecedence <= old.ImportPrecedence, "Global objects are processed in order of decreasing import precedence");
if (old.ImportPrecedence == template.ImportPrecedence) {
return false;
}
}
}
if (template.Match != null) {
Templates.Add(template);
}
return true;
}
}
}

View File

@@ -0,0 +1,403 @@
//------------------------------------------------------------------------------
// <copyright file="XPathPatternBuilder.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Xml.XPath;
using System.Xml.Schema;
using System.Xml.Xsl.Qil;
using System.Xml.Xsl.XPath;
namespace System.Xml.Xsl.Xslt {
using T = XmlQueryTypeFactory;
internal class XPathPatternBuilder : XPathPatternParser.IPatternBuilder {
private XPathPredicateEnvironment predicateEnvironment;
private XPathBuilder predicateBuilder;
private bool inTheBuild;
private XPathQilFactory f;
private QilNode fixupNode;
private IXPathEnvironment environment;
public XPathPatternBuilder(IXPathEnvironment environment) {
Debug.Assert(environment != null);
this.environment = environment;
this.f = environment.Factory;
this.predicateEnvironment = new XPathPredicateEnvironment(environment);
this.predicateBuilder = new XPathBuilder(predicateEnvironment);
this.fixupNode = f.Unknown(T.NodeNotRtfS);
}
public QilNode FixupNode {
get { return fixupNode; }
}
public virtual void StartBuild() {
Debug.Assert(! inTheBuild, "XPathBuilder is buisy!");
inTheBuild = true;
return;
}
[Conditional("DEBUG")]
public void AssertFilter(QilLoop filter) {
Debug.Assert(filter.NodeType == QilNodeType.Filter, "XPathPatternBuilder expected to generate list of Filters on top level");
Debug.Assert(filter.Variable.XmlType.IsSubtypeOf(T.NodeNotRtf));
Debug.Assert(filter.Variable.Binding.NodeType == QilNodeType.Unknown); // fixupNode
Debug.Assert(filter.Body.XmlType.IsSubtypeOf(T.Boolean));
}
private void FixupFilterBinding(QilLoop filter, QilNode newBinding) {
AssertFilter(filter);
filter.Variable.Binding = newBinding;
}
public virtual QilNode EndBuild(QilNode result) {
Debug.Assert(inTheBuild, "StartBuild() wasn't called");
if (result == null) {
// Special door to clean builder state in exception handlers
}
// All these variables will be positive for "false() and (. = position() + last())"
// since QilPatternFactory eliminates the right operand of 'and'
Debug.Assert(predicateEnvironment.numFixupCurrent >= 0, "Context fixup error");
Debug.Assert(predicateEnvironment.numFixupPosition >= 0, "Context fixup error");
Debug.Assert(predicateEnvironment.numFixupLast >= 0, "Context fixup error");
inTheBuild = false;
return result;
}
public QilNode Operator(XPathOperator op, QilNode left, QilNode right) {
Debug.Assert(op == XPathOperator.Union);
Debug.Assert(left != null);
Debug.Assert(right != null);
// It is important to not create nested lists here
Debug.Assert(right.NodeType == QilNodeType.Filter, "LocationPathPattern must be compiled into a filter");
if (left.NodeType == QilNodeType.Sequence) {
((QilList)left).Add(right);
return left;
} else {
Debug.Assert(left.NodeType == QilNodeType.Filter, "LocationPathPattern must be compiled into a filter");
return f.Sequence(left, right);
}
}
private static QilLoop BuildAxisFilter(QilPatternFactory f, QilIterator itr, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri) {
QilNode nameTest = (
name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar
nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:*
name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo
/*name == nsUri == null*/ f.True() // *
);
XmlNodeKindFlags intersection = XPathBuilder.AxisTypeMask(itr.XmlType.NodeKinds, nodeType, xpathAxis);
QilNode typeTest = (
intersection == 0 ? f.False() : // input & required doesn't intersect
intersection == itr.XmlType.NodeKinds ? f.True() : // input is subset of required
/*else*/ f.IsType(itr, T.NodeChoice(intersection))
);
QilLoop filter = f.BaseFactory.Filter(itr, f.And(typeTest, nameTest));
filter.XmlType = T.PrimeProduct(T.NodeChoice(intersection), filter.XmlType.Cardinality);
return filter;
}
public QilNode Axis(XPathAxis xpathAxis, XPathNodeType nodeType, string prefix, string name) {
Debug.Assert(
xpathAxis == XPathAxis.Child ||
xpathAxis == XPathAxis.Attribute ||
xpathAxis == XPathAxis.DescendantOrSelf ||
xpathAxis == XPathAxis.Root
);
QilLoop result;
double priority;
switch (xpathAxis) {
case XPathAxis.DescendantOrSelf :
Debug.Assert(nodeType == XPathNodeType.All && prefix == null && name == null, " // is the only d-o-s axes that we can have in pattern");
return f.Nop(this.fixupNode); // We using Nop as a flag that DescendantOrSelf exis was used between steps.
case XPathAxis.Root :
QilIterator i;
result = f.BaseFactory.Filter(i = f.For(fixupNode), f.IsType(i, T.Document));
priority = 0.5;
break;
default :
string nsUri = prefix == null ? null : this.environment.ResolvePrefix(prefix);
result = BuildAxisFilter(f, f.For(fixupNode), xpathAxis, nodeType, name, nsUri);
switch (nodeType) {
case XPathNodeType.Element :
case XPathNodeType.Attribute :
if (name != null) {
priority = 0;
} else {
if (prefix != null) {
priority = -0.25;
} else {
priority = -0.5;
}
}
break;
case XPathNodeType.ProcessingInstruction :
priority = name != null ? 0 : -0.5;
break;
default:
priority = -0.5;
break;
}
break;
}
SetPriority(result, priority);
SetLastParent(result, result);
return result;
}
// a/b/c -> self::c[parent::b[parent::a]]
// a/b//c -> self::c[ancestor::b[parent::a]]
// a/b -> self::b[parent::a]
// -> JoinStep(Axis('a'), Axis('b'))
// -> Filter('b' & Parent(Filter('a')))
// a//b
// -> JoinStep(Axis('a'), JoingStep(Axis(DescendantOrSelf), Axis('b')))
// -> JoinStep(Filter('a'), JoingStep(Nop(null), Filter('b')))
// -> JoinStep(Filter('a'), Nop(Filter('b')))
// -> Filter('b' & Ancestor(Filter('a')))
public QilNode JoinStep(QilNode left, QilNode right) {
Debug.Assert(left != null);
Debug.Assert(right != null);
if (left.NodeType == QilNodeType.Nop) {
QilUnary nop = (QilUnary)left;
Debug.Assert(nop.Child == this.fixupNode);
nop.Child = right; // We use Nop as a flag that DescendantOrSelf axis was used between steps.
return nop;
}
Debug.Assert(GetLastParent(left) == left, "Left is always single axis and never the step");
Debug.Assert(left.NodeType == QilNodeType.Filter);
CleanAnnotation(left);
QilLoop parentFilter = (QilLoop) left;
bool ancestor = false; {
if (right.NodeType == QilNodeType.Nop) {
ancestor = true;
QilUnary nop = (QilUnary)right;
Debug.Assert(nop.Child != null);
right = nop.Child;
}
}
Debug.Assert(right.NodeType == QilNodeType.Filter);
QilLoop lastParent = GetLastParent(right);
FixupFilterBinding(parentFilter, ancestor ? f.Ancestor(lastParent.Variable) : f.Parent(lastParent.Variable));
lastParent.Body = f.And(lastParent.Body, f.Not(f.IsEmpty(parentFilter)));
SetPriority(right, 0.5);
SetLastParent(right, parentFilter);
return right;
}
QilNode IXPathBuilder<QilNode>.Predicate(QilNode node, QilNode condition, bool isReverseStep) {
Debug.Assert(false, "Should not call to this function.");
return null;
}
//The structure of result is a Filter, variable is current node, body is the match condition.
//Previous predicate build logic in XPathPatternBuilder is match from right to left, which have 2^n complexiy when have lots of position predicates. TFS #368771
//Now change the logic to: If predicates contains position/last predicates, given the current node, filter out all the nodes that match the predicates,
//and then check if current node is in the result set.
public QilNode BuildPredicates(QilNode nodeset, List<QilNode> predicates) {
//convert predicates to boolean type
List<QilNode> convertedPredicates = new List<QilNode>(predicates.Count);
foreach (var predicate in predicates) {
convertedPredicates.Add(XPathBuilder.PredicateToBoolean(predicate, f, predicateEnvironment));
}
QilLoop nodeFilter = (QilLoop)nodeset;
QilIterator current = nodeFilter.Variable;
//If no last() and position() in predicates, use nodeFilter.Variable to fixup current
//because all the predicates only based on the input variable, no matter what other predicates are.
if (predicateEnvironment.numFixupLast == 0 && predicateEnvironment.numFixupPosition == 0) {
foreach (var predicate in convertedPredicates) {
nodeFilter.Body = f.And(nodeFilter.Body, predicate);
}
nodeFilter.Body = predicateEnvironment.fixupVisitor.Fixup(nodeFilter.Body, current, null);
}
//If any preidcate contains last() or position() node, then the current node is based on previous predicates,
//for instance, a[...][2] is match second node after filter 'a[...]' instead of second 'a'.
else {
//filter out the siblings
QilIterator parentIter = f.For(f.Parent(current));
QilNode sibling = f.Content(parentIter);
//generate filter based on input filter
QilLoop siblingFilter = (QilLoop)nodeset.DeepClone(f.BaseFactory);
siblingFilter.Variable.Binding = sibling;
siblingFilter = (QilLoop)f.Loop(parentIter, siblingFilter);
//build predicates from left to right to get all the matching nodes
QilNode matchingSet = siblingFilter;
foreach (var predicate in convertedPredicates) {
matchingSet = XPathBuilder.BuildOnePredicate(matchingSet, predicate, /*isReverseStep*/false,
f, predicateEnvironment.fixupVisitor,
ref predicateEnvironment.numFixupCurrent, ref predicateEnvironment.numFixupPosition, ref predicateEnvironment.numFixupLast);
}
//check if the matching nodes contains the current node
QilIterator matchNodeIter = f.For(matchingSet);
QilNode filterCurrent = f.Filter(matchNodeIter, f.Is(matchNodeIter, current));
nodeFilter.Body = f.Not(f.IsEmpty(filterCurrent));
//for passing type check, explict say the result is target type
nodeFilter.Body = f.And(f.IsType(current, nodeFilter.XmlType), nodeFilter.Body);
}
SetPriority(nodeset, 0.5);
return nodeset;
}
public QilNode Function(string prefix, string name, IList<QilNode> args) {
Debug.Assert(prefix.Length == 0);
QilIterator i = f.For(fixupNode);
QilNode matches;
if (name == "id") {
Debug.Assert(
args.Count == 1 && args[0].NodeType == QilNodeType.LiteralString,
"Function id() must have one literal string argument"
);
matches = f.Id(i, args[0]);
} else {
Debug.Assert(name == "key", "Unexpected function");
Debug.Assert(
args.Count == 2 &&
args[0].NodeType == QilNodeType.LiteralString && args[1].NodeType == QilNodeType.LiteralString,
"Function key() must have two literal string arguments"
);
matches = environment.ResolveFunction(prefix, name, args, new XsltFunctionFocus(i));
}
QilIterator j;
QilLoop result = f.BaseFactory.Filter(i, f.Not(f.IsEmpty(f.Filter(j = f.For(matches), f.Is(j, i)))));
SetPriority(result, 0.5);
SetLastParent(result, result);
return result;
}
public QilNode String(string value) { return f.String(value); } // As argument of id() or key() function
public QilNode Number(double value) { return UnexpectedToken("Literal number"); }
public QilNode Variable(string prefix, string name) { return UnexpectedToken("Variable"); }
private QilNode UnexpectedToken(string tokenName) {
string prompt = string.Format(CultureInfo.InvariantCulture, "Internal Error: {0} is not allowed in XSLT pattern outside of predicate.", tokenName);
Debug.Assert(false, prompt);
throw new Exception(prompt);
}
// -------------------------------------- Priority / Parent ---------------------------------------
private class Annotation {
public double Priority;
public QilLoop Parent;
}
public static void SetPriority(QilNode node, double priority) {
Annotation ann = (Annotation)node.Annotation ?? new Annotation();
ann.Priority = priority;
node.Annotation = ann;
}
public static double GetPriority(QilNode node) {
return ((Annotation)node.Annotation).Priority;
}
private static void SetLastParent(QilNode node, QilLoop parent) {
Debug.Assert(parent.NodeType == QilNodeType.Filter);
Annotation ann = (Annotation)node.Annotation ?? new Annotation();
ann.Parent = parent;
node.Annotation = ann;
}
private static QilLoop GetLastParent(QilNode node) {
return ((Annotation)node.Annotation).Parent;
}
public static void CleanAnnotation(QilNode node) {
node.Annotation = null;
}
// -------------------------------------- GetPredicateBuilder() ---------------------------------------
public IXPathBuilder<QilNode> GetPredicateBuilder(QilNode ctx) {
QilLoop context = (QilLoop) ctx;
Debug.Assert(context != null, "Predicate always has step so it can't have context == null");
Debug.Assert(context.Variable.NodeType == QilNodeType.For, "It shouldn't be Let, becaus predicates in PatternBuilder don't produce cached tuples.");
return predicateBuilder;
}
private class XPathPredicateEnvironment : IXPathEnvironment {
private readonly IXPathEnvironment baseEnvironment;
private readonly XPathQilFactory f;
public readonly XPathBuilder.FixupVisitor fixupVisitor;
private readonly QilNode fixupCurrent, fixupPosition, fixupLast;
// Number of unresolved fixup nodes
public int numFixupCurrent, numFixupPosition, numFixupLast;
public XPathPredicateEnvironment(IXPathEnvironment baseEnvironment) {
this.baseEnvironment = baseEnvironment;
this.f = baseEnvironment.Factory;
this.fixupCurrent = f.Unknown(T.NodeNotRtf);
this.fixupPosition = f.Unknown(T.DoubleX);
this.fixupLast = f.Unknown(T.DoubleX);
this.fixupVisitor = new XPathBuilder.FixupVisitor(f, fixupCurrent, fixupPosition, fixupLast);
}
/* ----------------------------------------------------------------------------
IXPathEnvironment interface
*/
public XPathQilFactory Factory { get { return f; } }
public QilNode ResolveVariable(string prefix, string name) {
return baseEnvironment.ResolveVariable(prefix, name);
}
public QilNode ResolveFunction(string prefix, string name, IList<QilNode> args, IFocus env) {
return baseEnvironment.ResolveFunction(prefix, name, args, env);
}
public string ResolvePrefix(string prefix) {
return baseEnvironment.ResolvePrefix(prefix);
}
public QilNode GetCurrent() { numFixupCurrent++; return fixupCurrent; }
public QilNode GetPosition() { numFixupPosition++; return fixupPosition; }
public QilNode GetLast() { numFixupLast++; return fixupLast; }
}
private class XsltFunctionFocus : IFocus {
private QilIterator current;
public XsltFunctionFocus(QilIterator current) {
Debug.Assert(current != null);
this.current = current;
}
/* ----------------------------------------------------------------------------
IFocus interface
*/
public QilNode GetCurrent() {
return current;
}
public QilNode GetPosition() {
Debug.Fail("GetPosition() must not be called");
return null;
}
public QilNode GetLast() {
Debug.Fail("GetLast() must not be called");
return null;
}
}
}
}

View File

@@ -0,0 +1,240 @@
//------------------------------------------------------------------------------
// <copyright file="XPathPatternParser.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Xml.Xsl.Qil;
using System.Xml.Xsl.XPath;
namespace System.Xml.Xsl.Xslt {
using XPathParser = XPathParser<QilNode>;
using XPathNodeType = System.Xml.XPath.XPathNodeType;
using Res = System.Xml.Utils.Res;
internal class XPathPatternParser {
public interface IPatternBuilder : IXPathBuilder<QilNode> {
IXPathBuilder<QilNode> GetPredicateBuilder(QilNode context);
}
XPathScanner scanner;
IPatternBuilder ptrnBuilder;
XPathParser predicateParser = new XPathParser();
public QilNode Parse(XPathScanner scanner, IPatternBuilder ptrnBuilder) {
Debug.Assert(this.scanner == null && this.ptrnBuilder == null);
Debug.Assert(scanner != null && ptrnBuilder != null);
QilNode result = null;
ptrnBuilder.StartBuild();
try {
this.scanner = scanner;
this.ptrnBuilder = ptrnBuilder;
result = this.ParsePattern();
this.scanner.CheckToken(LexKind.Eof);
} finally {
result = ptrnBuilder.EndBuild(result);
#if DEBUG
this.ptrnBuilder = null;
this.scanner = null;
#endif
}
return result;
}
/*
* Pattern ::= LocationPathPattern ('|' LocationPathPattern)*
*/
private QilNode ParsePattern() {
QilNode opnd = ParseLocationPathPattern();
while (scanner.Kind == LexKind.Union) {
scanner.NextLex();
opnd = ptrnBuilder.Operator(XPathOperator.Union, opnd, ParseLocationPathPattern());
}
return opnd;
}
/*
* LocationPathPattern ::= '/' RelativePathPattern? | '//'? RelativePathPattern | IdKeyPattern (('/' | '//') RelativePathPattern)?
*/
private QilNode ParseLocationPathPattern() {
QilNode opnd;
switch (scanner.Kind) {
case LexKind.Slash :
scanner.NextLex();
opnd = ptrnBuilder.Axis(XPathAxis.Root, XPathNodeType.All, null, null);
if (XPathParser.IsStep(scanner.Kind)) {
opnd = ptrnBuilder.JoinStep(opnd, ParseRelativePathPattern());
}
return opnd;
case LexKind.SlashSlash :
scanner.NextLex();
return ptrnBuilder.JoinStep(
ptrnBuilder.Axis(XPathAxis.Root, XPathNodeType.All, null, null),
ptrnBuilder.JoinStep(
ptrnBuilder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null),
ParseRelativePathPattern()
)
);
case LexKind.Name :
if (scanner.CanBeFunction && scanner.Prefix.Length == 0 && (scanner.Name == "id" || scanner.Name == "key")) {
opnd = ParseIdKeyPattern();
switch (scanner.Kind) {
case LexKind.Slash :
scanner.NextLex();
opnd = ptrnBuilder.JoinStep(opnd, ParseRelativePathPattern());
break;
case LexKind.SlashSlash :
scanner.NextLex();
opnd = ptrnBuilder.JoinStep(opnd,
ptrnBuilder.JoinStep(
ptrnBuilder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null),
ParseRelativePathPattern()
)
);
break;
}
return opnd;
}
break;
}
opnd = ParseRelativePathPattern();
return opnd;
}
/*
* IdKeyPattern ::= 'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')'
*/
private QilNode ParseIdKeyPattern() {
Debug.Assert(scanner.CanBeFunction);
Debug.Assert(scanner.Prefix.Length == 0);
Debug.Assert(scanner.Name == "id" || scanner.Name == "key");
List<QilNode> args = new List<QilNode>(2);
if (scanner.Name == "id") {
scanner.NextLex();
scanner.PassToken(LexKind.LParens);
scanner.CheckToken(LexKind.String);
args.Add(ptrnBuilder.String(scanner.StringValue));
scanner.NextLex();
scanner.PassToken(LexKind.RParens);
return ptrnBuilder.Function("", "id", args);
} else {
scanner.NextLex();
scanner.PassToken(LexKind.LParens);
scanner.CheckToken(LexKind.String);
args.Add(ptrnBuilder.String(scanner.StringValue));
scanner.NextLex();
scanner.PassToken(LexKind.Comma);
scanner.CheckToken(LexKind.String);
args.Add(ptrnBuilder.String(scanner.StringValue));
scanner.NextLex();
scanner.PassToken(LexKind.RParens);
return ptrnBuilder.Function("", "key", args);
}
}
/*
* RelativePathPattern ::= StepPattern (('/' | '//') StepPattern)*
*/
//Max depth to avoid StackOverflow
const int MaxParseRelativePathDepth = 1024;
private int parseRelativePath = 0;
private QilNode ParseRelativePathPattern() {
if (++parseRelativePath > MaxParseRelativePathDepth) {
if (System.Xml.XmlConfiguration.XsltConfigSection.LimitXPathComplexity) {
throw scanner.CreateException(System.Xml.Utils.Res.Xslt_InputTooComplex);
}
}
QilNode opnd = ParseStepPattern();
if (scanner.Kind == LexKind.Slash) {
scanner.NextLex();
opnd = ptrnBuilder.JoinStep(opnd, ParseRelativePathPattern());
} else if (scanner.Kind == LexKind.SlashSlash) {
scanner.NextLex();
opnd = ptrnBuilder.JoinStep(opnd,
ptrnBuilder.JoinStep(
ptrnBuilder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null),
ParseRelativePathPattern()
)
);
}
--parseRelativePath;
return opnd;
}
/*
* StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
* ChildOrAttributeAxisSpecifier ::= @ ? | ('child' | 'attribute') '::'
*/
private QilNode ParseStepPattern() {
QilNode opnd;
XPathAxis axis;
switch (scanner.Kind) {
case LexKind.Dot:
case LexKind.DotDot:
throw scanner.CreateException(Res.XPath_InvalidAxisInPattern);
case LexKind.At:
axis = XPathAxis.Attribute;
scanner.NextLex();
break;
case LexKind.Axis:
axis = scanner.Axis;
if (axis != XPathAxis.Child && axis != XPathAxis.Attribute) {
throw scanner.CreateException(Res.XPath_InvalidAxisInPattern);
}
scanner.NextLex(); // Skip '::'
scanner.NextLex();
break;
case LexKind.Name:
case LexKind.Star:
// NodeTest must start with Name or '*'
axis = XPathAxis.Child;
break;
default:
throw scanner.CreateException(Res.XPath_UnexpectedToken, scanner.RawValue);
}
XPathNodeType nodeType;
string nodePrefix, nodeName;
XPathParser.InternalParseNodeTest(scanner, axis, out nodeType, out nodePrefix, out nodeName);
opnd = ptrnBuilder.Axis(axis, nodeType, nodePrefix, nodeName);
XPathPatternBuilder xpathPatternBuilder = ptrnBuilder as XPathPatternBuilder;
if (xpathPatternBuilder != null) {
//for XPathPatternBuilder, get all predicates and then build them
List<QilNode> predicates = new List<QilNode>();
while (scanner.Kind == LexKind.LBracket) {
predicates.Add(ParsePredicate(opnd));
}
if (predicates.Count > 0)
opnd = xpathPatternBuilder.BuildPredicates(opnd, predicates);
}
else {
while (scanner.Kind == LexKind.LBracket) {
opnd = ptrnBuilder.Predicate(opnd, ParsePredicate(opnd), /*reverseStep:*/false);
}
}
return opnd;
}
/*
* Predicate ::= '[' Expr ']'
*/
private QilNode ParsePredicate(QilNode context) {
Debug.Assert(scanner.Kind == LexKind.LBracket);
scanner.NextLex();
QilNode result = predicateParser.Parse(scanner, ptrnBuilder.GetPredicateBuilder(context), LexKind.RBracket);
Debug.Assert(scanner.Kind == LexKind.RBracket);
scanner.NextLex();
return result;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
// <copyright file="XslFlags.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">sdub</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Xsl {
[Flags]
internal enum XslFlags {
None = 0x0000,
// XPath types flags. These flags indicate what type the result of the expression may have.
String = 0x0001,
Number = 0x0002,
Boolean = 0x0004,
Node = 0x0008,
Nodeset = 0x0010,
Rtf = 0x0020,
TypeFilter = AnyType,
AnyType = XslFlags.String | XslFlags.Number | XslFlags.Boolean | XslFlags.Node | XslFlags.Nodeset | XslFlags.Rtf,
// Focus flags. These flags indicate which of the three focus values (context item, context position,
// context size) are required for calculation of the expression.
Current = 0x0100,
Position = 0x0200,
Last = 0x0400,
FocusFilter = FullFocus,
FullFocus = XslFlags.Current | XslFlags.Position | XslFlags.Last,
// Indicates that the expression contains at least one of xsl:call-template, xsl:apply-templates,
// xsl:apply-imports, [xsl:]use-attribute-sets. Needed for default values of xsl:param's.
HasCalls = 0x1000,
// Used for xsl:param's only. Indicates that at least one caller does not pass value for this param,
// so its default value will be used.
MayBeDefault = 0x2000,
// Indicates that expression may produce side effects
// This flag is on for xsl:message and for calls to extension functions.
SideEffects = 0x4000,
// Indicates that the corresponding graph vertex has been already visited in flag propagation process.
Stop = 0x8000,
}
}

View File

@@ -0,0 +1,88 @@
//------------------------------------------------------------------------------
// <copyright file="XslVisitor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Xsl.Xslt {
internal abstract class XslVisitor<T> {
protected virtual T Visit(XslNode node) {
switch (node.NodeType) {
case XslNodeType.ApplyImports : return VisitApplyImports ((XslNode) node);
case XslNodeType.ApplyTemplates : return VisitApplyTemplates ((XslNode) node);
case XslNodeType.Attribute : return VisitAttribute ((NodeCtor) node);
case XslNodeType.AttributeSet : return VisitAttributeSet ((AttributeSet)node);
case XslNodeType.CallTemplate : return VisitCallTemplate ((XslNode) node);
case XslNodeType.Choose : return VisitChoose ((XslNode) node);
case XslNodeType.Comment : return VisitComment ((XslNode) node);
case XslNodeType.Copy : return VisitCopy ((XslNode) node);
case XslNodeType.CopyOf : return VisitCopyOf ((XslNode) node);
case XslNodeType.Element : return VisitElement ((NodeCtor) node);
case XslNodeType.Error : return VisitError ((XslNode) node);
case XslNodeType.ForEach : return VisitForEach ((XslNode) node);
case XslNodeType.If : return VisitIf ((XslNode) node);
case XslNodeType.Key : return VisitKey ((Key) node);
case XslNodeType.List : return VisitList ((XslNode) node);
case XslNodeType.LiteralAttribute : return VisitLiteralAttribute((XslNode) node);
case XslNodeType.LiteralElement : return VisitLiteralElement ((XslNode) node);
case XslNodeType.Message : return VisitMessage ((XslNode) node);
case XslNodeType.Nop : return VisitNop ((XslNode) node);
case XslNodeType.Number : return VisitNumber ((Number) node);
case XslNodeType.Otherwise : return VisitOtherwise ((XslNode) node);
case XslNodeType.Param : return VisitParam ((VarPar) node);
case XslNodeType.PI : return VisitPI ((XslNode) node);
case XslNodeType.Sort : return VisitSort ((Sort) node);
case XslNodeType.Template : return VisitTemplate ((Template) node);
case XslNodeType.Text : return VisitText ((Text) node);
case XslNodeType.UseAttributeSet : return VisitUseAttributeSet ((XslNode) node);
case XslNodeType.ValueOf : return VisitValueOf ((XslNode) node);
case XslNodeType.ValueOfDoe : return VisitValueOfDoe ((XslNode) node);
case XslNodeType.Variable : return VisitVariable ((VarPar) node);
case XslNodeType.WithParam : return VisitWithParam ((VarPar) node);
default : return VisitUnknown ((XslNode) node);
}
}
protected virtual T VisitApplyImports (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitApplyTemplates (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitAttribute (NodeCtor node) { return VisitChildren( node ); }
protected virtual T VisitAttributeSet (AttributeSet node) { return VisitChildren( node ); }
protected virtual T VisitCallTemplate (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitChoose (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitComment (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitCopy (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitCopyOf (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitElement (NodeCtor node) { return VisitChildren( node ); }
protected virtual T VisitError (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitForEach (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitIf (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitKey (Key node) { return VisitChildren( node ); }
protected virtual T VisitList (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitLiteralAttribute(XslNode node) { return VisitChildren( node ); }
protected virtual T VisitLiteralElement (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitMessage (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitNop (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitNumber (Number node) { return VisitChildren( node ); }
protected virtual T VisitOtherwise (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitParam (VarPar node) { return VisitChildren( node ); }
protected virtual T VisitPI (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitSort (Sort node) { return VisitChildren( node ); }
protected virtual T VisitTemplate (Template node) { return VisitChildren( node ); }
protected virtual T VisitText (Text node) { return VisitChildren( node ); }
protected virtual T VisitUseAttributeSet (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitValueOf (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitValueOfDoe (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitVariable (VarPar node) { return VisitChildren( node ); }
protected virtual T VisitWithParam (VarPar node) { return VisitChildren( node ); }
protected virtual T VisitUnknown (XslNode node) { return VisitChildren( node ); }
protected virtual T VisitChildren(XslNode node) {
foreach (XslNode child in node.Content) {
this.Visit(child);
}
return default(T);
}
}
}

Some files were not shown because too many files have changed in this diff Show More