Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / Xslt / XslAst.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XslAst.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 using System.Text;
9 using System.Collections.Generic;
10 using System.Collections.ObjectModel;
11 using System.Diagnostics;
12 using System.Globalization;
13 using System.Xml.Xsl.Qil;
14
15 namespace System.Xml.Xsl.Xslt {
16     using ContextInfo     = XsltInput.ContextInfo;
17     using XPathQilFactory = System.Xml.Xsl.XPath.XPathQilFactory;
18
19     // Set of classes that represent XSLT AST
20
21     // XSLT AST is a tree of nodes that represent content of xsl template.
22     // All nodes are subclasses of QilNode. This was done to keep NodeCtor and Text ctors
23     // the sames nodes thay will be in resulting QilExpression tree.
24     // So we have: ElementCtor, AttributeCtor, QilTextCtor, CommentCtor, PICtor, NamespaceDecl, List.
25     // Plus couple subclasses of XslNode that represent different xslt instructions
26     // including artifitial: Sort, ExNamespaceDecl, UseAttributeSets
27
28     internal enum XslNodeType {
29         Unknown = 0,
30         ApplyImports,
31         ApplyTemplates,
32         Attribute,
33         AttributeSet,
34         CallTemplate,
35         Choose,
36         Comment,
37         Copy,
38         CopyOf,
39         Element,
40         Error,
41         ForEach,
42         If,
43         Key,
44         List,
45         LiteralAttribute,
46         LiteralElement,
47         Message,
48         Nop,
49         Number,
50         Otherwise,
51         Param,
52         PI,
53         Sort,
54         Template,
55         Text,
56         UseAttributeSet,
57         ValueOf,
58         ValueOfDoe,
59         Variable,
60         WithParam,
61     }
62
63     internal class NsDecl {
64         public readonly NsDecl Prev;
65         public readonly string Prefix;  // Empty string denotes the default namespace, null - extension or excluded namespace
66         public readonly string NsUri;   // null means "#all" -- all namespace defined above this one are excluded.
67
68         public NsDecl(NsDecl prev, string prefix, string nsUri) {
69             Debug.Assert(nsUri != null || Prefix == null);
70             this.Prev   = prev;
71             this.Prefix = prefix;
72             this.NsUri  = nsUri;
73         }
74     }
75
76     internal class XslNode {
77         public readonly XslNodeType NodeType;
78         public ISourceLineInfo      SourceLine;
79         public NsDecl               Namespaces;
80         public readonly QilName     Name;   // name or mode
81         public readonly object      Arg;    // select or test or terminate or stylesheet;-)
82         public readonly XslVersion  XslVersion;
83         public XslFlags             Flags;
84         private List<XslNode>       content;
85
86         public XslNode(XslNodeType nodeType, QilName name, object arg, XslVersion xslVer) {
87             this.NodeType   = nodeType;
88             this.Name       = name;
89             this.Arg        = arg;
90             this.XslVersion = xslVer;
91         }
92
93         public XslNode(XslNodeType nodeType) {
94             this.NodeType   = nodeType;
95             this.XslVersion = XslVersion.Current;
96         }
97
98         public string   Select              { get { return (string)Arg; } }
99         public bool     ForwardsCompatible  { get { return XslVersion == XslVersion.ForwardsCompatible; } }
100
101         // -------------------------------- Content Management --------------------------------
102
103         private static readonly IList<XslNode> EmptyList = new List<XslNode>().AsReadOnly();
104
105         public IList<XslNode> Content {
106             get { return content ?? EmptyList; }
107         }
108
109         public void SetContent(List<XslNode> content) {
110             this.content = content;
111         }
112
113         public void AddContent(XslNode node) {
114             Debug.Assert(node != null);
115             if (content == null) {
116                 content = new List<XslNode>();
117             }
118             content.Add(node);
119         }
120
121         public void InsertContent(IEnumerable<XslNode> collection) {
122             if (content == null) {
123                 content = new List<XslNode>(collection);
124             } else {
125                 content.InsertRange(0, collection);
126             }
127         }
128
129         internal string TraceName {
130             get {
131             #if DEBUG
132                 System.Text.StringBuilder sb = new System.Text.StringBuilder();
133                 string nodeTypeName;
134                 switch (NodeType) {
135                 case XslNodeType.AttributeSet : nodeTypeName = "attribute-set"; break;
136                 case XslNodeType.Template     : nodeTypeName = "template";      break;
137                 case XslNodeType.Param        : nodeTypeName = "param";         break;
138                 case XslNodeType.Variable     : nodeTypeName = "variable";      break;
139                 case XslNodeType.WithParam    : nodeTypeName = "with-param";    break;
140                 default                       : nodeTypeName = NodeType.ToString(); break;
141                 }
142                 sb.Append(nodeTypeName);
143                 if (Name != null) {
144                     sb.Append(' ');
145                     sb.Append(Name.QualifiedName);
146                 }
147                 ISourceLineInfo lineInfo = SourceLine;
148                 if (lineInfo == null && NodeType == XslNodeType.AttributeSet) {
149                     lineInfo = Content[0].SourceLine;
150                     Debug.Assert(lineInfo != null);
151                 }
152                 if (lineInfo != null) {
153                     string fileName = SourceLineInfo.GetFileName(lineInfo.Uri);
154                     int idx = fileName.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1;
155                     sb.Append(" (");
156                     sb.Append(fileName, idx, fileName.Length - idx);
157                     sb.Append(':');
158                     sb.Append(lineInfo.Start.Line);
159                     sb.Append(')');
160                 }
161                 return sb.ToString();
162             #else
163                 return null;
164             #endif
165             }
166         }
167     }
168
169     internal abstract class ProtoTemplate : XslNode {
170         public QilFunction  Function;                   // Compiled body
171
172         public ProtoTemplate(XslNodeType nt, QilName name, XslVersion xslVer) : base(nt, name, null, xslVer) {}
173         public abstract string GetDebugName();
174     }
175
176     internal enum CycleCheck {
177         NotStarted  = 0,
178         Processing  = 1,
179         Completed   = 2,
180     }
181
182     internal class AttributeSet : ProtoTemplate {
183         public CycleCheck               CycleCheck;     // Used to detect circular references
184
185         public AttributeSet(QilName name, XslVersion xslVer) : base(XslNodeType.AttributeSet, name, xslVer) {}
186
187         public override string GetDebugName() {
188             StringBuilder dbgName = new StringBuilder();
189             dbgName.Append("<xsl:attribute-set name=\"");
190             dbgName.Append(Name.QualifiedName);
191             dbgName.Append("\">");
192             return dbgName.ToString();
193         }
194
195         public new void AddContent(XslNode node) {
196             Debug.Assert(node != null && node.NodeType == XslNodeType.List);
197             base.AddContent(node);
198         }
199
200         public void MergeContent(AttributeSet other) {
201             InsertContent(other.Content);
202         }
203     }
204
205     internal class Template : ProtoTemplate {
206         public readonly string  Match;
207         public readonly QilName Mode;
208         public readonly double  Priority;
209         public int              ImportPrecedence;
210         public int              OrderNumber;
211
212         public Template(QilName name, string match, QilName mode, double priority, XslVersion xslVer)
213             : base(XslNodeType.Template, name, xslVer)
214         {
215             this.Match      = match;
216             this.Mode       = mode;
217             this.Priority   = priority;
218         }
219
220         public override string GetDebugName() {
221             StringBuilder dbgName = new StringBuilder();
222             dbgName.Append("<xsl:template");
223             if (Match != null) {
224                 dbgName.Append(" match=\"");
225                 dbgName.Append(Match);
226                 dbgName.Append('"');
227             }
228             if (Name != null) {
229                 dbgName.Append(" name=\"");
230                 dbgName.Append(Name.QualifiedName);
231                 dbgName.Append('"');
232             }
233             if (!double.IsNaN(Priority)) {
234                 dbgName.Append(" priority=\"");
235                 dbgName.Append(Priority.ToString(CultureInfo.InvariantCulture));
236                 dbgName.Append('"');
237             }
238             if (Mode.LocalName.Length != 0) {
239                 dbgName.Append(" mode=\"");
240                 dbgName.Append(Mode.QualifiedName);
241                 dbgName.Append('"');
242             }
243             dbgName.Append('>');
244             return dbgName.ToString();
245         }
246     }
247
248     internal class VarPar : XslNode {
249         public XslFlags DefValueFlags;
250         public QilNode  Value;          // Contains value for WithParams and global VarPars
251
252         public VarPar(XslNodeType nt, QilName name, string select, XslVersion xslVer) : base(nt, name, select, xslVer) {}
253     }
254
255     internal class Sort : XslNode {
256         public readonly string  Lang;
257         public readonly string  DataType;
258         public readonly string  Order;
259         public readonly string  CaseOrder;
260
261         public Sort(string select, string lang, string dataType, string order, string caseOrder, XslVersion xslVer)
262             : base(XslNodeType.Sort, null, select, xslVer)
263         {
264             this.Lang       = lang;
265             this.DataType   = dataType;
266             this.Order      = order;
267             this.CaseOrder  = caseOrder;
268         }
269     }
270
271     internal class Keys : KeyedCollection<QilName, List<Key>> {
272         protected override QilName GetKeyForItem(List<Key> list) {
273             Debug.Assert(list != null && list.Count > 0);
274             return list[0].Name;
275         }
276     }
277
278     internal class Key : XslNode {
279         public readonly string  Match;
280         public readonly string  Use;
281         public QilFunction      Function;
282
283         public Key(QilName name, string match, string use, XslVersion xslVer)
284             : base(XslNodeType.Key, name, null, xslVer)
285         {
286             // match and use can be null in case of incorrect stylesheet
287             Debug.Assert(name != null);
288             this.Match  = match;
289             this.Use    = use;
290         }
291
292         public string GetDebugName() {
293             StringBuilder dbgName = new StringBuilder();
294             dbgName.Append("<xsl:key name=\"");
295             dbgName.Append(Name.QualifiedName);
296             dbgName.Append('"');
297
298             if (Match != null) {
299                 dbgName.Append(" match=\"");
300                 dbgName.Append(Match);
301                 dbgName.Append('"');
302             }
303             if (Use != null) {
304                 dbgName.Append(" use=\"");
305                 dbgName.Append(Use);
306                 dbgName.Append('"');
307             }
308             dbgName.Append('>');
309             return dbgName.ToString();
310         }
311     }
312
313     internal enum NumberLevel {
314         Single,
315         Multiple,
316         Any,
317     }
318
319     internal class Number : XslNode {
320         public readonly NumberLevel Level;
321         public readonly string      Count;
322         public readonly string      From;
323         public readonly string      Value;
324         public readonly string      Format;
325         public readonly string      Lang;
326         public readonly string      LetterValue;
327         public readonly string      GroupingSeparator;
328         public readonly string      GroupingSize;
329
330         public Number(NumberLevel level, string count, string from, string value,
331             string format, string lang, string letterValue, string groupingSeparator, string groupingSize,
332             XslVersion xslVer) : base(XslNodeType.Number, null, null, xslVer)
333         {
334             this.Level  = level;
335             this.Count  = count;
336             this.From   = from;
337             this.Value  = value;
338             this.Format = format;
339             this.Lang   = lang;
340             this.LetterValue       = letterValue;
341             this.GroupingSeparator = groupingSeparator;
342             this.GroupingSize      = groupingSize;
343         }
344     }
345
346     internal class NodeCtor : XslNode {
347         public readonly string  NameAvt;
348         public readonly string  NsAvt;
349
350         public NodeCtor(XslNodeType nt, string nameAvt, string nsAvt, XslVersion xslVer)
351             : base(nt, null, null, xslVer)
352         {
353             this.NameAvt = nameAvt;
354             this.NsAvt   = nsAvt;
355         }
356     }
357
358     internal class Text : XslNode {
359         public readonly SerializationHints  Hints;
360
361         public Text(string data, SerializationHints hints, XslVersion xslVer)
362             : base(XslNodeType.Text, null, data, xslVer)
363         {
364             this.Hints = hints;
365         }
366     }
367
368     internal class XslNodeEx : XslNode {
369         public readonly ISourceLineInfo ElemNameLi;
370         public readonly ISourceLineInfo EndTagLi;
371
372         public XslNodeEx(XslNodeType t, QilName name, object arg, ContextInfo ctxInfo, XslVersion xslVer)
373             : base(t, name, arg, xslVer)
374         {
375             ElemNameLi = ctxInfo.elemNameLi;
376             EndTagLi = ctxInfo.endTagLi;
377         }
378
379         public XslNodeEx(XslNodeType t, QilName name, object arg, XslVersion xslVer) : base(t, name, arg, xslVer) {
380         }
381     }
382
383     internal static class AstFactory {
384         public static XslNode XslNode(XslNodeType nodeType, QilName name, string arg, XslVersion xslVer) {
385             return new XslNode(nodeType, name, arg, xslVer);
386         }
387
388         public static XslNode ApplyImports(QilName mode, Stylesheet sheet, XslVersion xslVer) {
389             return new XslNode(XslNodeType.ApplyImports, mode, sheet, xslVer);
390         }
391
392         public static XslNodeEx ApplyTemplates(QilName mode, string select, ContextInfo ctxInfo, XslVersion xslVer) {
393             return new XslNodeEx(XslNodeType.ApplyTemplates, mode, select, ctxInfo, xslVer);
394         }
395
396         // Special node for start apply-templates
397         public static XslNodeEx ApplyTemplates(QilName mode) {
398             return new XslNodeEx(XslNodeType.ApplyTemplates, mode, /*select:*/null, XslVersion.Current);
399         }
400
401         public static NodeCtor Attribute(string nameAvt, string nsAvt, XslVersion xslVer) {
402             return new NodeCtor(XslNodeType.Attribute, nameAvt, nsAvt, xslVer);
403         }
404
405         public static AttributeSet AttributeSet(QilName name) {
406             return new AttributeSet(name, XslVersion.Current);
407         }
408
409         public static XslNodeEx CallTemplate(QilName name, ContextInfo ctxInfo) {
410             return new XslNodeEx(XslNodeType.CallTemplate, name, null, ctxInfo, XslVersion.Current);
411         }
412
413         public static XslNode Choose() {
414             return new XslNode(XslNodeType.Choose);
415         }
416
417         public static XslNode Comment() {
418             return new XslNode(XslNodeType.Comment);
419         }
420
421         public static XslNode Copy() {
422             return new XslNode(XslNodeType.Copy);
423         }
424
425         public static XslNode CopyOf(string select, XslVersion xslVer) {
426             return new XslNode(XslNodeType.CopyOf, null, select, xslVer);
427         }
428
429         public static NodeCtor Element(string nameAvt, string nsAvt, XslVersion xslVer) {
430             return new NodeCtor(XslNodeType.Element, nameAvt, nsAvt, xslVer);
431         }
432
433         public static XslNode Error(string message) {
434             return new XslNode(XslNodeType.Error, null, message, XslVersion.Current);
435         }
436
437         public static XslNodeEx ForEach(string select, ContextInfo ctxInfo, XslVersion xslVer) {
438             return new XslNodeEx(XslNodeType.ForEach, null, select, ctxInfo, xslVer);
439         }
440
441         public static XslNode If(string test, XslVersion xslVer) {
442             return new XslNode(XslNodeType.If, null, test, xslVer);
443         }
444
445         public static Key Key(QilName name, string match, string use, XslVersion xslVer) {
446             return new Key(name, match, use, xslVer);
447         }
448
449         public static XslNode List() {
450             return new XslNode(XslNodeType.List);
451         }
452
453         public static XslNode LiteralAttribute(QilName name, string value, XslVersion xslVer) {
454             return new XslNode(XslNodeType.LiteralAttribute, name, value, xslVer);
455         }
456
457         public static XslNode LiteralElement(QilName name) {
458             return new XslNode(XslNodeType.LiteralElement, name, null, XslVersion.Current);
459         }
460
461         public static XslNode Message(bool term) {
462             return new XslNode(XslNodeType.Message, null, term, XslVersion.Current);
463         }
464
465         public static XslNode Nop() {
466             return new XslNode(XslNodeType.Nop);
467         }
468
469         public static Number Number(NumberLevel level, string count, string from, string value,
470             string format, string lang, string letterValue, string groupingSeparator, string groupingSize,
471             XslVersion xslVer)
472         {
473             return new Number(level, count, from, value, format, lang, letterValue, groupingSeparator, groupingSize, xslVer);
474         }
475
476         public static XslNode Otherwise() {
477             return new XslNode(XslNodeType.Otherwise);
478         }
479
480         public static XslNode PI(string name, XslVersion xslVer) {
481             return new XslNode(XslNodeType.PI, null, name, xslVer);
482         }
483
484         public static Sort Sort(string select, string lang, string dataType, string order, string caseOrder, XslVersion xslVer) {
485             return new Sort(select, lang, dataType, order, caseOrder, xslVer);
486         }
487
488         public static Template Template(QilName name, string match, QilName mode, double priority, XslVersion xslVer) {
489             return new Template(name, match, mode, priority, xslVer);
490         }
491
492         public static XslNode Text(string data) {
493             return new Text(data, SerializationHints.None, XslVersion.Current);
494         }
495
496         public static XslNode Text(string data, SerializationHints hints) {
497             return new Text(data, hints, XslVersion.Current);
498         }
499
500         public static XslNode UseAttributeSet(QilName name) {
501             return new XslNode(XslNodeType.UseAttributeSet, name, null, XslVersion.Current);
502         }
503
504         public static VarPar VarPar(XslNodeType nt, QilName name, string select, XslVersion xslVer) {
505             return new VarPar(nt, name, select, xslVer);
506         }
507
508         public static VarPar WithParam(QilName name) {
509             return VarPar(XslNodeType.WithParam, name, /*select*/null, XslVersion.Current);
510         }
511
512         private static QilFactory f = new QilFactory();
513
514         public static QilName QName(string local, string uri, string prefix) {
515             return f.LiteralQName(local, uri, prefix);
516         }
517
518         public static QilName QName(string local) {
519             return f.LiteralQName(local);
520         }
521     }
522 }