cb02a285e405e9365829172453eb2672c9aaf9e4
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / XsltOld / Compiler.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Compiler.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml.Xsl.XsltOld {
9     using Res = System.Xml.Utils.Res;
10     using System;
11     using System.Diagnostics;
12     using System.Globalization;
13     using System.Xml;
14     using System.Xml.XPath;
15     using System.Xml.Xsl.Runtime;
16     using MS.Internal.Xml.XPath;
17     using System.Xml.Xsl.XsltOld.Debugger;
18     using System.Text;
19     using System.Collections;
20     using System.Collections.Generic;
21     using System.Collections.Specialized;
22     using System.IO;
23     using System.CodeDom;
24     using System.CodeDom.Compiler;
25     using System.Reflection;
26     using System.Security;
27     using System.Security.Policy;
28     using System.Security.Permissions;
29     using Keywords = System.Xml.Xsl.Xslt.KeywordsTable;
30     using System.Runtime.Versioning;
31
32     internal class Sort {
33         internal int          select;
34         internal string       lang;
35         internal XmlDataType  dataType;
36         internal XmlSortOrder order;
37         internal XmlCaseOrder caseOrder;
38
39         public Sort(int sortkey, String xmllang, XmlDataType datatype, XmlSortOrder xmlorder, XmlCaseOrder xmlcaseorder) {
40             select    = sortkey;
41             lang      = xmllang;
42             dataType  = datatype;
43             order     = xmlorder;
44             caseOrder = xmlcaseorder;
45         }
46     }
47
48     internal enum ScriptingLanguage {
49         JScript,
50 #if !FEATURE_PAL // visualbasic
51         VisualBasic,
52 #endif // !FEATURE_PAL
53         CSharp
54     }
55
56     internal class Compiler {
57         internal const int    InvalidQueryKey   = -1;
58
59         internal const double RootPriority   = 0.5;
60
61         // cached StringBuilder for AVT parseing
62         internal StringBuilder AvtStringBuilder = new StringBuilder();
63
64         private int                 stylesheetid; // Root stylesheet has id=0. We are using this in CompileImports to compile BuiltIns
65         private InputScope          rootScope;
66
67         //
68         // Object members
69         private XmlResolver         xmlResolver;
70
71         //
72         // Template being currently compiled
73         private TemplateBaseAction  currentTemplate;
74         private XmlQualifiedName    currentMode;
75         private Hashtable           globalNamespaceAliasTable;
76
77         //
78         // Current import stack
79         private Stack               stylesheets;
80
81         private HybridDictionary    documentURIs = new HybridDictionary();
82
83         // import/include documents, who is here has its URI in this.documentURIs
84         private NavigatorInput      input;
85
86         // Atom table & InputScopeManager - cached top of the this.input stack
87         private Keywords            atoms;
88         private InputScopeManager   scopeManager;
89
90         //
91         // Compiled stylesheet state
92         internal Stylesheet         stylesheet;
93         internal Stylesheet         rootStylesheet;
94         private RootAction          rootAction;
95         private List<TheQuery>      queryStore;
96         private QueryBuilder        queryBuilder = new QueryBuilder();
97         private int                 rtfCount = 0;
98
99         // Used to load Built In templates
100         public  bool                AllowBuiltInMode;
101         public  static XmlQualifiedName BuiltInMode = new XmlQualifiedName("*", string.Empty);
102
103         internal Keywords Atoms {
104             get {
105                 Debug.Assert(this.atoms != null);
106                 return this.atoms;
107             }
108         }
109
110         internal int Stylesheetid {
111             get{ return this.stylesheetid; }
112             set { this.stylesheetid = value; }
113         }
114
115         internal NavigatorInput Document {
116             get { return this.input; }
117         }
118
119         internal NavigatorInput Input {
120             get { return this.input; }
121         }
122
123         internal bool Advance() {
124             Debug.Assert(Document != null);
125             return Document.Advance();
126         }
127
128         internal bool Recurse() {
129             Debug.Assert(Document != null);
130             return Document.Recurse();
131         }
132
133         internal bool ToParent() {
134             Debug.Assert(Document != null);
135             return Document.ToParent();
136         }
137
138         internal Stylesheet CompiledStylesheet {
139             get { return this.stylesheet; }
140         }
141
142         internal RootAction RootAction {
143             get { return this.rootAction; }
144             set {
145                 Debug.Assert(this.rootAction == null);
146                 this.rootAction = value;
147                 Debug.Assert(this.currentTemplate == null);
148                 this.currentTemplate = this.rootAction;
149             }
150         }
151
152         internal List<TheQuery> QueryStore {
153             get { return this.queryStore; }
154         }
155
156         public virtual IXsltDebugger Debugger { get { return null; } }
157
158         internal string GetUnicRtfId() {
159             this.rtfCount++;
160             return this.rtfCount.ToString(CultureInfo.InvariantCulture);
161         }
162
163         //
164         // The World of Compile
165         //
166         internal void Compile(NavigatorInput input, XmlResolver xmlResolver, Evidence evidence) {
167 #if DISABLE_CAS_USE
168             evidence = null;
169 #endif
170             Debug.Assert(input != null);
171             Debug.Assert(xmlResolver != null);
172 //            Debug.Assert(evidence    != null); -- default evidence is null now
173             Debug.Assert(this.input == null && this.atoms == null);
174             this.xmlResolver = xmlResolver;
175
176             PushInputDocument(input);
177             this.rootScope  = this.scopeManager.PushScope();
178             this.queryStore = new List<TheQuery>();
179
180             try {
181                 this.rootStylesheet = new Stylesheet();
182                 PushStylesheet(this.rootStylesheet);
183
184                 Debug.Assert(this.input != null && this.atoms != null);
185
186                 try {
187                     this.CreateRootAction();
188                 }
189                 catch (XsltCompileException) {
190                     throw;
191                 }
192                 catch (Exception e) {
193                     throw new XsltCompileException(e, this.Input.BaseURI, this.Input.LineNumber, this.Input.LinePosition);
194                 }
195
196                 this.stylesheet.ProcessTemplates();
197                 this.rootAction.PorcessAttributeSets(this.rootStylesheet);
198                 this.stylesheet.SortWhiteSpace();
199 #if !DISABLE_XSLT_SCRIPT
200                 CompileScript(evidence);
201 #endif
202                 if (evidence != null) {
203                     this.rootAction.permissions = SecurityManager.GetStandardSandbox(evidence);
204                 }
205
206                 if (this.globalNamespaceAliasTable != null) {
207                     this.stylesheet.ReplaceNamespaceAlias(this);
208                     this.rootAction.ReplaceNamespaceAlias(this);
209                 }
210             }
211             finally {
212                 PopInputDocument();
213             }
214
215             Debug.Assert(this.rootAction != null);
216             Debug.Assert(this.stylesheet != null);
217             Debug.Assert(this.queryStore != null);
218             Debug.Assert(this.input == null && this.atoms == null);
219         }
220
221         //
222         // Input scope compiler's support
223         //
224
225         internal bool ForwardCompatibility {
226             get { return this.scopeManager.CurrentScope.ForwardCompatibility;  }
227             set { this.scopeManager.CurrentScope.ForwardCompatibility = value; }
228         }
229
230         internal bool CanHaveApplyImports {
231             get { return this.scopeManager.CurrentScope.CanHaveApplyImports;  }
232             set { this.scopeManager.CurrentScope.CanHaveApplyImports = value; }
233         }
234
235         internal void InsertExtensionNamespace(string value) {
236             string[] nsList = ResolvePrefixes(value);
237             if (nsList != null) {
238                 scopeManager.InsertExtensionNamespaces(nsList);
239             }
240         }
241
242         internal void InsertExcludedNamespace(string value) {
243             string[] nsList = ResolvePrefixes(value);
244             if (nsList != null) {
245                 scopeManager.InsertExcludedNamespaces(nsList);
246             }
247         }
248
249         internal void InsertExtensionNamespace() {
250             InsertExtensionNamespace(Input.Navigator.GetAttribute(Input.Atoms.ExtensionElementPrefixes, Input.Atoms.UriXsl));
251         }
252
253         internal void InsertExcludedNamespace() {
254             InsertExcludedNamespace(Input.Navigator.GetAttribute(Input.Atoms.ExcludeResultPrefixes, Input.Atoms.UriXsl));
255         }
256
257         internal bool IsExtensionNamespace(String nspace) {
258             return this.scopeManager.IsExtensionNamespace(nspace);
259         }
260
261         internal bool IsExcludedNamespace(String nspace) {
262             return this.scopeManager.IsExcludedNamespace(nspace);
263         }
264
265         internal void PushLiteralScope() {
266             PushNamespaceScope();
267             string value = Input.Navigator.GetAttribute(Atoms.Version, Atoms.UriXsl);
268             if (value.Length != 0) {
269                 ForwardCompatibility = (value != "1.0");
270             }
271         }
272
273         internal void PushNamespaceScope() {
274             this.scopeManager.PushScope();
275             NavigatorInput input  = Input;
276
277             if (input.MoveToFirstNamespace()) {
278                 do {
279                     this.scopeManager.PushNamespace(input.LocalName, input.Value);
280                 }
281                 while(input.MoveToNextNamespace());
282                 input.ToParent();
283             }
284         }
285
286         protected InputScopeManager  ScopeManager {
287             get { return this.scopeManager; }
288         }
289
290         internal virtual void PopScope() {
291             this.currentTemplate.ReleaseVariableSlots(this.scopeManager.CurrentScope.GetVeriablesCount());
292             this.scopeManager.PopScope();
293         }
294
295         internal InputScopeManager CloneScopeManager() {
296             return this.scopeManager.Clone();
297         }
298
299         //
300         // Variable support
301         //
302
303         internal int InsertVariable(VariableAction variable) {
304             InputScope varScope;
305             if (variable.IsGlobal) {
306                 Debug.Assert(this.rootAction != null);
307                 varScope = this.rootScope;
308             }
309             else {
310                 Debug.Assert(this.currentTemplate != null);
311                 Debug.Assert(variable.VarType == VariableType.LocalVariable || variable.VarType == VariableType.LocalParameter || variable.VarType == VariableType.WithParameter);
312                 varScope = this.scopeManager.VariableScope;
313             }
314
315             VariableAction oldVar = varScope.ResolveVariable(variable.Name);
316             if (oldVar != null) {
317                 // Other variable with this name is visible in this scope
318                 if (oldVar.IsGlobal) {
319                     if (variable.IsGlobal) {
320                         // Global Vars replace each other base on import presidens odred
321                         if (variable.Stylesheetid == oldVar.Stylesheetid) {
322                             // Both vars are in the same stylesheet
323                             throw XsltException.Create(Res.Xslt_DupVarName, variable.NameStr);
324                         }
325                         else if (variable.Stylesheetid < oldVar.Stylesheetid) {
326                             // newly defined var is more importent
327                             varScope.InsertVariable(variable);
328                             return oldVar.VarKey;
329                         }
330                         else {
331                             // we egnore new variable
332                             return InvalidQueryKey; // We didn't add this var, so doesn't matter what VarKey we return;
333                         }
334                     }
335                     else {
336                         // local variable can shadow global
337                     }
338                 }
339                 else {
340                     // Local variable never can be "shadowed"
341                     throw XsltException.Create(Res.Xslt_DupVarName, variable.NameStr);
342                 }
343             }
344
345             varScope.InsertVariable(variable);
346             return this.currentTemplate.AllocateVariableSlot();
347         }
348
349         internal void AddNamespaceAlias(String StylesheetURI, NamespaceInfo AliasInfo){
350             if (this.globalNamespaceAliasTable == null) {
351                 this.globalNamespaceAliasTable = new Hashtable();
352             }
353             NamespaceInfo duplicate = this.globalNamespaceAliasTable[StylesheetURI] as NamespaceInfo;
354             if (duplicate == null || AliasInfo.stylesheetId <= duplicate.stylesheetId) {
355                 this.globalNamespaceAliasTable[StylesheetURI] = AliasInfo;
356             }
357         }
358
359         internal bool IsNamespaceAlias(String StylesheetURI){
360             if (this.globalNamespaceAliasTable == null) {
361                 return false;
362             }
363             return this.globalNamespaceAliasTable.Contains(StylesheetURI);
364         }
365
366         internal NamespaceInfo FindNamespaceAlias(String StylesheetURI) {
367             if (this.globalNamespaceAliasTable != null) {
368                return (NamespaceInfo)this.globalNamespaceAliasTable[StylesheetURI];
369             }
370             return null;
371         }
372
373         internal String ResolveXmlNamespace(String prefix) {
374             return this.scopeManager.ResolveXmlNamespace(prefix);
375         }
376
377         internal String ResolveXPathNamespace(String prefix) {
378             return this.scopeManager.ResolveXPathNamespace(prefix);
379         }
380
381         internal String DefaultNamespace {
382             get{ return this.scopeManager.DefaultNamespace; }
383         }
384
385         internal void InsertKey(XmlQualifiedName name, int MatchKey, int UseKey) {
386             this.rootAction.InsertKey(name, MatchKey, UseKey);
387         }
388
389         internal void AddDecimalFormat(XmlQualifiedName name, DecimalFormat formatinfo) {
390             this.rootAction.AddDecimalFormat(name, formatinfo);
391         }
392
393         //
394         // Attribute parsing support
395         //
396
397         // This function is for processing optional attributes only.  In case of error
398         // the value is ignored iff forwards-compatible mode is on.
399         private string[] ResolvePrefixes(string tokens) {
400             if (tokens == null || tokens.Length == 0) {
401                 return null;
402             }
403             string[] nsList = XmlConvert.SplitString(tokens);
404
405             try {
406                 for (int idx = 0; idx < nsList.Length; idx++) {
407                     string prefix = nsList[idx];
408                     nsList[idx] = scopeManager.ResolveXmlNamespace(prefix == "#default" ? string.Empty : prefix);
409                 }
410             }
411             catch (XsltException) {
412                 // The only exception here might be Res.Xslt_InvalidPrefix
413                 if (!ForwardCompatibility) {
414                     // Rethrow the exception if we're not in forwards-compatible mode
415                     throw;
416                 }
417                 // Ignore the whole list in forwards-compatible mode
418                 return null;
419             }
420             return nsList;
421         }
422
423         internal bool GetYesNo(string value) {
424             Debug.Assert(value != null);
425             Debug.Assert((object)value == (object)Input.Value); // this is always true. Why we passing value to this function.
426             if (value == "yes") {
427                 return true;
428             }
429             if (value == "no") {
430                 return false;
431             }
432             throw XsltException.Create(Res.Xslt_InvalidAttrValue, Input.LocalName, value);
433         }
434
435         internal string GetSingleAttribute(string attributeAtom) {
436             NavigatorInput input   = Input;
437             string         element = input.LocalName;
438             string         value   = null;
439
440             if (input.MoveToFirstAttribute()) {
441                 do {
442                     string nspace = input.NamespaceURI;
443                     string name   = input.LocalName;
444
445                     if (nspace.Length != 0) continue;
446
447                     if (Ref.Equal(name, attributeAtom)) {
448                         value = input.Value;
449                     }
450                     else {
451                         if (! this.ForwardCompatibility) {
452                             throw XsltException.Create(Res.Xslt_InvalidAttribute, name, element);
453                         }
454                     }
455                 }
456                 while (input.MoveToNextAttribute());
457                 input.ToParent();
458             }
459
460             if (value == null) {
461                 throw XsltException.Create(Res.Xslt_MissingAttribute, attributeAtom);
462             }
463             return value;
464         }
465
466         internal XmlQualifiedName CreateXPathQName(string qname) {
467             string prefix, local;
468             PrefixQName.ParseQualifiedName(qname, out prefix, out local);
469
470             return new XmlQualifiedName(local, this.scopeManager.ResolveXPathNamespace(prefix));
471         }
472
473         internal XmlQualifiedName CreateXmlQName(string qname) {
474             string prefix, local;
475             PrefixQName.ParseQualifiedName(qname, out prefix, out local);
476
477             return new XmlQualifiedName(local, this.scopeManager.ResolveXmlNamespace(prefix));
478         }
479
480         //
481         // Input documents management
482         //
483
484         internal static XPathDocument LoadDocument(XmlTextReaderImpl reader) {
485             reader.EntityHandling = EntityHandling.ExpandEntities;
486             reader.XmlValidatingReaderCompatibilityMode = true;
487             try {
488                 return new XPathDocument(reader, XmlSpace.Preserve);
489             }
490             finally {
491                 reader.Close();
492             }
493         }
494
495         private void AddDocumentURI(string href) {
496             Debug.Assert(!this.documentURIs.Contains(href), "Circular references must be checked while processing xsl:include and xsl:import");
497             this.documentURIs.Add(href, null);
498         }
499
500         private void RemoveDocumentURI(string href) {
501             Debug.Assert(this.documentURIs.Contains(href), "Attempt to remove href that was not added");
502             this.documentURIs.Remove(href);
503         }
504
505         internal bool IsCircularReference(string href) {
506             return this.documentURIs.Contains(href);
507         }
508
509         [ResourceConsumption(ResourceScope.Machine)]
510         [ResourceExposure(ResourceScope.Machine)]
511         internal Uri ResolveUri(string relativeUri) {
512             Debug.Assert(this.xmlResolver != null);
513             string baseUri = this.Input.BaseURI;
514             Uri uri = this.xmlResolver.ResolveUri((baseUri.Length != 0) ? this.xmlResolver.ResolveUri(null, baseUri) : null, relativeUri);
515             if (uri == null) {
516                 throw XsltException.Create(Res.Xslt_CantResolve, relativeUri);
517             }
518             return uri;
519         }
520
521         internal NavigatorInput ResolveDocument(Uri absoluteUri) {
522             Debug.Assert(this.xmlResolver != null);
523             object input = this.xmlResolver.GetEntity(absoluteUri, null, null);
524             string resolved = absoluteUri.ToString();
525
526             if (input is Stream) {
527                 XmlTextReaderImpl tr  = new XmlTextReaderImpl(resolved, (Stream) input); {
528                     tr.XmlResolver = this.xmlResolver;
529                 }
530                 // reader is closed by Compiler.LoadDocument()
531                 return new NavigatorInput(Compiler.LoadDocument(tr).CreateNavigator(), resolved, rootScope);
532             }
533             else if (input is XPathNavigator) {
534                 return new NavigatorInput((XPathNavigator) input, resolved, rootScope);
535             }
536             else {
537                 throw XsltException.Create(Res.Xslt_CantResolve, resolved);
538             }
539         }
540
541         internal void PushInputDocument(NavigatorInput newInput) {
542             Debug.Assert(newInput != null);
543             string inputUri = newInput.Href;
544
545             AddDocumentURI(inputUri);
546
547             newInput.Next     = this.input;
548             this.input        = newInput;
549             this.atoms        = this.input.Atoms;
550             this.scopeManager = this.input.InputScopeManager;
551         }
552
553         internal void PopInputDocument() {
554             Debug.Assert(this.input != null);
555             Debug.Assert(this.input.Atoms == this.atoms);
556
557             NavigatorInput lastInput = this.input;
558
559             this.input     = lastInput.Next;
560             lastInput.Next = null;
561
562             if (this.input != null) {
563                 this.atoms        = this.input.Atoms;
564                 this.scopeManager = this.input.InputScopeManager;
565             }
566             else {
567                 this.atoms        = null;
568                 this.scopeManager = null;
569             }
570
571             RemoveDocumentURI(lastInput.Href);
572             lastInput.Close();
573         }
574
575         //
576         // Stylesheet management
577         //
578
579         internal void PushStylesheet(Stylesheet stylesheet) {
580             if (this.stylesheets == null) {
581                 this.stylesheets = new Stack();
582             }
583             Debug.Assert(this.stylesheets != null);
584
585             this.stylesheets.Push(stylesheet);
586             this.stylesheet = stylesheet;
587         }
588
589         internal Stylesheet PopStylesheet() {
590             Debug.Assert(this.stylesheet == this.stylesheets.Peek());
591             Stylesheet stylesheet = (Stylesheet) this.stylesheets.Pop();
592             this.stylesheet = (Stylesheet) this.stylesheets.Peek();
593             return stylesheet;
594         }
595
596         //
597         // Attribute-Set management
598         //
599
600         internal void AddAttributeSet(AttributeSetAction attributeSet) {
601             Debug.Assert(this.stylesheet == this.stylesheets.Peek());
602             this.stylesheet.AddAttributeSet(attributeSet);
603         }
604
605         //
606         // Template management
607         //
608
609         internal void AddTemplate(TemplateAction template) {
610             Debug.Assert(this.stylesheet == this.stylesheets.Peek());
611             this.stylesheet.AddTemplate(template);
612         }
613
614         internal void BeginTemplate(TemplateAction template) {
615             Debug.Assert(this.currentTemplate != null);
616             this.currentTemplate = template;
617             this.currentMode     = template.Mode;
618             this.CanHaveApplyImports = template.MatchKey != Compiler.InvalidQueryKey;
619         }
620
621         internal void EndTemplate() {
622             Debug.Assert(this.currentTemplate != null);
623             this.currentTemplate = this.rootAction;
624         }
625
626         internal XmlQualifiedName CurrentMode {
627             get { return this.currentMode; }
628         }
629
630         //
631         // Query management
632         //
633         internal int AddQuery(string xpathQuery) {
634             return AddQuery(xpathQuery, /*allowVars:*/true, /*allowKey*/true, false);
635         }
636
637         internal int AddQuery(string xpathQuery, bool allowVar, bool allowKey, bool isPattern) {
638             Debug.Assert(this.queryStore != null);
639
640             CompiledXpathExpr expr;
641             try {
642                 expr = new CompiledXpathExpr(
643                     (isPattern
644                         ? this.queryBuilder.BuildPatternQuery(xpathQuery, allowVar, allowKey)
645                         : this.queryBuilder.Build(            xpathQuery, allowVar, allowKey)
646                     ),
647                     xpathQuery,
648                     false
649                 );
650             } catch (XPathException e) {
651                 if (! ForwardCompatibility) {
652                     throw XsltException.Create(Res.Xslt_InvalidXPath,  new string[] { xpathQuery }, e);
653                 }
654                 expr = new ErrorXPathExpression(xpathQuery, this.Input.BaseURI, this.Input.LineNumber, this.Input.LinePosition);
655             }
656             this.queryStore.Add(new TheQuery(expr, this.scopeManager));
657             return this.queryStore.Count - 1;
658         }
659
660         internal int AddStringQuery(string xpathQuery) {
661             string modifiedQuery = XmlCharType.Instance.IsOnlyWhitespace(xpathQuery) ? xpathQuery : "string(" + xpathQuery + ")";
662             return AddQuery(modifiedQuery);
663         }
664
665         internal int AddBooleanQuery(string xpathQuery) {
666             string modifiedQuery = XmlCharType.Instance.IsOnlyWhitespace(xpathQuery) ? xpathQuery : "boolean(" + xpathQuery + ")";
667             return AddQuery(modifiedQuery);
668         }
669
670         //
671         // Script support
672         //
673         Hashtable[] _typeDeclsByLang = new Hashtable[] { new Hashtable(), new Hashtable(), new Hashtable() };
674         ArrayList   scriptFiles = new ArrayList();
675         // Namespaces we always import when compiling
676         private static string[] _defaultNamespaces = new string[] {
677             "System",
678             "System.Collections",
679             "System.Text",
680             "System.Text.RegularExpressions",
681             "System.Xml",
682             "System.Xml.Xsl",
683             "System.Xml.XPath",
684         };
685
686         private static int scriptClassCounter = 0;
687         private static string GenerateUniqueClassName() {
688             return "ScriptClass_" + System.Threading.Interlocked.Increment(ref scriptClassCounter);
689         }
690
691 #if !DISABLE_XSLT_SCRIPT
692         internal void AddScript(string source, ScriptingLanguage lang, string ns, string fileName, int lineNumber) {
693             ValidateExtensionNamespace(ns);
694
695             for (ScriptingLanguage langTmp = ScriptingLanguage.JScript; langTmp <= ScriptingLanguage.CSharp; langTmp ++) {
696                 Hashtable typeDecls = _typeDeclsByLang[(int)langTmp];
697                 if (lang == langTmp) {
698                     CodeTypeDeclaration scriptClass = (CodeTypeDeclaration)typeDecls[ns];
699                     if (scriptClass == null) {
700                         scriptClass = new CodeTypeDeclaration(GenerateUniqueClassName());
701                         scriptClass.TypeAttributes = TypeAttributes.Public;
702                         typeDecls.Add(ns, scriptClass);
703                     }
704                     CodeSnippetTypeMember scriptSnippet = new CodeSnippetTypeMember(source);
705                     if (lineNumber > 0) {
706                         scriptSnippet.LinePragma = new CodeLinePragma(fileName, lineNumber);
707                         scriptFiles.Add(fileName);
708                     }
709                     scriptClass.Members.Add(scriptSnippet);
710                 }
711                 else if (typeDecls.Contains(ns)) {
712                     throw XsltException.Create(Res.Xslt_ScriptMixedLanguages, ns);
713                 }
714             }
715         }
716 #endif
717
718         private static void ValidateExtensionNamespace(string nsUri) {
719             if (nsUri.Length == 0 || nsUri == XmlReservedNs.NsXslt) {
720                 throw XsltException.Create(Res.Xslt_InvalidExtensionNamespace);
721             }
722             XmlConvert.ToUri(nsUri);
723         }
724
725 #if !DISABLE_XSLT_SCRIPT
726         private void FixCompilerError(CompilerError e) {
727             foreach(string scriptFile in this.scriptFiles) {
728                 if (e.FileName == scriptFile) {
729                     return; // Yes! this error is in our code sippet.
730                 }
731             }
732             e.FileName = string.Empty;
733         }
734
735         CodeDomProvider ChooseCodeDomProvider(ScriptingLanguage lang) {
736             return (
737                 lang == ScriptingLanguage.JScript     ? (CodeDomProvider) Activator.CreateInstance(Type.GetType("Microsoft.JScript.JScriptCodeProvider, " + AssemblyRef.MicrosoftJScript), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null) :
738 #if !FEATURE_PAL // visualbasic
739                 lang == ScriptingLanguage.VisualBasic ? (CodeDomProvider) new Microsoft.VisualBasic.VBCodeProvider() :
740 #endif
741                 /*CSharp | default */                   (CodeDomProvider) new Microsoft.CSharp.CSharpCodeProvider()
742             );
743         }
744
745         private void CompileScript(Evidence evidence) {
746             for (ScriptingLanguage lang = ScriptingLanguage.JScript; lang <= ScriptingLanguage.CSharp; lang ++) {
747                 int idx = (int)lang;
748                 if (_typeDeclsByLang[idx].Count > 0) {
749                     CompileAssembly(lang, _typeDeclsByLang[idx], lang.ToString(), evidence);
750                 }
751             }
752         }
753
754         [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
755         // SxS: This method does not take any resource name and does not expose any resources to the caller.
756         // It's OK to suppress the SxS warning.
757         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
758         [ResourceExposure(ResourceScope.None)]
759         private void CompileAssembly(ScriptingLanguage lang, Hashtable typeDecls, string nsName, Evidence evidence) {
760             nsName = "Microsoft.Xslt.CompiledScripts." + nsName;
761             CodeNamespace msXslt = new CodeNamespace(nsName);
762
763             // Add all the default namespaces
764             foreach(string ns in _defaultNamespaces) {
765                 msXslt.Imports.Add(new CodeNamespaceImport(ns));
766             }
767
768 #if !FEATURE_PAL // visualbasic
769             if (lang == ScriptingLanguage.VisualBasic) {
770                 msXslt.Imports.Add(new CodeNamespaceImport("Microsoft.VisualBasic"));
771             }
772 #endif //!FEATURE_PAL
773
774             foreach(CodeTypeDeclaration scriptClass in typeDecls.Values) {
775                 msXslt.Types.Add(scriptClass);
776             }
777
778             CodeCompileUnit unit = new CodeCompileUnit(); {
779                 unit.Namespaces.Add(msXslt);
780                 // This settings have sense for Visual Basic only.
781                 // We can consider in future to allow user set them in <xsl:script option="???"> attribute.
782                 unit.UserData["AllowLateBound"]             = true;  // Allow variables to be undeclared
783                 unit.UserData["RequireVariableDeclaration"] = false; // Allow variables to be declared untyped
784             }
785
786             // We want the assemblies generated for scripts to stick to the old security model
787             unit.AssemblyCustomAttributes.Add(
788                 new CodeAttributeDeclaration(
789                     new CodeTypeReference(typeof(System.Security.SecurityRulesAttribute)),
790                     new CodeAttributeArgument(
791                         new CodeFieldReferenceExpression(
792                             new CodeTypeReferenceExpression(typeof(System.Security.SecurityRuleSet)), "Level1"))));
793
794             CompilerParameters compilParams = new CompilerParameters(); {
795                 try {
796                     new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Assert();
797                     try {
798                         compilParams.GenerateInMemory = true;
799 #pragma warning disable 618
800                         compilParams.Evidence = evidence;
801 #pragma warning restore 618
802                         compilParams.ReferencedAssemblies.Add(typeof(XPathNavigator).Module.FullyQualifiedName);
803                         compilParams.ReferencedAssemblies.Add("system.dll");
804 #if !FEATURE_PAL // visualbasic
805                         if (lang == ScriptingLanguage.VisualBasic) {
806                             compilParams.ReferencedAssemblies.Add("microsoft.visualbasic.dll");
807                         }
808 #endif // !FEATURE_PAL
809                     }
810                     finally {
811                         CodeAccessPermission.RevertAssert();
812                     }
813                 } catch { throw; }
814             }
815
816             CompilerResults results = ChooseCodeDomProvider(lang).CompileAssemblyFromDom(compilParams, unit);
817             if (results.Errors.HasErrors) {
818                 StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
819                 foreach (CompilerError e in results.Errors) {
820                     FixCompilerError(e);
821                     stringWriter.WriteLine(e.ToString());
822                 }
823                 throw XsltException.Create(Res.Xslt_ScriptCompileErrors, stringWriter.ToString());
824             }
825             Assembly assembly = results.CompiledAssembly;
826             foreach(DictionaryEntry entry in typeDecls) {
827                 string ns = (string)entry.Key;
828                 CodeTypeDeclaration scriptClass = (CodeTypeDeclaration)entry.Value;
829                 this.stylesheet.ScriptObjectTypes.Add(ns, assembly.GetType(nsName + "." + scriptClass.Name));
830             }
831         }
832 #endif
833
834         public string GetNsAlias(ref string prefix) {
835             Debug.Assert(
836                 Ref.Equal(this.input.LocalName, this.input.Atoms.StylesheetPrefix) ||
837                 Ref.Equal(this.input.LocalName, this.input.Atoms.ResultPrefix)
838             );
839             if (prefix == "#default") {
840                 prefix = string.Empty;
841                 return this.DefaultNamespace;
842             }
843             else {
844                 if (! PrefixQName.ValidatePrefix(prefix)) {
845                     throw XsltException.Create(Res.Xslt_InvalidAttrValue, this.input.LocalName, prefix);
846                 }
847                 return this.ResolveXPathNamespace(prefix);
848             }
849         }
850
851         // AVT's compilation.
852         // CompileAvt() returns ArrayList of TextEvent & AvtEvent
853
854         private static void getTextLex(string avt, ref int start, StringBuilder lex) {
855             Debug.Assert(avt.Length != start, "Empty string not supposed here");
856             Debug.Assert(lex.Length == 0    , "Builder shoud to be reset here");
857             int avtLength = avt.Length;
858             int i;
859             for (i = start; i < avtLength; i ++) {
860                 char ch = avt[i];
861                 if (ch == '{') {
862                     if (i + 1 < avtLength && avt[i + 1] == '{') { // "{{"
863                         i ++;
864                     }
865                     else {
866                         break;
867                     }
868                 }
869                 else if (ch == '}') {
870                     if (i + 1 < avtLength && avt[i + 1] == '}') { // "}}"
871                         i ++;
872                     }
873                     else {
874                         throw XsltException.Create(Res.Xslt_SingleRightAvt, avt);
875                     }
876                 }
877                 lex.Append(ch);
878             }
879             start = i;
880         }
881
882         private static void getXPathLex(string avt, ref int start, StringBuilder lex) {
883             // AVT parser states
884             const int InExp       = 0;      // Inside AVT expression
885             const int InLiteralA  = 1;      // Inside literal in expression, apostrophe delimited
886             const int InLiteralQ  = 2;      // Inside literal in expression, quote delimited
887             Debug.Assert(avt.Length != start, "Empty string not supposed here");
888             Debug.Assert(lex.Length == 0    , "Builder shoud to be reset here");
889             Debug.Assert(avt[start] == '{'  , "We calling getXPathLex() only after we realy meet {");
890             int avtLength = avt.Length;
891             int state  = InExp;
892             for (int i = start + 1; i < avtLength; i ++) {
893                 char ch = avt[i];
894                 switch(state) {
895                 case InExp :
896                     switch (ch) {
897                     case '{' :
898                         throw XsltException.Create(Res.Xslt_NestedAvt, avt);
899                     case '}' :
900                         i ++; // include '}'
901                         if (i == start + 2) { // empty XPathExpresion
902                             throw XsltException.Create(Res.Xslt_EmptyAvtExpr, avt);
903                         }
904                         lex.Append(avt, start + 1, i - start - 2); // avt without {}
905                         start = i;
906                         return;
907                     case '\'' :
908                         state = InLiteralA;
909                         break;
910                     case '"' :
911                         state = InLiteralQ;
912                         break;
913                     }
914                     break;
915                 case InLiteralA :
916                     if (ch == '\'') {
917                         state = InExp;
918                     }
919                     break;
920                 case InLiteralQ :
921                     if (ch == '"') {
922                         state = InExp;
923                     }
924                     break;
925                 }
926             }
927
928             // if we meet end of string before } we have an error
929             throw XsltException.Create(state == InExp ? Res.Xslt_OpenBracesAvt : Res.Xslt_OpenLiteralAvt, avt);
930         }
931
932         private static bool GetNextAvtLex(string avt, ref int start, StringBuilder lex, out bool isAvt) {
933             Debug.Assert(start <= avt.Length);
934 #if DEBUG
935             int saveStart = start;
936 #endif
937             isAvt = false;
938             if (start == avt.Length) {
939                 return false;
940             }
941             lex.Length = 0;
942             getTextLex(avt, ref start, lex);
943             if (lex.Length == 0) {
944                 isAvt = true;
945                 getXPathLex(avt, ref start, lex);
946             }
947 #if DEBUG
948             Debug.Assert(saveStart < start, "We have to read something. Otherwise it's dead loop.");
949 #endif
950             return true;
951         }
952
953         internal ArrayList CompileAvt(string avtText, out bool constant) {
954             Debug.Assert(avtText != null);
955             ArrayList list = new ArrayList();
956
957             constant = true;
958             /* Parse input.Value as AVT */ {
959                 int  pos = 0;
960                 bool isAvt;
961                 while (GetNextAvtLex(avtText, ref pos, this.AvtStringBuilder, out isAvt)) {
962                     string lex = this.AvtStringBuilder.ToString();
963                     if (isAvt) {
964                         list.Add(new AvtEvent(this.AddStringQuery(lex)));
965                         constant = false;
966                     }
967                     else {
968                         list.Add(new TextEvent(lex));
969                     }
970                 }
971             }
972             Debug.Assert(!constant || list.Count <= 1, "We can't have more then 1 text event if now {avt} found");
973             return list;
974         }
975
976         internal ArrayList CompileAvt(string avtText) {
977             bool constant;
978             return CompileAvt(avtText, out constant);
979         }
980
981         // Compiler is a class factory for some actions:
982         // CompilerDbg override all this methods:
983
984         public virtual ApplyImportsAction CreateApplyImportsAction() {
985             ApplyImportsAction action = new ApplyImportsAction();
986             action.Compile(this);
987             return action;
988         }
989
990         public virtual ApplyTemplatesAction CreateApplyTemplatesAction() {
991             ApplyTemplatesAction action = new ApplyTemplatesAction();
992             action.Compile(this);
993             return action;
994         }
995
996         public virtual AttributeAction CreateAttributeAction() {
997             AttributeAction action = new AttributeAction();
998             action.Compile(this);
999             return action;
1000         }
1001
1002         public virtual AttributeSetAction CreateAttributeSetAction() {
1003             AttributeSetAction action = new AttributeSetAction();
1004             action.Compile(this);
1005             return action;
1006         }
1007
1008         public virtual CallTemplateAction CreateCallTemplateAction() {
1009             CallTemplateAction action = new CallTemplateAction();
1010             action.Compile(this);
1011             return action;
1012         }
1013
1014         public virtual ChooseAction CreateChooseAction() {//!!! don't need to be here
1015             ChooseAction action = new ChooseAction();
1016             action.Compile(this);
1017             return action;
1018         }
1019
1020         public virtual CommentAction CreateCommentAction() {
1021             CommentAction action = new CommentAction();
1022             action.Compile(this);
1023             return action;
1024         }
1025
1026         public virtual CopyAction CreateCopyAction() {
1027             CopyAction action = new CopyAction();
1028             action.Compile(this);
1029             return action;
1030         }
1031
1032         public virtual CopyOfAction CreateCopyOfAction() {
1033             CopyOfAction action = new CopyOfAction();
1034             action.Compile(this);
1035             return action;
1036         }
1037
1038         public virtual ElementAction CreateElementAction() {
1039             ElementAction action = new ElementAction();
1040             action.Compile(this);
1041             return action;
1042         }
1043
1044         public virtual ForEachAction CreateForEachAction() {
1045             ForEachAction action = new ForEachAction();
1046             action.Compile(this);
1047             return action;
1048         }
1049
1050         public virtual IfAction CreateIfAction(IfAction.ConditionType type) {
1051             IfAction action = new IfAction(type);
1052             action.Compile(this);
1053             return action;
1054         }
1055
1056         public virtual MessageAction CreateMessageAction() {
1057             MessageAction action = new MessageAction();
1058             action.Compile(this);
1059             return action;
1060         }
1061
1062         public virtual NewInstructionAction CreateNewInstructionAction() {
1063             NewInstructionAction action = new NewInstructionAction();
1064             action.Compile(this);
1065             return action;
1066         }
1067
1068         public virtual NumberAction CreateNumberAction() {
1069             NumberAction action = new NumberAction();
1070             action.Compile(this);
1071             return action;
1072         }
1073
1074         public virtual ProcessingInstructionAction CreateProcessingInstructionAction() {
1075             ProcessingInstructionAction action = new ProcessingInstructionAction();
1076             action.Compile(this);
1077             return action;
1078         }
1079
1080         public virtual void CreateRootAction() {
1081             this.RootAction = new RootAction();
1082             this.RootAction.Compile(this);
1083         }
1084
1085         public virtual SortAction CreateSortAction() {
1086             SortAction action = new SortAction();
1087             action.Compile(this);
1088             return action;
1089         }
1090
1091         public virtual TemplateAction CreateTemplateAction() {
1092             TemplateAction action = new TemplateAction();
1093             action.Compile(this);
1094             return action;
1095         }
1096
1097         public virtual TemplateAction CreateSingleTemplateAction() {
1098             TemplateAction action = new TemplateAction();
1099             action.CompileSingle(this);
1100             return action;
1101         }
1102
1103         public virtual TextAction CreateTextAction() {
1104             TextAction action = new TextAction();
1105             action.Compile(this);
1106             return action;
1107         }
1108
1109         public virtual UseAttributeSetsAction CreateUseAttributeSetsAction() {
1110             UseAttributeSetsAction action = new UseAttributeSetsAction();
1111             action.Compile(this);
1112             return action;
1113         }
1114
1115         public virtual ValueOfAction CreateValueOfAction() {
1116             ValueOfAction action = new ValueOfAction();
1117             action.Compile(this);
1118             return action;
1119         }
1120
1121         public virtual VariableAction CreateVariableAction(VariableType type) {
1122             VariableAction action = new VariableAction(type);
1123             action.Compile(this);
1124             if (action.VarKey != InvalidQueryKey) {
1125                 return action;
1126             }
1127             else {
1128                 return null;
1129             }
1130         }
1131
1132         public virtual WithParamAction CreateWithParamAction() {
1133             WithParamAction action = new WithParamAction();
1134             action.Compile(this);
1135             return action;
1136         }
1137
1138         // Compiler is a class factory for some events:
1139         // CompilerDbg override all this methods:
1140
1141         public virtual BeginEvent CreateBeginEvent() {
1142             return new BeginEvent(this);
1143         }
1144
1145         public virtual TextEvent CreateTextEvent() {
1146             return new TextEvent(this);
1147         }
1148
1149         public XsltException UnexpectedKeyword() {
1150             XPathNavigator nav = this.Input.Navigator.Clone();
1151             string thisName = nav.Name;
1152             nav.MoveToParent();
1153             string parentName = nav.Name;
1154             return XsltException.Create(Res.Xslt_UnexpectedKeyword, thisName, parentName);
1155         }
1156
1157         internal class ErrorXPathExpression : CompiledXpathExpr {
1158             private string baseUri;
1159             private int lineNumber, linePosition;
1160             public ErrorXPathExpression(string expression, string baseUri, int lineNumber, int linePosition)
1161                 :  base(null, expression, false)
1162             {
1163                 this.baseUri      = baseUri;
1164                 this.lineNumber   = lineNumber;
1165                 this.linePosition = linePosition;
1166             }
1167
1168             public override XPathExpression Clone() { return this; }
1169             public override void CheckErrors() {
1170                 throw new XsltException(Res.Xslt_InvalidXPath, new string[] { Expression }, baseUri, linePosition, lineNumber, null);
1171             }
1172         }
1173     }
1174 }