2007-11-14 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / Mono.Xml.Ext / Mono.Xml.XPath2 / XQueryASTCompiler.cs
1 //
2 // XQueryASTCompiler.cs - XQuery static context compiler
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if NET_2_0
30
31 using System;
32 using System.Collections;
33 using System.Collections.Specialized;
34 using System.IO;
35 using System.Security.Policy;
36 using System.Xml;
37 using System.Xml.Query;
38 using System.Xml.Schema;
39 using Mono.Xml.XQuery;
40 using Mono.Xml.XQuery.Parser;
41 using Mono.Xml;
42
43 namespace Mono.Xml.XPath2
44 {
45         internal class XQueryASTCompiler
46         {
47                 // Static method
48
49                 public static XQueryStaticContext Compile (XQueryModule module, XQueryCompileOptions options, Evidence evidence, XQueryCommandImpl commandImpl)
50                 {
51                         if (options == null)
52                                 options = new XQueryCompileOptions ();
53                         return new XQueryASTCompiler (module, options, new XQueryCompileContext (), evidence, commandImpl).Compile ();
54                 }
55
56                 // Constructor
57
58                 private XQueryASTCompiler (XQueryModule module, XQueryCompileOptions options, XQueryCompileContext compileContext, Evidence evidence, XQueryCommandImpl commandImpl)
59                 {
60                         this.module = module;
61                         this.options = options;
62                         this.compileContext = compileContext;
63                         this.evidence = evidence;
64                         this.commandImpl = commandImpl;
65
66                         inScopeSchemas = new XmlSchemaSet ();
67                         localVariables = new Hashtable ();
68                         localFunctions = new XQueryFunctionTable ();
69                 }
70
71                 XQueryModule module;
72                 XQueryCompileOptions options;
73                 XQueryCompileContext compileContext;
74
75                 IXmlNamespaceResolver nsResolver;
76                 string defaultFunctionNamespace;
77
78                 // FIXME: Is it OK for an XmlSchema to be in two or more set?
79                 XmlSchemaSet inScopeSchemas;
80                 ArrayList libModuleContexts = new ArrayList ();
81
82                 Hashtable localVariables;
83                 XQueryFunctionTable localFunctions;
84
85                 bool preserveWhitespace; // Xml space policy
86                 bool constructionSpace; // construction mode
87                 bool defaultOrdered; // Ordering mode
88                 string baseUri;
89                 Evidence evidence;
90                 XQueryCommandImpl commandImpl;
91
92                 // methods.
93
94                 private XQueryStaticContext Compile ()
95                 {
96                         CompileProlog ();
97
98                         XQueryMainModule main = module as XQueryMainModule;
99                         ExprSequence expr = (main != null) ?
100                                 CompileExprSequence (main.QueryBody) : null;
101
102                         return new XQueryStaticContext (
103                                 options,
104                                 compileContext,
105                                 expr,
106                                 inScopeSchemas,
107                                 localVariables,
108                                 localFunctions,
109                                 module.NSResolver,
110                                 module.Prolog.DefaultFunctionNamespace,
111                                 preserveWhitespace,
112                                 constructionSpace,
113                                 defaultOrdered,
114                                 baseUri,
115                                 evidence,
116                                 commandImpl);
117                 }
118
119                 private void CompileProlog ()
120                 {
121                         Prolog p = module.Prolog;
122
123                         // resolve external modules
124                         // FIXME: check if external queries are allowed by default.
125                         // FIXME: check recursion
126                         XmlUrlResolver res = new XmlUrlResolver ();
127                         foreach (ModuleImport modimp in p.ModuleImports) {
128                                 foreach (string uri in modimp.Locations) {
129                                         Stream s = res.GetEntity (res.ResolveUri (null, uri), null, typeof (Stream)) as Stream;
130                                         XQueryLibraryModule ext = Mono.Xml.XQuery.Parser.Parser.Parse (new StreamReader (s)) as XQueryLibraryModule;
131                                         if (ext == null)
132                                                 throw new XmlQueryCompileException (String.Format ("External module {0} is resolved as a main module, while it should be a library module."));
133                                         XQueryStaticContext sctx = new XQueryASTCompiler (ext, options, compileContext, evidence, commandImpl).Compile ();
134                                         libModuleContexts.Add (sctx);
135                                 }
136                         }
137
138                         // resolve and compile in-scope schemas
139                         foreach (SchemaImport xsimp in p.SchemaImports) {
140                                 foreach (string uri in xsimp.Locations) {
141                                         XmlSchema schema = inScopeSchemas.Add (xsimp.Namespace, uri);
142                                         compileContext.InEffectSchemas.Add (schema);
143                                 }
144                         }
145                         inScopeSchemas.Compile ();
146
147                         CheckReferences ();
148
149                         ResolveVariableReferences ();
150
151                         // compile FunctionDeclaration into XQueryFunction
152                         foreach (FunctionDeclaration func in p.Functions.Values) {
153                                 XQueryFunction cfunc = CompileFunction (func);
154                                 localFunctions.Add (cfunc);
155                         }
156                 }
157
158                 private void CheckReferences ()
159                 {
160                         XQueryMainModule main = module as XQueryMainModule;
161                         if (main != null)
162                                 main.QueryBody.CheckReference (this);
163                         foreach (FunctionDeclaration func in module.Prolog.Functions.Values) {
164                                 if (!func.External)
165                                         func.FunctionBody.CheckReference (this);
166                                 CheckSchemaType (func.ReturnType);
167                                 foreach (XQueryFunctionArgument param in func.Parameters)
168                                         CheckSchemaType (param.Type);
169                         }
170                 }
171
172                 internal void CheckSchemaType (SequenceType type)
173                 {
174                         if (type == null)
175                                 return;
176                         type.ItemType.CheckReference (this);
177                 }
178
179                 internal void CheckSchemaTypeName (XmlQualifiedName name)
180                 {
181                         XmlSchemaType type = InternalPool.GetBuiltInType (name);
182                         if (type != null)
183                                 return;
184                         throw new XmlQueryCompileException (String.Format ("Unresolved schema type name: {0}", name));
185                 }
186
187                 internal void CheckVariableName (XmlQualifiedName name)
188                 {
189                         // This should not be done, since unresolved QName
190                         // may be still valid in context of XmlArgumentList
191                         // which is supplied at dynamic evaluation phase.
192                         /*
193                         if (module.Prolog.Variables [name] != null)
194                                 return;
195                         if (localVariables [name] != null)
196                                 return;
197                         foreach (XQueryStaticContext ctx in libModuleContexts)
198                                 if (ctx.InScopeVariables [name] != null)
199                                         return;
200                         throw new XmlQueryCompileException (String.Format ("Unresolved variable name: {0}", name));
201                         */
202                 }
203
204                 internal void CheckFunctionName (XmlQualifiedName name)
205                 {
206                         if (XQueryFunction.FindKnownFunction (name) != null)
207                                 return;
208                         if (module.Prolog.Functions [name] != null)
209                                 return;
210                         foreach (XQueryStaticContext ctx in libModuleContexts)
211                                 if (ctx.InScopeFunctions [name] != null)
212                                         return;
213                         throw new XmlQueryCompileException (String.Format ("Unresolved function name: {0}", name));
214                 }
215
216                 private void ResolveVariableReferences ()
217                 {
218                         // TODO
219                 }
220
221                 internal XmlSchemaType ResolveSchemaType (XmlQualifiedName name)
222                 {
223                         XmlSchemaType type = InternalPool.GetBuiltInType (name);
224                         if (type != null)
225                                 return type;
226                         type = inScopeSchemas.GlobalTypes [name] as XmlSchemaType;
227                         if (type != null)
228                                 return type;
229                         return null;
230                 }
231
232                 private XQueryFunction CompileFunction (FunctionDeclaration func)
233                 {
234                         if (func.External)
235                                 return XQueryFunction.FromQName (func.Name);
236                         return new XQueryUserFunction (func.Name, func.Parameters.ToArray (), func.FunctionBody.Expr, func.ReturnType);
237                 }
238
239                 private ExprSequence CompileExprSequence (ExprSequence expr)
240                 {
241                         for (int i = 0; i < expr.Count; i++)
242                                 expr [i] = expr [i].Compile (this);
243                         return expr;
244                 }
245
246                 internal void CheckType (ExprSingle expr, SequenceType type)
247                 {
248                         if (!expr.StaticType.CanConvertTo (type))
249                                 throw new XmlQueryCompileException (String.Format ("Cannot convert type from {0} to {1}", expr.StaticType, type));
250                 }
251
252                 internal XQueryFunction ResolveFunction (XmlQualifiedName name)
253                 {
254                         XQueryFunction func = XQueryFunction.FindKnownFunction (name);
255                         if (func == null)
256                                 func = localFunctions [name];
257
258                         if (func != null)
259                                 return func;
260                         else
261                                 throw new XmlQueryCompileException ("Could not find specified function.");
262                 }
263         }
264 }
265 #endif