2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.XML / System.Xml.Query / XPath2Expression.cs
1 //
2 // XPath2Expression.cs - abstract syntax tree for XPath 2.0
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 #if NET_2_0
30 using System;
31 using System.Collections;
32 using System.Globalization;
33 using System.Xml;
34 using System.Xml.Query;
35 using System.Xml.Schema;
36 using System.Xml.XPath;
37 using Mono.Xml.XQuery;
38
39 namespace Mono.Xml.XPath2
40 {
41         public class ExprSequence : CollectionBase
42         {
43                 public ExprSequence ()
44                 {
45                 }
46
47                 public void Add (ExprSingle expr)
48                 {
49                         List.Add (expr);
50                 }
51
52                 public void AddRange (ICollection items)
53                 {
54                         if (items != null)
55                                 foreach (ExprSingle e in items)
56                                         List.Add (e);
57                 }
58
59                 public void Insert (int pos, ExprSingle expr)
60                 {
61                         List.Insert (pos, expr);
62                 }
63
64                 public ExprSingle this [int i] {
65                         get { return List [i] as ExprSingle; }
66                         set { List [i] = value; }
67                 }
68
69                 internal void CheckReference (XQueryASTCompiler compiler)
70                 {
71                         foreach (ExprSingle expr in List)
72                                 expr.CheckReference (compiler);
73                 }
74         }
75
76         public abstract partial class ExprSingle
77         {
78                 internal abstract void CheckReference (XQueryASTCompiler compiler);
79
80 #region CompileAndEvaluate
81                 internal static readonly XPathAtomicValue AtomicTrue = new XPathAtomicValue (true, XmlSchemaSimpleType.XsBoolean);
82                 internal static readonly XPathAtomicValue AtomicFalse = new XPathAtomicValue (false, XmlSchemaSimpleType.XsBoolean);
83
84                 XQueryStaticContext ctx;
85
86                 internal ExprSingle Compile (XQueryASTCompiler compiler)
87                 {
88                         this.ctx = ctx;
89                         return CompileCore (compiler);
90                 }
91
92                 // If internal&&protected is available in C#, it is the best signature.
93                 internal abstract ExprSingle CompileCore (XQueryASTCompiler compiler);
94
95                 internal XQueryStaticContext Context {
96                         get { return ctx; }
97                 }
98
99                 public abstract SequenceType StaticType { get; }
100
101                 /** <summary>
102                         This is the core part of ExprSingle. It is
103                         generally used to evaluate expression and returns
104                         XPathItem sequence (iterator). The result is unordered
105                 */
106                 public abstract XPathSequence Evaluate (XPathSequence iter);
107
108                 public virtual XPathSequence EvaluateOrdered (XPathSequence iter)
109                 {
110                         if (RequireSorting) {
111                                 ArrayList al = new ArrayList ();
112                                 foreach (XPathItem item in Evaluate (iter))
113                                         al.Add (item);
114                                 return new ListIterator (iter.Context, al);
115                         }
116                         else
117                                 return Evaluate (iter);
118                 }
119
120                 public virtual void Serialize (XPathSequence iter)
121                 {
122                         XmlWriter w = iter.Context.Writer;
123                         XPathSequence result = Evaluate (iter);
124                         bool initial = true;
125                         foreach (XPathItem item in result) {
126                                 if (initial)
127                                         initial = false;
128                                 else
129                                         w.WriteWhitespace (" ");
130                                 WriteXPathItem (item, w);
131                         }
132                 }
133
134                 private void WriteXPathItem (XPathItem item, XmlWriter w)
135                 {
136                         if (item.IsNode) {
137                                 XPathNavigator nav = item as XPathNavigator;
138                                 if (w.WriteState != WriteState.Start && nav.NodeType == XPathNodeType.Root)
139                                         throw new XmlQueryException ("Current output can not accept root node.");
140                                 if (w.WriteState == WriteState.Attribute)
141                                         w.WriteString (nav.Value);
142                                 else
143                                         w.WriteNode (nav, false);
144                         } else
145                                 w.WriteString (item.Value);
146                 }
147
148                 // get EBV (fn:boolean())
149                 public virtual bool EvaluateAsBoolean (XPathSequence iter)
150                 {
151                         XPathSequence result = Evaluate (iter);
152                         if (!result.MoveNext ())
153                                 return false;
154                         XPathItem v = result.Current;
155                         if (v is XPathNavigator)
156                                 return true;
157                         if (result.MoveNext ())
158                                 return true;
159                         switch (v.XmlType.TypeCode) {
160                         case XmlTypeCode.Boolean:
161                                 return v.ValueAsBoolean;
162                         case XmlTypeCode.String:
163                         case XmlTypeCode.UntypedAtomic:
164                                 return v.Value != String.Empty;
165                         case XmlTypeCode.Float:
166                                 return v.ValueAsSingle != Single.NaN && v.ValueAsSingle != 0.0;
167                         case XmlTypeCode.Double:
168                                 return v.ValueAsDouble != Double.NaN && v.ValueAsSingle != 0.0;
169                         case XmlTypeCode.Decimal:
170                                 return v.ValueAsDecimal != 0;
171                         case XmlTypeCode.Integer:
172                         case XmlTypeCode.NonPositiveInteger:
173                         case XmlTypeCode.NegativeInteger:
174                         case XmlTypeCode.Long:
175                         case XmlTypeCode.Int:
176                         case XmlTypeCode.Short:
177                         case XmlTypeCode.Byte:
178                         case XmlTypeCode.UnsignedInt:
179                         case XmlTypeCode.UnsignedShort:
180                         case XmlTypeCode.UnsignedByte:
181                                 return v.ValueAsInt64 != 0;
182                         case XmlTypeCode.NonNegativeInteger:
183                         case XmlTypeCode.UnsignedLong:
184                         case XmlTypeCode.PositiveInteger:
185                                 return (ulong) (v.ValueAs (typeof (ulong))) != 0;
186                         }
187                         // otherwise, return true
188                         return true;
189                 }
190
191                 public virtual int EvaluateAsInt (XPathSequence iter)
192                 {
193                         XPathAtomicValue v = Atomize (Evaluate (iter));
194                         return v != null ? v.ValueAsInt32 : 0;
195                 }
196
197                 public virtual string EvaluateAsString (XPathSequence iter)
198                 {
199                         XPathAtomicValue v = Atomize (Evaluate (iter));
200                         return v != null ? v.Value : String.Empty;
201                 }
202
203                 public static XPathAtomicValue Atomize (XPathItem item)
204                 {
205                         XPathNavigator nav = item as XPathNavigator;
206                         if (nav != null) {
207                                 if (nav.SchemaInfo != null)
208                                         return new XPathAtomicValue (nav.TypedValue, nav.SchemaInfo.SchemaType);
209                                 else
210                                         return new XPathAtomicValue (nav.Value, XmlSchemaSimpleType.XdtUntypedAtomic);
211                         }
212                         else
213                                 return (XPathAtomicValue) item;
214                 }
215
216                 // FIXME: What if iter contains list value?
217                 public static XPathAtomicValue Atomize (XPathSequence iter)
218                 {
219                         if (!iter.MoveNext ())
220                                 return null;
221                         XPathNavigator nav = iter.Current as XPathNavigator;
222                         if (nav != null) {
223                                 // FIXME: is it really always untypedAtomic?
224                                 // It might be complex content.
225                                 XmlSchemaType type = nav.SchemaInfo == null ? XmlSchemaSimpleType.XdtUntypedAtomic : nav.SchemaInfo.SchemaType;
226                                 return new XPathAtomicValue (nav.TypedValue, type);
227                         }
228                         else
229                                 return (XPathAtomicValue) iter.Current;
230                 }
231
232                 public virtual XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
233                 {
234                         return Atomize (Evaluate (iter));
235                 }
236
237                 public virtual bool RequireSorting {
238                         get { return false; }
239                 }
240 #endregion
241         }
242
243         // FLWORExpr
244
245         internal partial class FLWORExpr : ExprSingle
246         {
247                 public FLWORExpr (ForLetClauseCollection forlet, ExprSequence whereClause, OrderSpecList orderBy, ExprSingle ret)
248                 {
249                         this.fl = forlet;
250                         if (whereClause != null)
251                                 this.whereClause = new ParenthesizedExpr (whereClause);
252                         this.orderBy = orderBy;
253                         this.ret = ret;
254                 }
255
256                 ForLetClauseCollection fl;
257                 ExprSingle whereClause;
258                 OrderSpecList orderBy;
259                 ExprSingle ret;
260
261                 public ForLetClauseCollection ForLetClauses {
262                         get { return fl; }
263                 }
264
265                 public ExprSingle WhereClause {
266                         get { return whereClause; }
267                 }
268
269                 public OrderSpecList OrderBy {
270                         get { return orderBy; }
271                 }
272
273                 public ExprSingle ReturnExpr {
274                         get { return ret; }
275                         set { ret = value; }
276                 }
277
278                 // ExprSingle Overrides
279
280                 internal override void CheckReference (XQueryASTCompiler compiler)
281                 {
282                         foreach (ForLetClause flc in fl)
283                                 foreach (ForLetSingleBody single in flc)
284                                         single.CheckReference (compiler);
285                         if (whereClause != null)
286                                 whereClause.CheckReference (compiler);
287                         if (orderBy != null)
288                                 foreach (OrderSpec os in orderBy)
289                                         os.Expression.CheckReference (compiler);
290                         ret.CheckReference (compiler);
291                 }
292
293 #region CompileAndEvaluate
294                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
295                 {
296                         foreach (ForLetClause flc in ForLetClauses) {
297                                 foreach (ForLetSingleBody flsb in flc) {
298                                         flsb.Expression = flsb.Expression.Compile (compiler);
299                                         if (flsb.ReturnType != null)
300                                                 compiler.CheckType (flsb.Expression, flsb.ReturnType);
301                                 }
302                         }
303                         if (WhereClause != null)
304                                 whereClause = whereClause.Compile (compiler);
305                         if (OrderBy != null)
306                                 foreach (OrderSpec os in OrderBy)
307                                         os.Expression = os.Expression.Compile (compiler);
308                         ReturnExpr = ReturnExpr.Compile (compiler);
309
310                         return this;
311                 }
312
313                 public override SequenceType StaticType {
314                         get { return ReturnExpr.StaticType; }
315                 }
316
317                 public override XPathSequence Evaluate (XPathSequence iter)
318                 {
319                         return new FLWORIterator (iter, this);
320                 }
321 #endregion
322         }
323
324         internal class ForLetClauseCollection : CollectionBase
325         {
326                 public void Add (ForLetClause clause)
327                 {
328                         List.Add (clause);
329                 }
330
331                 public void Insert (int pos, ForLetClause clause)
332                 {
333                         List.Insert (pos, clause);
334                 }
335
336                 public ForLetClause this [int i] {
337                         get { return (ForLetClause) List [i]; }
338                 }
339         }
340
341         internal class OrderSpecList : CollectionBase
342         {
343                 bool isStable;
344
345                 public OrderSpecList ()
346                 {
347                 }
348
349                 public bool IsStable {
350                         get { return isStable; }
351                         set { isStable = value; }
352                 }
353
354                 public void Insert (int pos, OrderSpec os)
355                 {
356                         List.Insert (pos, os);
357                 }
358
359                 public void Add (OrderSpec spec)
360                 {
361                         List.Add (spec);
362                 }
363
364                 public OrderSpec this [int i] {
365                         get { return (OrderSpec) List [i]; }
366                 }
367         }
368
369         internal class OrderSpec
370         {
371                 public OrderSpec (ExprSingle expr, OrderModifier modifier)
372                 {
373                         this.expr = expr;
374                         this.mod = modifier;
375                 }
376
377                 ExprSingle expr;
378                 OrderModifier mod;
379
380                 public ExprSingle Expression {
381                         get {return expr; }
382                         set { expr = value; }
383                 }
384
385                 public OrderModifier Modifier {
386                         get { return mod; }
387                         set { mod = value; }
388                 }
389         }
390
391         internal class OrderModifier
392         {
393                 public OrderModifier (XmlSortOrder order, XmlSortOrder emptyOrder, string collation)
394                 {
395                         this.sortOrder = sortOrder;
396                         this.emptyOrder = emptyOrder;
397                         if (collation != null)
398                                 this.coll = new CultureInfo (collation);
399                 }
400
401                 XmlSortOrder sortOrder;
402                 XmlSortOrder emptyOrder;
403                 CultureInfo coll;
404
405                 public XmlSortOrder SortOrder {
406                         get { return sortOrder; }
407                 }
408
409                 public XmlSortOrder EmptyOrder {
410                         get { return emptyOrder; }
411                 }
412
413                 public CultureInfo Collation {
414                         get { return coll; }
415                 }
416         }
417
418         internal class ForLetClause : CollectionBase
419         {
420                 public ForLetSingleBody this [int i] {
421                         get { return (ForLetSingleBody) List [i]; }
422                 }
423         }
424
425         internal class ForClause : ForLetClause
426         {
427                 public ForClause ()
428                 {
429                 }
430
431                 public void Insert (int pos, ForSingleBody body)
432                 {
433                         List.Insert (pos, body);
434                 }
435
436                 public void Add (ForSingleBody body)
437                 {
438                         List.Add (body);
439                 }
440         }
441
442         internal class LetClause : ForLetClause
443         {
444                 public LetClause ()
445                 {
446                 }
447
448                 public void Insert (int pos, LetSingleBody body)
449                 {
450                         List.Insert (pos, body);
451                 }
452
453                 public void Add (LetSingleBody body)
454                 {
455                         List.Add (body);
456                 }
457         }
458
459         internal abstract class ForLetSingleBody
460         {
461                 XmlQualifiedName varName;
462                 SequenceType type;
463                 ExprSingle expr;
464
465                 public ForLetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr)
466                 {
467                         this.varName = varName;
468                         this.type = type;
469                         this.expr = expr;
470                 }
471
472                 public XmlQualifiedName VarName {
473                         get { return varName; }
474                 }
475
476                 public SequenceType ReturnType {
477                         get { return type; }
478                 }
479
480                 public ExprSingle Expression {
481                         get { return expr; }
482                         set { expr = value; }
483                 }
484
485                 internal void CheckReference (XQueryASTCompiler compiler)
486                 {
487                         if (type != null)
488                                 compiler.CheckSchemaType (type);
489                         expr.CheckReference (compiler);
490                 }
491         }
492
493         internal class ForSingleBody : ForLetSingleBody
494         {
495                 public ForSingleBody (XmlQualifiedName varName, SequenceType type, XmlQualifiedName positionalVar, ExprSingle expr)
496                         : base (varName, type, expr)
497                 {
498                         this.positionalVar = positionalVar;
499                 }
500
501                 XmlQualifiedName positionalVar;
502
503                 public XmlQualifiedName PositionalVar {
504                         get { return positionalVar; }
505                 }
506         }
507
508         internal class LetSingleBody : ForLetSingleBody
509         {
510                 public LetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr)
511                         : base (varName, type, expr)
512                 {
513                 }
514         }
515
516         // QuantifiedExpr
517
518         internal class QuantifiedExpr : ExprSingle
519         {
520                 QuantifiedExprBodyList body;
521                 ExprSingle satisfies;
522                 bool every;
523
524                 public QuantifiedExpr (bool every, QuantifiedExprBodyList body, ExprSingle satisfies)
525                 {
526                         this.every = every;
527                         this.body = body;
528                         this.satisfies = satisfies;
529                 }
530
531                 public bool Every {
532                         get { return every; }
533                 }
534
535                 public QuantifiedExprBodyList BodyList {
536                         get { return body; }
537                 }
538
539                 public ExprSingle Satisfies {
540                         get { return satisfies; }
541                         set { satisfies = value; }
542                 }
543
544                 internal override void CheckReference (XQueryASTCompiler compiler)
545                 {
546                         foreach (QuantifiedExprBody one in body) {
547                                 if (one.Type != null)
548                                         compiler.CheckSchemaType (one.Type);
549                                 one.Expression.CheckReference (compiler);
550                         }
551                         Satisfies.CheckReference (compiler);
552                 }
553
554 #region CompileAndEvaluate
555                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
556                 {
557                         Satisfies = Satisfies.Compile (compiler);
558                         for (int i = 0; i < BodyList.Count; i++) {
559                                 BodyList [i].Expression = BodyList [i].Expression.Compile (compiler);
560                                 if (BodyList [i].Type != null)
561                                         compiler.CheckType (BodyList [i].Expression, BodyList [i].Type);
562                         }
563                         return this;
564                 }
565
566                 public override SequenceType StaticType {
567                         get { return SequenceType.Boolean; }
568                 }
569
570                 public override XPathSequence Evaluate (XPathSequence iter)
571                 {
572                         return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
573                 }
574
575                 public override bool EvaluateAsBoolean (XPathSequence iter)
576                 {
577                         return EvaluateQuantification (iter, BodyList.GetEnumerator ());
578                 }
579
580                 private bool EvaluateQuantification (XPathSequence iter, IEnumerator bodies)
581                 {
582                         if (bodies.MoveNext ()) {
583                                 QuantifiedExprBody qb = bodies.Current as QuantifiedExprBody;
584                                 XPathSequence seq = qb.Expression.Evaluate (iter);
585                                 bool passed = false;
586                                 foreach (XPathItem item in seq) {
587                                         passed = true;
588                                         // FIXME: consider qb.Type
589                                         try {
590                                                 iter.Context.PushVariable (qb.VarName, item);
591                                                 if (EvaluateQuantification (iter, bodies)) {
592                                                         if (!Every)
593                                                                 return true;
594                                                 }
595                                                 else if (Every)
596                                                         return false;
597                                         } finally {
598                                                 iter.Context.PopVariable ();
599                                         }
600                                 }
601                                 return passed;
602                         }
603                         return Satisfies.EvaluateAsBoolean (iter);
604                 }
605 #endregion
606         }
607
608         internal class QuantifiedExprBodyList : CollectionBase
609         {
610                 public QuantifiedExprBodyList ()
611                 {
612                 }
613
614                 public void Add (QuantifiedExprBody body)
615                 {
616                         List.Add (body);
617                 }
618
619                 public void Insert (int pos, QuantifiedExprBody body)
620                 {
621                         List.Insert (pos, body);
622                 }
623
624                 public QuantifiedExprBody this [int i] {
625                         get { return (QuantifiedExprBody) List [i]; }
626                 }
627         }
628
629         internal class QuantifiedExprBody
630         {
631                 private XmlQualifiedName varName;
632                 private SequenceType type;
633                 private ExprSingle expr;
634
635                 public QuantifiedExprBody (XmlQualifiedName varName,
636                         SequenceType type, ExprSingle expr)
637                 {
638                         this.varName = varName;
639                         this.type = type ;
640                         this.expr = expr;
641                 }
642
643                 public XmlQualifiedName VarName {
644                         get { return varName; }
645                 }
646
647                 public SequenceType Type {
648                         get { return type; }
649                 }
650
651                 public ExprSingle Expression {
652                         get { return expr; }
653                         set { expr = value; }
654                 }
655         }
656
657         // TypeswitchExpr
658
659         internal class TypeswitchExpr : ExprSingle
660         {
661                 ExprSequence switchExpr;
662                 CaseClauseList caseList;
663                 XmlQualifiedName defaultVarName;
664                 ExprSingle defaultReturn;
665
666                 public TypeswitchExpr (ExprSequence switchExpr, CaseClauseList caseList, XmlQualifiedName defaultVarName, ExprSingle defaultReturn)
667                 {
668                         this.switchExpr = switchExpr;
669                         this.caseList = caseList;
670                         this.defaultVarName = defaultVarName;
671                         this.defaultReturn = defaultReturn;
672                 }
673
674                 public ExprSequence SwitchExpr {
675                         get { return switchExpr; }
676                 }
677
678                 public CaseClauseList Cases {
679                         get { return caseList; }
680                 }
681
682                 public XmlQualifiedName DefaultVarName {
683                         get { return defaultVarName; }
684                 }
685
686                 public ExprSingle DefaultReturn {
687                         get { return defaultReturn; }
688                         set { defaultReturn = value; }
689                 }
690
691                 internal override void CheckReference (XQueryASTCompiler compiler)
692                 {
693                         switchExpr.CheckReference (compiler);
694                         foreach (CaseClause cc in caseList) {
695                                 compiler.CheckSchemaType (cc.Type);
696                                 cc.Expr.CheckReference (compiler);
697                         }
698                         defaultReturn.CheckReference (compiler);
699                 }
700
701 #region CompileAndEvaluate
702                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
703                 {
704                         for (int i = 0; i < SwitchExpr.Count; i++)
705                                 SwitchExpr [i] = SwitchExpr [i].Compile (compiler);
706                         foreach (CaseClause cc in Cases)
707                                 cc.Expr = cc.Expr.Compile (compiler);
708                         DefaultReturn = DefaultReturn.Compile (compiler);
709                         return this;
710                 }
711
712                 // FIXME: it can be optimized by checking all case clauses.
713                 public override SequenceType StaticType {
714                         get { return SequenceType.AnyType; }
715                 }
716
717                 public override XPathSequence Evaluate (XPathSequence iter)
718                 {
719                         // FIXME: should move to iterator?
720                         XPathSequence cond = new ExprSequenceIterator (iter, SwitchExpr);
721                         XPathSequence ret = null;
722
723                         foreach (CaseClause ccc in Cases) {
724                                 if (ccc.Type.Matches (cond)) {
725                                         if (ccc.VarName != XmlQualifiedName.Empty)
726                                                 iter.Context.PushVariable (ccc.VarName, cond);
727                                         ret = ccc.Expr.Evaluate (iter);
728                                         // FIXME: The design should make sure that in-scope variables are held on actual iteration.
729                                         if (ccc.VarName != XmlQualifiedName.Empty)
730                                                 iter.Context.PopVariable ();
731                                         return ret;
732                                 }
733                         }
734
735                         if (DefaultVarName != XmlQualifiedName.Empty)
736                                 iter.Context.PushVariable (DefaultVarName, cond);
737                         ret = DefaultReturn.Evaluate (iter);
738                         if (DefaultVarName != XmlQualifiedName.Empty)
739                                 iter.Context.PopVariable ();
740                         return ret;
741                 }
742 #endregion
743         }
744
745         internal class CaseClauseList : CollectionBase
746         {
747                 public void Insert (int pos, CaseClause cc)
748                 {
749                         List.Insert (pos, cc);
750                 }
751
752                 public void Add (CaseClause cc)
753                 {
754                         List.Add (cc);
755                 }
756
757                 public CaseClause this [int i] {
758                         get { return (CaseClause) List [i]; }
759                 }
760         }
761
762         internal class CaseClause
763         {
764                 public CaseClause (SequenceType type, ExprSingle expr, XmlQualifiedName varName)
765                 {
766                         this.type = type;
767                         this.expr = expr;
768                         this.varName = varName;
769                 }
770
771                 SequenceType type;
772                 ExprSingle expr;
773                 XmlQualifiedName varName;
774
775                 public SequenceType Type {
776                         get { return type; }
777                 }
778
779                 public ExprSingle Expr {
780                         get { return expr; }
781                         set { expr = value; }
782                 }
783
784                 public XmlQualifiedName VarName {
785                         get { return varName; }
786                         set { varName = value; }
787                 }
788         }
789
790         // IfExpr
791
792         internal class IfExpr : ExprSingle
793         {
794                 public IfExpr (ExprSequence condition, ExprSingle trueExpr, ExprSingle falseExpr)
795                 {
796                         this.condition = new ParenthesizedExpr (condition);
797                         this.trueExpr = trueExpr;
798                         this.falseExpr = falseExpr;
799                 }
800
801                 ExprSingle condition;
802                 ExprSingle trueExpr;
803                 ExprSingle falseExpr;
804
805                 public ExprSingle Condition {
806                         get { return condition; }
807                         set { condition = value; }
808                 }
809
810                 public ExprSingle TrueExpr {
811                         get { return trueExpr; }
812                         set { trueExpr = value; }
813                 }
814
815                 public ExprSingle FalseExpr {
816                         get { return falseExpr; }
817                         set { falseExpr = value; }
818                 }
819
820                 internal override void CheckReference (XQueryASTCompiler compiler)
821                 {
822                         condition.CheckReference (compiler);
823                         trueExpr.CheckReference (compiler);
824                         falseExpr.CheckReference (compiler);
825                 }
826
827 #region CompileAndEvaluate
828                 SequenceType computedReturnType;
829
830                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
831                 {
832                         condition = condition.Compile (compiler);
833                         // FIXME: check if condition is constant, and returns trueExpr or falseExpr
834                         TrueExpr = TrueExpr.Compile (compiler);
835                         FalseExpr = FalseExpr.Compile (compiler);
836                         return this;
837                 }
838
839                 public override SequenceType StaticType {
840                         get {
841                                 if (Context == null)
842                                         return SequenceType.AnyType;
843                                 if (computedReturnType == null)
844                                         computedReturnType = SequenceType.ComputeCommonBase (TrueExpr.StaticType, FalseExpr.StaticType);
845                                 return computedReturnType;
846                         }
847                 }
848
849                 public override XPathSequence Evaluate (XPathSequence iter)
850                 {
851                         if (condition.EvaluateAsBoolean (iter))
852                                 return TrueExpr.Evaluate (iter);
853                         return FalseExpr.Evaluate (iter);
854                 }
855 #endregion
856
857         }
858
859         // logical expr
860
861         internal abstract class BinaryOperationExpr : ExprSingle
862         {
863                 protected BinaryOperationExpr (ExprSingle left, ExprSingle right)
864                 {
865                         this.left = left;
866                         this.right = right;
867                 }
868
869                 ExprSingle left, right;
870                 
871                 public ExprSingle Left {
872                         get { return left; }
873                         set { left = value; }
874                 }
875
876                 public ExprSingle Right{
877                         get { return right; }
878                         set { right = value; }
879                 }
880
881                 internal override void CheckReference (XQueryASTCompiler compiler)
882                 {
883                         left.CheckReference (compiler);
884                         right.CheckReference (compiler);
885                 }
886
887 #region CompileAndEvaluate
888                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
889                 {
890                         Left = Left.Compile (compiler);
891                         Right = Right.Compile (compiler);
892                         return this;
893                 }
894 #endregion
895
896         }
897
898         internal class OrExpr : BinaryOperationExpr
899         {
900                 public OrExpr (ExprSingle left, ExprSingle right)
901                         : base (left, right)
902                 {
903                 }
904
905 #region CompileAndEvaluate
906                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
907                 {
908                         base.CompileCore (compiler);
909                         // FIXME: check constant value and return true or false
910                         return this;
911                 }
912
913                 public override SequenceType StaticType {
914                         get { return SequenceType.Boolean; }
915                 }
916
917                 public override bool EvaluateAsBoolean (XPathSequence iter)
918                 {
919                         return Left.EvaluateAsBoolean (iter) || Right.EvaluateAsBoolean (iter);
920                 }
921
922                 public override XPathSequence Evaluate (XPathSequence iter)
923                 {
924                         return new SingleItemIterator (EvaluateAsBoolean (iter) ?AtomicTrue : AtomicFalse, iter.Context);
925                 }
926
927                 /*
928                         - compiler -
929                         return leftExprBool (context) || rightExprBool (context);
930                 */
931 #endregion
932         }
933
934         internal class AndExpr : BinaryOperationExpr
935         {
936                 public AndExpr (ExprSingle left, ExprSingle right)
937                         : base (left, right)
938                 {
939                 }
940
941 #region CompileAndEvaluate
942                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
943                 {
944                         base.CompileCore (compiler);
945                         // FIXME: check constant value and return true or false
946                         return this;
947                 }
948
949                 public override SequenceType StaticType {
950                         get { return SequenceType.Boolean; }
951                 }
952
953                 public override bool EvaluateAsBoolean (XPathSequence iter)
954                 {
955                         return Left.EvaluateAsBoolean (iter) && Right.EvaluateAsBoolean (iter);
956                 }
957
958                 public override XPathSequence Evaluate (XPathSequence iter)
959                 {
960                         return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
961                 }
962
963                 /*
964                         - compiler -
965                         return leftExprBool (context) && rightExprBool (context);
966                 */
967 #endregion
968         }
969
970         // TypeOperation expr
971
972         internal abstract class TypeOperationExpr : ExprSingle
973         {
974                 protected TypeOperationExpr (ExprSingle expr, SequenceType type)
975                 {
976                         this.expr = expr;
977                         this.type = type;
978                 }
979
980                 ExprSingle expr;
981                 SequenceType type;
982
983                 public ExprSingle Expr {
984                         get { return expr; }
985                         set { expr = value; }
986                 }
987
988                 public SequenceType TargetType {
989                         get { return type; }
990                 }
991
992                 internal override void CheckReference (XQueryASTCompiler compiler)
993                 {
994                         expr.CheckReference (compiler);
995                         compiler.CheckSchemaType (type);
996                 }
997         }
998
999         internal abstract class AtomicTypeOperationExpr : ExprSingle
1000         {
1001                 protected AtomicTypeOperationExpr (ExprSingle expr, XmlTypeCode type, bool optional)
1002                 {
1003                         this.expr = expr;
1004                         this.targetType = SequenceType.Create (type, optional ? Occurence.Optional : Occurence.One);
1005                 }
1006
1007                 ExprSingle expr;
1008                 SequenceType targetType;
1009
1010                 internal ExprSingle Expr {
1011                         get { return expr; }
1012                         set { expr = value; }
1013                 }
1014
1015 /*
1016                 public XmlTypeCode TypeCode {
1017                         get { return typeCode; }
1018                 }
1019
1020                 public bool Optional {
1021                         get { return optional; }
1022                 }
1023 */
1024                 internal SequenceType TargetType {
1025                         get { return targetType; }
1026                 }
1027
1028                 internal override void CheckReference (XQueryASTCompiler compiler)
1029                 {
1030                         expr.CheckReference (compiler);
1031                 }
1032         }
1033
1034         internal class InstanceOfExpr : TypeOperationExpr
1035         {
1036                 public InstanceOfExpr (ExprSingle expr, SequenceType type)
1037                         : base (expr, type)
1038                 {
1039                 }
1040
1041 #region CompileAndEvaluate
1042                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1043                 {
1044                         Expr = Expr.Compile (compiler);
1045                         // FIXME: check return type and if it never matches then return false
1046                         return this;
1047                 }
1048
1049                 public override SequenceType StaticType {
1050                         get { return SequenceType.Boolean; }
1051                 }
1052
1053                 public override bool EvaluateAsBoolean (XPathSequence iter)
1054                 {
1055                         bool occured = false;
1056                         bool onlyOnce = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.Optional);
1057                         bool required = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.OneOrMore);
1058                         foreach (XPathItem item in iter) {
1059                                 if (occured && onlyOnce)
1060                                         return false;
1061                                 if (!TargetType.IsInstance (item))
1062                                         return false;
1063                         }
1064                         return occured || !required;
1065                 }
1066
1067                 public override XPathSequence Evaluate (XPathSequence iter)
1068                 {
1069                         return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
1070                 }
1071 #endregion
1072         }
1073
1074         internal class TreatExpr : TypeOperationExpr
1075         {
1076                 public TreatExpr (ExprSingle expr, SequenceType type)
1077                         : base (expr, type)
1078                 {
1079                 }
1080
1081 #region CompileAndEvaluate
1082                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1083                 {
1084                         Expr = Expr.Compile (compiler);
1085                         // FIXME: check return type and if it never matches then return false
1086                         return this;
1087                 }
1088
1089                 public override SequenceType StaticType {
1090                         get { return SequenceType.AnyType; }
1091                 }
1092
1093                 public override XPathSequence Evaluate (XPathSequence iter)
1094                 {
1095                         if (TargetType.CanConvert (iter))
1096                                 return iter;
1097                         else
1098                                 throw new XmlQueryException (String.Format ("Cannot treat as {1}", TargetType));
1099                 }
1100 #endregion
1101         }
1102
1103         internal class CastableExpr : AtomicTypeOperationExpr
1104         {
1105                 public CastableExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional)
1106                         : base (expr, atomicType, optional)
1107                 {
1108                 }
1109
1110 #region CompileAndEvaluate
1111                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1112                 {
1113                         Expr = Expr.Compile (compiler);
1114                         // FIXME: check return type and if it never matches then return boolean
1115                         return this;
1116                 }
1117
1118                 public override SequenceType StaticType {
1119                         get { return SequenceType.Boolean; }
1120                 }
1121
1122                 public override XPathSequence Evaluate (XPathSequence iter)
1123                 {
1124                         return new SingleItemIterator (new XPathAtomicValue (EvaluateAsBoolean (iter), XmlSchemaSimpleType.XsBoolean), iter.Context);
1125                 }
1126
1127                 public override bool EvaluateAsBoolean (XPathSequence iter)
1128                 {
1129                         bool occured = false;
1130                         bool onlyOnce = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.Optional);
1131                         bool required = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.OneOrMore);
1132                         foreach (XPathItem item in iter) {
1133                                 if (occured && onlyOnce)
1134                                         return false;
1135                                 if (!TargetType.CanConvert (item))
1136                                         return false;
1137                         }
1138                         return occured || !required;
1139                 }
1140 #endregion
1141         }
1142
1143         internal class CastExpr : AtomicTypeOperationExpr
1144         {
1145                 public CastExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional)
1146                         : base (expr, atomicType, optional)
1147                 {
1148                 }
1149
1150 #region CompileAndEvaluate
1151                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1152                 {
1153                         Expr = Expr.Compile (compiler);
1154                         // FIXME: check return type and if it never matches then return boolean
1155                         return this;
1156                 }
1157
1158                 public override SequenceType StaticType {
1159                         get { return TargetType; }
1160                 }
1161
1162                 public override XPathSequence Evaluate (XPathSequence iter)
1163                 {
1164                         if (TargetType.CanConvert (iter))
1165                                 return new ConvertingIterator (iter, TargetType);
1166                         else
1167                                 throw new XmlQueryException (String.Format ("Cannot cast as {1}", TargetType));
1168                 }
1169 #endregion
1170         }
1171
1172         // ComparisonExpr
1173
1174         internal class ComparisonExpr : BinaryOperationExpr
1175         {
1176                 public ComparisonExpr (ExprSingle left, ExprSingle right, ComparisonOperator oper)
1177                         : base (left, right)
1178                 {
1179                         this.oper = oper;
1180                 }
1181
1182                 ComparisonOperator oper;
1183
1184                 public ComparisonOperator Operation {
1185                         get { return oper; }
1186                 }
1187
1188 #region CompileAndEvaluate
1189                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1190                 {
1191                         Left = Left.Compile (compiler);
1192                         Right = Right.Compile (compiler);
1193                         // FIXME: check return type and if it never matches then return boolean
1194                         return this;
1195                 }
1196
1197                 public override SequenceType StaticType {
1198                         get { return SequenceType.Boolean; }
1199                 }
1200
1201                 public override XPathSequence Evaluate (XPathSequence iter)
1202                 {
1203                         bool isEmpty;
1204                         bool result = EvaluateAsBoolean (iter, out isEmpty);
1205                         if (isEmpty)
1206                                 return new XPathEmptySequence (iter.Context);
1207                         return new SingleItemIterator (result ? AtomicTrue : AtomicFalse, iter.Context);
1208                 }
1209
1210                 public override bool EvaluateAsBoolean (XPathSequence iter)
1211                 {
1212                         bool isEmpty;
1213                         return EvaluateAsBoolean (iter, out isEmpty);
1214                 }
1215
1216                 private bool EvaluateAsBoolean (XPathSequence iter, out bool isEmpty)
1217                 {
1218                         XPathSequence lseq, rseq;
1219                         isEmpty = false;
1220
1221                         switch (Operation) {
1222                         // FIXME: it is curious but currently gmcs requires full typename.
1223                         case Mono.Xml.XPath2.ComparisonOperator.ValueEQ:
1224                         case Mono.Xml.XPath2.ComparisonOperator.ValueNE:
1225                         case Mono.Xml.XPath2.ComparisonOperator.ValueLT:
1226                         case Mono.Xml.XPath2.ComparisonOperator.ValueLE:
1227                         case Mono.Xml.XPath2.ComparisonOperator.ValueGT:
1228                         case Mono.Xml.XPath2.ComparisonOperator.ValueGE:
1229                                 XPathItem itemVL = ExamineOneItem (Left.Evaluate (iter));
1230                                 XPathItem itemVR = ExamineOneItem (Right.Evaluate (iter));
1231                                 if (itemVL == null || itemVR == null) {
1232                                         isEmpty = true;
1233                                         return false;
1234                                 }
1235                                 return CompareAtomic (itemVL, itemVR);
1236
1237                         case Mono.Xml.XPath2.ComparisonOperator.GeneralEQ:
1238                         case Mono.Xml.XPath2.ComparisonOperator.GeneralNE:
1239                         case Mono.Xml.XPath2.ComparisonOperator.GeneralLT:
1240                         case Mono.Xml.XPath2.ComparisonOperator.GeneralLE:
1241                         case Mono.Xml.XPath2.ComparisonOperator.GeneralGT:
1242                         case Mono.Xml.XPath2.ComparisonOperator.GeneralGE:
1243                                 lseq = Left.Evaluate (iter);
1244                                 rseq = Right.Evaluate (iter);
1245                                 foreach (XPathItem itemGL in lseq) {
1246                                         foreach (XPathItem itemGR in rseq.Clone ()) {
1247                                                 if (CompareAtomic (itemGL, itemGR))
1248                                                         return true;
1249                                         }
1250                                 }
1251                                 return false;
1252
1253                         case Mono.Xml.XPath2.ComparisonOperator.NodeIs:
1254                         case Mono.Xml.XPath2.ComparisonOperator.NodeFWD:
1255                         case Mono.Xml.XPath2.ComparisonOperator.NodeBWD:
1256                                 XPathNavigator lnav = ExamineOneNode (Left.Evaluate (iter));
1257                                 XPathNavigator rnav = ExamineOneNode (Right.Evaluate (iter));
1258                                 if (lnav == null || rnav == null) {
1259                                         isEmpty = true;
1260                                         return false;
1261                                 }
1262                                 switch (Operation) {
1263                                 case Mono.Xml.XPath2.ComparisonOperator.NodeIs:
1264                                         return lnav.IsSamePosition (rnav);
1265                                 case Mono.Xml.XPath2.ComparisonOperator.NodeFWD:
1266                                         return lnav.ComparePosition (rnav) == XmlNodeOrder.Before;
1267                                 case Mono.Xml.XPath2.ComparisonOperator.NodeBWD:
1268                                         return lnav.ComparePosition (rnav) == XmlNodeOrder.After;
1269                                 }
1270                                 break;
1271                         }
1272                         throw new SystemException ("XQuery internal error: should not happen.");
1273                 }
1274
1275                 // returns null if sequence was empty
1276                 private XPathItem ExamineOneItem (XPathSequence seq)
1277                 {
1278                         if (!seq.MoveNext ())
1279                                 return null;
1280                         XPathItem item = seq.Current;
1281                         if (seq.MoveNext ())
1282                                 throw new XmlQueryException ("Operand of value comparison expression must be evaluated as a sequence that contains exactly one item.");
1283                         return item;
1284                 }
1285
1286                 // returns null if sequence was empty
1287                 private XPathNavigator ExamineOneNode (XPathSequence seq)
1288                 {
1289                         if (!seq.MoveNext ())
1290                                 return null;
1291                         XPathNavigator nav = seq.Current as XPathNavigator;
1292                         if (nav == null || seq.MoveNext ())
1293                                 throw new XmlQueryException ("Operand of node comparison expression must be evaluated as a sequence that contains exactly one node.");
1294                         return nav;
1295                 }
1296
1297                 private bool CompareAtomic (XPathItem itemL, XPathItem itemR)
1298                 {
1299                         XmlSchemaSimpleType ua = XmlSchemaSimpleType.XdtUntypedAtomic;
1300                         XmlSchemaSimpleType str = XmlSchemaSimpleType.XsString;
1301                         // FIXME: XPathNavigator might be complex content.
1302                         bool uaL = itemL.XmlType == null || itemL.XmlType == ua;
1303                         bool uaR = itemR.XmlType == null || itemR.XmlType == ua;
1304                         bool bothUA = uaL && uaR;
1305                         XPathAtomicValue avL =
1306                                 (uaL) ?
1307                                 bothUA ? new XPathAtomicValue (itemL.Value, str) :
1308                                 new XPathAtomicValue (itemL.Value, itemR.XmlType) :
1309                                 Atomize (itemL);
1310                         XPathAtomicValue avR =
1311                                 uaR ?
1312                                 bothUA ? new XPathAtomicValue (itemR.Value, str) :
1313                                 new XPathAtomicValue (itemR.Value, itemL.XmlType) :
1314                                 Atomize (itemR);
1315
1316                         switch (Operation) {
1317                         // FIXME: it is curious but currently gmcs requires full typename.
1318                         case Mono.Xml.XPath2.ComparisonOperator.ValueEQ:
1319                         case Mono.Xml.XPath2.ComparisonOperator.GeneralEQ:
1320                                 return XQueryComparisonOperator.ValueEQ (avL, avR);
1321                         case Mono.Xml.XPath2.ComparisonOperator.ValueNE:
1322                         case Mono.Xml.XPath2.ComparisonOperator.GeneralNE:
1323                                 return XQueryComparisonOperator.ValueNE (avL, avR);
1324                         case Mono.Xml.XPath2.ComparisonOperator.ValueLT:
1325                         case Mono.Xml.XPath2.ComparisonOperator.GeneralLT:
1326                                 return XQueryComparisonOperator.ValueLT (avL, avR);
1327                         case Mono.Xml.XPath2.ComparisonOperator.ValueLE:
1328                         case Mono.Xml.XPath2.ComparisonOperator.GeneralLE:
1329                                 return XQueryComparisonOperator.ValueLE (avL, avR);
1330                         case Mono.Xml.XPath2.ComparisonOperator.ValueGT:
1331                         case Mono.Xml.XPath2.ComparisonOperator.GeneralGT:
1332                                 return XQueryComparisonOperator.ValueGT (avL, avR);
1333                         case Mono.Xml.XPath2.ComparisonOperator.ValueGE:
1334                         case Mono.Xml.XPath2.ComparisonOperator.GeneralGE:
1335                                 return  XQueryComparisonOperator.ValueGE (avL, avR);
1336                         }
1337                         return false; // should not happen
1338                 }
1339 #endregion
1340         }
1341
1342         public enum ComparisonOperator {
1343                 ValueEQ,
1344                 ValueNE,
1345                 ValueLT,
1346                 ValueLE,
1347                 ValueGT,
1348                 ValueGE,
1349                 GeneralEQ,
1350                 GeneralNE,
1351                 GeneralLT,
1352                 GeneralLE,
1353                 GeneralGT,
1354                 GeneralGE,
1355                 NodeIs,
1356                 NodeFWD,
1357                 NodeBWD
1358         }
1359
1360         // Range
1361
1362         internal class RangeExpr : BinaryOperationExpr
1363         {
1364                 public RangeExpr (ExprSingle left, ExprSingle right)
1365                         : base (left, right)
1366                 {
1367                 }
1368
1369 #region CompileAndEvaluate
1370                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1371                 {
1372                         Left = Left.Compile (compiler);
1373                         Right = Right.Compile (compiler);
1374                         return this;
1375                 }
1376
1377                 public override SequenceType StaticType {
1378                         get { return SequenceType.IntegerList; }
1379                 }
1380
1381                 public override XPathSequence Evaluate (XPathSequence iter)
1382                 {
1383                         int start = Left.EvaluateAsInt (iter);
1384                         int end = Right.EvaluateAsInt (iter);
1385                         return new IntegerRangeIterator (iter.Context, start, end);
1386                 }
1387
1388                 public override void Serialize (XPathSequence iter)
1389                 {
1390                         int start = Left.EvaluateAsInt (iter);
1391                         int end = Right.EvaluateAsInt (iter);
1392                         for (int i = start; i <= end; i++) {
1393                                 iter.Context.Writer.WriteValue (i);
1394                                 if (i < end)
1395                                         iter.Context.Writer.WriteWhitespace (" ");
1396                         }
1397                 }
1398 #endregion
1399         }
1400
1401         // arithmetic operation expr
1402
1403         public enum ArithmeticOperator {
1404                 Add,
1405                 Sub,
1406                 Mul,
1407                 Div,
1408                 IDiv,
1409                 IMod
1410         }
1411
1412         internal class ArithmeticOperationExpr : BinaryOperationExpr
1413         {
1414                 public ArithmeticOperationExpr (ExprSingle left, ExprSingle right, ArithmeticOperator oper)
1415                         : base (left, right)
1416                 {
1417                         this.oper = oper;
1418                 }
1419
1420                 ArithmeticOperator oper;
1421
1422                 public ArithmeticOperator Operation {
1423                         get { return oper; }
1424                 }
1425
1426 #region CompileAndEvaluate
1427                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1428                 {
1429                         Left = Left.Compile (compiler);
1430                         Right = Right.Compile (compiler);
1431                         return this;
1432                 }
1433
1434                 // FIXME: It can be optimized by comparing l/r value types.
1435                 public override SequenceType StaticType {
1436                         get { return SequenceType.AnyType; }
1437                 }
1438
1439                 public override XPathSequence Evaluate (XPathSequence iter)
1440                 {
1441                         XPathSequence lseq = Left.Evaluate (iter);
1442                         if (!lseq.MoveNext ())
1443                                 return new XPathEmptySequence (iter.Context);
1444                         XPathSequence rseq = Right.Evaluate (iter);
1445                         if (!rseq.MoveNext ())
1446                                 return new XPathEmptySequence (iter.Context);
1447                         XPathAtomicValue lvalue = Atomize (lseq.Current);
1448                         XPathAtomicValue rvalue = Atomize (rseq.Current);
1449                         if (lseq.MoveNext ())
1450                                 throw new XmlQueryException ("XP0006: Left operand resulted in an sequence that contains more than one item.");
1451                         if (rseq.MoveNext ())
1452                                 throw new XmlQueryException ("XP0006: Left operand resulted in an sequence that contains more than one item.");
1453
1454                         // FIXME: handle "untypedAtomic to xs:double" casting
1455
1456                         return new SingleItemIterator (Compute (lvalue, rvalue), iter.Context);
1457                 }
1458
1459                 private XPathAtomicValue Compute (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
1460                 {
1461                         switch (Operation) {
1462                         case ArithmeticOperator.Add:
1463                                 return XQueryArithmeticOperator.Add (lvalue, rvalue);
1464                         case ArithmeticOperator.Sub:
1465                                 return XQueryArithmeticOperator.Subtract (lvalue, rvalue);
1466                         case ArithmeticOperator.Mul:
1467                                 return XQueryArithmeticOperator.Multiply (lvalue, rvalue);
1468                         case ArithmeticOperator.Div:
1469                                 return XQueryArithmeticOperator.Divide (lvalue, rvalue);
1470                         case ArithmeticOperator.IDiv:
1471                                 return XQueryArithmeticOperator.IntDivide (lvalue, rvalue);
1472                         case ArithmeticOperator.IMod:
1473                                 return XQueryArithmeticOperator.Remainder (lvalue, rvalue);
1474                         default:
1475                                 throw new SystemException ("XQuery internal error: should not happen.");
1476                         }
1477                 }
1478 #endregion
1479         }
1480
1481         internal class MinusExpr : ExprSingle
1482         {
1483                 public MinusExpr (ExprSingle expr)
1484                 {
1485                         this.expr = expr;
1486                 }
1487
1488                 ExprSingle expr;
1489
1490                 public ExprSingle Expr {
1491                         get { return expr; }
1492                         set { expr = value; }
1493                 }
1494
1495                 internal override void CheckReference (XQueryASTCompiler compiler)
1496                 {
1497                         expr.CheckReference (compiler);
1498                 }
1499
1500 #region CompileAndEvaluate
1501                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1502                 {
1503                         return new ArithmeticOperationExpr (new DecimalLiteralExpr (-1), Expr, ArithmeticOperator.Mul).Compile (compiler);
1504                 }
1505
1506                 public override SequenceType StaticType {
1507                         get { return Expr.StaticType; }
1508                 }
1509
1510                 public override XPathSequence Evaluate (XPathSequence iter)
1511                 {
1512                         throw new SystemException ("XQuery internal error: should not happen.");
1513                 }
1514 #endregion
1515         }
1516
1517         // aggregation expr
1518
1519         public enum AggregationType {
1520                 Union,
1521                 Intersect,
1522                 Except
1523         }
1524
1525         internal class GroupExpr : BinaryOperationExpr
1526         {
1527                 public GroupExpr (ExprSingle left, ExprSingle right, AggregationType aggrType)
1528                         : base (left, right)
1529                 {
1530                         this.aggrType = aggrType;
1531                 }
1532
1533                 AggregationType aggrType;
1534
1535                 public AggregationType AggregationType {
1536                         get { return aggrType; }
1537                 }
1538
1539 #region CompileAndEvaluate
1540                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1541                 {
1542                         Left = Left.Compile (compiler);
1543                         Right = Right.Compile (compiler);
1544                         return this;
1545                 }
1546
1547                 // FIXME: It can be optimized by comparing l/r value types.
1548                 public override SequenceType StaticType {
1549                         get { return SequenceType.AnyType; }
1550                 }
1551
1552                 // only applicable against node-sets
1553                 public override XPathSequence Evaluate (XPathSequence iter)
1554                 {
1555                         return new GroupIterator (iter, this);
1556                 }
1557 #endregion
1558         }
1559
1560         // validate expr
1561
1562         internal class ValidateExpr : ExprSingle
1563         {
1564                 XmlSchemaContentProcessing schemaMode;
1565                 ExprSequence expr;
1566
1567                 public ValidateExpr (XmlSchemaContentProcessing schemaMode, ExprSequence expr)
1568                 {
1569                         this.schemaMode = schemaMode;
1570                         this.expr = expr;
1571                 }
1572
1573                 public ExprSequence Expr {
1574                         get { return expr; }
1575                 }
1576
1577                 public XmlSchemaContentProcessing SchemaMode {
1578                         get { return schemaMode; }
1579                 }
1580
1581                 internal override void CheckReference (XQueryASTCompiler compiler)
1582                 {
1583                         expr.CheckReference (compiler);
1584                 }
1585
1586 #region CompileAndEvaluate
1587                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1588                 {
1589                         for (int i = 0; i < expr.Count; i++)
1590                                 expr [i] = expr [i].Compile (compiler);
1591                         return this;
1592                 }
1593
1594                 public override SequenceType StaticType {
1595                         get { return SequenceType.AnyType; }
1596                 }
1597
1598                 public override XPathSequence Evaluate (XPathSequence iter)
1599                 {
1600                         // TBD (see 3.13).
1601                         throw new NotImplementedException ();
1602                 }
1603 #endregion
1604         }
1605
1606         // Path expr
1607
1608         internal abstract class PathExpr : ExprSingle
1609         {
1610         }
1611
1612         // '/'
1613         internal class PathRootExpr : PathExpr
1614         {
1615                 public PathRootExpr ()
1616                 {
1617                 }
1618
1619                 internal override void CheckReference (XQueryASTCompiler compiler)
1620                 {
1621                 }
1622
1623 #region CompileAndEvaluate
1624                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1625                 {
1626                         return this;
1627                 }
1628
1629                 public override SequenceType StaticType {
1630                         get { return SequenceType.Document; }
1631                 }
1632
1633                 public override XPathSequence Evaluate (XPathSequence iter)
1634                 {
1635                         XPathNavigator nav = iter.Context.CurrentItem as XPathNavigator;
1636                         if (nav == null)
1637                                 throw new XmlQueryException ("Context item is not a node when evaluating expression '/'.");
1638                         nav = nav.Clone ();
1639                         nav.MoveToRoot ();
1640                         return new SingleItemIterator (nav, iter.Context);
1641                 }
1642 #endregion
1643         }
1644
1645         internal abstract class PathStepExpr : PathExpr
1646         {
1647                 ExprSingle first;
1648                 ExprSingle next;
1649
1650                 public PathStepExpr (ExprSingle first, ExprSingle next)
1651                 {
1652                         this.first = first;
1653                         this.next = next;
1654                 }
1655
1656                 public ExprSingle First {
1657                         get { return first; }
1658                         set { first = value; }
1659                 }
1660
1661                 public ExprSingle Next {
1662                         get { return next; }
1663                         set { next = value; }
1664                 }
1665
1666                 internal override void CheckReference (XQueryASTCompiler compiler)
1667                 {
1668                         first.CheckReference (compiler);
1669                         next.CheckReference (compiler);
1670                 }
1671
1672                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1673                 {
1674                         first = first.Compile (compiler);
1675                         next = next.Compile (compiler);
1676                         return this;
1677                 }
1678
1679         }
1680
1681         // 'foo/bar'
1682         internal class PathSlashExpr : PathStepExpr
1683         {
1684                 public PathSlashExpr (ExprSingle first, ExprSingle next)
1685                         : base (first, next)
1686                 {
1687                 }
1688
1689 #region CompileAndEvaluate
1690                 // FIXME: It can be optimized by comparing l/r value types.
1691                 public override SequenceType StaticType {
1692                         get { return SequenceType.Node; }
1693                 }
1694
1695                 public override XPathSequence Evaluate (XPathSequence iter)
1696                 {
1697                         return new PathStepIterator (First.Evaluate (iter), this);
1698                 }
1699 #endregion
1700         }
1701
1702         // 'foo//bar'
1703         internal class PathSlash2Expr : PathStepExpr
1704         {
1705                 public PathSlash2Expr (ExprSingle first, ExprSingle next)
1706                         : base (first, next)
1707                 {
1708                 }
1709
1710 #region CompileAndEvaluate
1711                 // FIXME: It can be optimized by comparing l/r value types.
1712                 public override SequenceType StaticType {
1713                         get { return SequenceType.Node; }
1714                 }
1715
1716                 public override XPathSequence Evaluate (XPathSequence iter)
1717                 {
1718                         XPathSequence seq = First.Evaluate (iter);
1719                         if (!seq.MoveNext ())
1720                                 return new XPathEmptySequence (iter.Context);
1721                         return new PathStepIterator (
1722                                 new DescendantOrSelfIterator (seq.Current as XPathNavigator, seq.Context), this);
1723                 }
1724 #endregion
1725         }
1726
1727         internal class AxisStepExpr : PathExpr
1728         {
1729                 public AxisStepExpr (XPathAxis axis, XPath2NodeTest test)
1730                 {
1731                         this.axis = axis;
1732                         if (test == null)
1733                                 nameTest = XmlQualifiedName.Empty;
1734                         else {
1735                                 if (test.NameTest != null)
1736                                         this.nameTest = test.NameTest;
1737                                 else
1738                                         this.kindTest = test.KindTest;
1739                         }
1740                 }
1741
1742                 XPathAxis axis;
1743                 XmlQualifiedName nameTest;
1744                 KindTest kindTest;
1745
1746                 public XPathAxis Axis {
1747                         get { return axis; }
1748                 }
1749
1750                 public XmlQualifiedName NameTest {
1751                         get { return nameTest; }
1752                         set { nameTest = value; }
1753                 }
1754
1755                 public KindTest KindTest {
1756                         get { return kindTest; }
1757                         set { kindTest = value; }
1758                 }
1759
1760                 internal override void CheckReference (XQueryASTCompiler compiler)
1761                 {
1762                         if (KindTest != null)
1763                                 KindTest.CheckReference (compiler);
1764                 }
1765
1766 #region CompileAndEvaluate
1767                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1768                 {
1769                         if (KindTest != null)
1770                                 KindTest.Compile (compiler);
1771                         return this;
1772                 }
1773
1774                 public override SequenceType StaticType {
1775                         get {
1776                                 switch (Axis.AxisType) {
1777                                 case XPathAxisType.Attribute:
1778                                         return SequenceType.Attribute;
1779                                 case XPathAxisType.Namespace:
1780                                         return SequenceType.Namespace;
1781                                 }
1782                                 // FIXME: we can more filtering by KindTest
1783                                 return SequenceType.Node;
1784                         }
1785                 }
1786
1787                 public override XPathSequence Evaluate (XPathSequence iter)
1788                 {
1789                         XQueryContext ctx = iter.Context;
1790
1791                         if (iter.Position == 0) {
1792                                 iter = iter.Clone ();
1793                                 if (!iter.MoveNext ())
1794                                         return new XPathEmptySequence (iter.Context);
1795                         }
1796
1797                         XPathNavigator nav = iter.Current as XPathNavigator;
1798                         if (nav == null)
1799                                 throw new XmlQueryException ("Node set is expected.");
1800
1801                         NodeIterator argIter = null;
1802
1803                         switch (Axis.AxisType) {
1804                         case XPathAxisType.Child:
1805                                 argIter = new ChildIterator (nav, ctx); break;
1806                         case XPathAxisType.Descendant:
1807                                 argIter = new DescendantIterator (nav, ctx); break;
1808                         case XPathAxisType.Attribute:
1809                                 argIter = new AttributeIterator (nav, ctx); break;
1810                         case XPathAxisType.Self:
1811                                 argIter = new SelfIterator (nav, ctx); break;
1812                         case XPathAxisType.DescendantOrSelf:
1813                                 argIter = new DescendantOrSelfIterator (nav, ctx); break;
1814                         case XPathAxisType.FollowingSibling:
1815                                 argIter = new FollowingSiblingIterator (nav, ctx); break;
1816                         case XPathAxisType.Following:
1817                                 argIter = new FollowingIterator (nav, ctx); break;
1818                         case XPathAxisType.Parent:
1819                                 argIter = new ParentIterator (nav, ctx); break;
1820                         case XPathAxisType.Ancestor:
1821                                 argIter = new AncestorIterator (nav, ctx); break;
1822                         case XPathAxisType.PrecedingSibling:
1823                                 argIter = new PrecedingSiblingIterator (nav, ctx); break;
1824                         case XPathAxisType.Preceding:
1825                                 argIter = new PrecedingIterator (nav, ctx); break;
1826                         case XPathAxisType.AncestorOrSelf:
1827                                 argIter = new AncestorOrSelfIterator (nav, ctx); break;
1828                         case XPathAxisType.Namespace: // only applicable under XPath 2.0: not XQuery 1.0
1829                                 argIter = new NamespaceIterator (nav, ctx); break;
1830                         }
1831                         return new AxisIterator (argIter, this);
1832                 }
1833
1834                 internal bool Matches (XPathNavigator nav)
1835                 {
1836                         if (nameTest != null)
1837                                 return nameTest == XmlQualifiedName.Empty || 
1838                                         ((nameTest.Name == nav.LocalName || nameTest.Name == "*") &&
1839                                         (nameTest.Namespace == nav.NamespaceURI || nameTest.Namespace == "*"));
1840                         else
1841                                 return kindTest.Matches (nav);
1842                 }
1843 #endregion
1844         }
1845
1846         internal class FilterStepExpr : PathExpr
1847         {
1848                 public FilterStepExpr (ExprSingle expr, ExprSequence predicate)
1849                 {
1850                         this.expr = expr;
1851                         this.predicate = predicate;
1852                 }
1853
1854                 ExprSingle expr;
1855                 ExprSequence predicate;
1856
1857                 public ExprSingle Expr {
1858                         get { return expr; }
1859                         set { expr = value; }
1860                 }
1861
1862                 public ExprSequence Predicate {
1863                         get { return predicate; }
1864                 }
1865
1866                 internal override void CheckReference (XQueryASTCompiler compiler)
1867                 {
1868                         expr.CheckReference (compiler);
1869                         predicate.CheckReference (compiler);
1870                 }
1871
1872 #region CompileAndEvaluate
1873                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1874                 {
1875                         Expr = Expr.Compile (compiler);
1876                         for (int i = 0; i < predicate.Count; i++)
1877                                 predicate [i] = predicate [i].Compile (compiler);
1878                         return this;
1879                 }
1880
1881                 public override SequenceType StaticType {
1882                         get { return Expr.StaticType; }
1883                 }
1884
1885                 public override XPathSequence Evaluate (XPathSequence iter)
1886                 {
1887                         return new FilteredIterator (iter, this);
1888                 }
1889 #endregion
1890         }
1891
1892 /*
1893         // predicates == exprsequence list == list of list of exprsingle
1894         internal class PredicateList : CollectionBase
1895         {
1896                 public void Add (ExprSequence expr)
1897                 {
1898                         List.Add (expr);
1899                 }
1900
1901                 public void Insert (int pos, ExprSequence expr)
1902                 {
1903                         List.Insert (pos, expr);
1904                 }
1905
1906                 public ExprSequence this [int i] {
1907                         get { return (ExprSequence) List [i]; }
1908                 }
1909         }
1910 */
1911
1912         internal class XPath2NodeTest
1913         {
1914                 public XPath2NodeTest (XmlQualifiedName nameTest)
1915                 {
1916                         this.NameTest = nameTest;
1917                 }
1918                 
1919                 public XPath2NodeTest (KindTest kindTest)
1920                 {
1921                         this.KindTest = kindTest;
1922                 }
1923
1924                 public XmlQualifiedName NameTest;
1925
1926                 public KindTest KindTest;
1927         }
1928
1929         internal class EnclosedExpr : ExprSingle
1930         {
1931                 ExprSequence expr;
1932
1933                 public EnclosedExpr (ExprSequence expr)
1934                 {
1935                         this.expr = expr;
1936                 }
1937
1938                 public ExprSequence Expr {
1939                         get { return expr; }
1940                 }
1941
1942                 internal override void CheckReference (XQueryASTCompiler compiler)
1943                 {
1944                         expr.CheckReference (compiler);
1945                 }
1946
1947 #region CompileAndEvaluate
1948                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1949                 {
1950                         if (Expr.Count == 1)
1951                                 return Expr [0].Compile (compiler);
1952                         for (int i = 0; i < Expr.Count; i++)
1953                                 Expr [i] = Expr [i].Compile (compiler);
1954                         return this;
1955                 }
1956
1957                 // FIXME: can be optimized by checking all items in Expr
1958                 public override SequenceType StaticType {
1959                         get { return SequenceType.AnyType; }
1960                 }
1961
1962                 public override XPathSequence Evaluate (XPathSequence iter)
1963                 {
1964                         return new ExprSequenceIterator (iter, Expr);
1965                 }
1966 #endregion
1967         }
1968
1969         // PrimaryExpr
1970
1971         internal abstract class PrimaryExpr : ExprSingle
1972         {
1973                 internal override void CheckReference (XQueryASTCompiler compiler)
1974                 {
1975                 }
1976
1977 #region CompileAndEvaluate
1978                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1979                 {
1980                         return this;
1981                 }
1982
1983                 public override XPathSequence Evaluate (XPathSequence iter)
1984                 {
1985                         return new SingleItemIterator (EvaluateAsAtomic (iter), iter.Context);
1986                 }
1987 #endregion
1988         }
1989
1990         internal class StringLiteralExpr : PrimaryExpr
1991         {
1992                 string literal;
1993
1994                 public StringLiteralExpr (string literal)
1995                 {
1996                         this.literal = literal;
1997                 }
1998
1999                 public string Literal {
2000                         get { return literal; }
2001                 }
2002
2003 #region CompileAndEvaluate
2004                 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("string", XmlSchema.Namespace));
2005
2006                 public override SequenceType StaticType {
2007                         get { return SequenceType.AtomicString; }
2008                 }
2009
2010                 public override string EvaluateAsString (XPathSequence iter)
2011                 {
2012                         return Literal;
2013                 }
2014
2015                 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2016                 {
2017                         return new XPathAtomicValue (Literal, stringType);
2018                 }
2019 #endregion
2020         }
2021
2022         internal class DecimalLiteralExpr : PrimaryExpr
2023         {
2024                 decimal value;
2025
2026                 public DecimalLiteralExpr (decimal value)
2027                 {
2028                         this.value = value;
2029                 }
2030
2031                 public decimal Value {
2032                         get { return value; }
2033                 }
2034
2035 #region CompileAndEvaluate
2036                 XmlSchemaSimpleType decimalType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("decimal", XmlSchema.Namespace));
2037
2038                 public override SequenceType StaticType {
2039                         get { return SequenceType.Decimal; }
2040                 }
2041
2042                 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2043                 {
2044                         return new XPathAtomicValue (Value, decimalType);
2045                 }
2046 #endregion
2047         }
2048
2049         internal class DoubleLiteralExpr : PrimaryExpr
2050         {
2051                 double value;
2052
2053                 public DoubleLiteralExpr (double value)
2054                 {
2055                         this.value = value;
2056                 }
2057
2058                 public double Value {
2059                         get { return value; }
2060                 }
2061
2062 #region CompileAndEvaluate
2063                 XmlSchemaSimpleType doubleType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("double", XmlSchema.Namespace));
2064
2065                 public override SequenceType StaticType {
2066                         get { return SequenceType.Double; }
2067                 }
2068
2069                 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2070                 {
2071                         return new XPathAtomicValue (Value, doubleType);
2072                 }
2073 #endregion
2074         }
2075
2076         internal class VariableReferenceExpr : PrimaryExpr
2077         {
2078                 XmlQualifiedName varName;
2079
2080                 public VariableReferenceExpr (XmlQualifiedName varName)
2081                 {
2082                         this.varName = varName;
2083                 }
2084
2085                 public XmlQualifiedName VariableName {
2086                         get { return varName; }
2087                 }
2088
2089                 // FIXME: variable name must be stacked in any area 
2090                 // whereever variables are defined.
2091                 internal override void CheckReference (XQueryASTCompiler compiler)
2092                 {
2093                         compiler.CheckVariableName (varName);
2094                 }
2095
2096 #region CompileAndEvaluate
2097                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2098                 {
2099                         // FIXME: try to resolve static context variable and return the actual value expression
2100                         return this;
2101                 }
2102
2103                 public override SequenceType StaticType {
2104                         get { return SequenceType.AnyType; }
2105                 }
2106
2107                 public override XPathSequence Evaluate (XPathSequence iter)
2108                 {
2109                         XPathSequence variable = iter.Context.ResolveVariable (VariableName);
2110                         // FIXME: if Evaluate() accepts XPathSequence, then XPathSequence must be public class (to make IXPath2Variable public).
2111                         return variable;
2112                 }
2113 #endregion
2114         }
2115
2116         internal class ParenthesizedExpr : PrimaryExpr
2117         {
2118                 ExprSequence expr;
2119
2120                 public ParenthesizedExpr (ExprSequence expr)
2121                 {
2122                         if (expr == null)
2123                                 expr = new ExprSequence ();
2124                         this.expr = expr;
2125                 }
2126
2127                 ExprSequence Expr {
2128                         get { return expr; }
2129                 }
2130
2131 #region CompileAndEvaluate
2132                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2133                 {
2134                         if (Expr.Count == 1)
2135                                 return Expr [0].Compile (compiler);
2136                         for (int i = 0; i < Expr.Count; i++)
2137                                 Expr [i] = Expr [i].Compile (compiler);
2138                         return this;
2139                 }
2140
2141                 // FIXME: can be optimized by checking all items in Expr
2142                 public override SequenceType StaticType {
2143                         get { return SequenceType.AnyType; }
2144                 }
2145
2146                 public override XPathSequence Evaluate (XPathSequence iter)
2147                 {
2148                         switch (Expr.Count) {
2149                         case 0:
2150                                 return new XPathEmptySequence (iter.Context);
2151                         case 1:
2152                                 return Expr [0].Evaluate (iter);
2153                         default:
2154                                 return new ExprSequenceIterator (iter, Expr);
2155                         }
2156                 }
2157 #endregion
2158         }
2159
2160         // "."
2161         internal class ContextItemExpr : PrimaryExpr
2162         {
2163                 public ContextItemExpr ()
2164                 {
2165                 }
2166
2167 #region CompileAndEvaluate
2168                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2169                 {
2170                         return this;
2171                 }
2172
2173                 public override SequenceType StaticType {
2174                         get { return SequenceType.AnyType; }
2175                 }
2176
2177                 public override XPathSequence Evaluate (XPathSequence iter)
2178                 {
2179                         return new SingleItemIterator (iter.Context.CurrentItem, iter.Context);
2180                 }
2181 #endregion
2182         }
2183
2184         internal abstract class FunctionCallExprBase : PrimaryExpr
2185         {
2186                 XmlQualifiedName name;
2187                 ExprSequence args;
2188
2189                 public FunctionCallExprBase (XmlQualifiedName name, ExprSequence args)
2190                 {
2191                         if (args == null)
2192                                 throw new ArgumentNullException (String.Format ("Function argument expressions for {0} is null.", name));
2193                         this.name = name;
2194                         this.args = args;
2195                 }
2196
2197                 public XmlQualifiedName Name {
2198                         get { return name; }
2199                 }
2200
2201                 public ExprSequence Args {
2202                         get { return args; }
2203                 }
2204
2205                 internal override void CheckReference (XQueryASTCompiler compiler)
2206                 {
2207                         compiler.CheckFunctionName (name);
2208                 }
2209
2210 #region CompileAndEvaluate
2211                 /*
2212                 internal static DefaultFunctionCall Create (
2213                         XmlQualifiedName name,
2214                         ExprSingle [] args,
2215                         XQueryStaticContext ctx)
2216                 {
2217                         switch (name.Namespace) {
2218                         case XQueryFunction.Namespace:
2219                                 switch (name.Name) {
2220                                 case "node-name":
2221                                         return new FnNodeNameCall (ctx, args);
2222                                 case "nilled":
2223                                         return new FnNilledCall (ctx, args);
2224                                 case "string":
2225                                         return new FnStringCall (ctx, args);
2226                                 case "data":
2227                                         return new FnDataCall (ctx, args);
2228                                 case "base-uri":
2229                                         return new FnBaseUriCall (ctx, args);
2230                                 case "document-uri":
2231                                         return new FnDocumentUriCall (ctx, args);
2232                                 case "error":
2233                                         return new FnErrorCall (ctx, args);
2234                                 case "trace":
2235                                         return new FnTraceCall (ctx, args);
2236                                 case "abs":
2237                                         return new FnAbsCall (ctx, args);
2238                                 case "ceiling":
2239                                         return new FnCeilingCall (ctx, args);
2240                                 case "floor":
2241                                         return new FnFloorCall (ctx, args);
2242                                 case "round":
2243                                         return new FnRoundCall (ctx, args);
2244                                 case "round-half-to-even":
2245                                         return new FnRoundHalfToEvenCall (ctx, args);
2246                                 case "codepoints-to-string":
2247                                         return new FnCodepointsToStringCall (ctx, args);
2248                                 case "string-to-codepoints":
2249                                         return new FnStringCallToCodepointsCall (ctx, args);
2250                                 }
2251                                 goto default;
2252                         case XmlSchema.XdtNamespace:
2253                         case XmlSchema.Namespace:
2254                                 XmlSchemaType type = XmlSchemaType.GetBuiltInSimpleType (name);
2255                                 if (type != null)
2256                                         return new AtomicConstructorCall (ctx, SequenceType.Create (type, Occurence.One), args);
2257                                 type = XmlSchemaType.GetBuiltInComplexType (name);
2258                                 if (type == null)
2259                                         goto default;
2260                                 return null;
2261                         default:
2262                                 XQueryFunction func = ctx.CompileContext.InEffectFunctions [name];
2263                                 if (func != null)
2264                                         return new CustomFunctionCallExpression (ctx, args, func);
2265                                 return null;
2266                         }
2267                 }
2268                 */
2269
2270                 internal void CheckArguments (XQueryASTCompiler compiler)
2271                 {
2272                         if (args.Count < MinArgs || args.Count > MaxArgs)
2273                                 // FIXME: add more info
2274                                 throw new XmlQueryCompileException (String.Format ("{0} is invalid for the number of {1} function argument. MinArgs = {2}, MaxArgs = {3}.", args.Count, name, MinArgs, MaxArgs));
2275                 }
2276
2277                 public abstract int MinArgs { get; }
2278                 public abstract int MaxArgs { get; }
2279 #endregion
2280         }
2281
2282         internal class FunctionCallExpr : FunctionCallExprBase
2283         {
2284                 public FunctionCallExpr (XmlQualifiedName name, ExprSequence args)
2285                         : base (name, args)
2286                 {
2287                 }
2288
2289                 XQueryFunction function;
2290
2291                 public XQueryFunction Function {
2292                         get { return function; }
2293                 }
2294
2295 #region CompileAndEvaluate
2296                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2297                 {
2298                         // resolve function
2299                         function = compiler.ResolveFunction (Name);
2300                         CheckArguments (compiler);
2301                         for (int i = 0; i < Args.Count; i++)
2302                                 Args [i] = Args [i].Compile (compiler);
2303                         return this;
2304                 }
2305
2306                 public override int MinArgs {
2307                         get { return function.MinArgs; }
2308                 }
2309
2310                 public override int MaxArgs {
2311                         get { return function.MaxArgs; }
2312                 }
2313
2314                 public override SequenceType StaticType {
2315                         get { return function.ReturnType; }
2316                 }
2317
2318                 public override XPathSequence Evaluate (XPathSequence iter)
2319                 {
2320                         return Function.Evaluate (iter, Args);
2321                 }
2322
2323                 // FIXME: add all overrides that delegates to XQueryFunction
2324 #endregion
2325         }
2326
2327 /*
2328 #region CompileAndEvaluate
2329
2330         // It is instantiated per function call expression.
2331         // (e.g. the example below contains 4 FunctionCallExpression instances:
2332         // "replace(node-name (node-before(/*)), 'foo', node-name($var))"
2333         internal class CustomFunctionCallExpr : FunctionCallExprBase
2334         {
2335                 public CustomFunctionCallExpr (ExprSequence args, XQueryFunction function)
2336                         : base (function.Name, args)
2337                 {
2338                         this.function = function;
2339                 }
2340
2341                 XQueryFunction function;
2342
2343                 public XQueryFunction Function {
2344                         get { return function; }
2345                 }
2346
2347                 public override int MinArgs {
2348                         get { return function.MinArgs; }
2349                 }
2350
2351                 public override int MaxArgs {
2352                         get { return function.MaxArgs; }
2353                 }
2354
2355                 public override SequenceType StaticType {
2356                         get { return function.ReturnType; }
2357                 }
2358
2359                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2360                 {
2361                         CheckArguments (compiler);
2362                         for (int i = 0; i < Args.Count; i++)
2363                                 Args [i] = Args [i].Compile (compiler);
2364                         return this;
2365                 }
2366
2367                 public override XPathSequence Evaluate (XPathSequence iter)
2368                 {
2369                         return Function.Evaluate (iter, Args);
2370                 }
2371
2372                 // FIXME: add all overrides that delegates to XQueryFunction
2373         }
2374 #endregion
2375 */
2376
2377         // Ordered / Unordered
2378         internal class OrderSpecifiedExpr : ExprSingle
2379         {
2380                 bool ordered;
2381                 ExprSequence expr;
2382                 
2383                 public OrderSpecifiedExpr (ExprSequence expr, bool ordered)
2384                 {
2385                         this.ordered = ordered;
2386                         this.expr = expr;
2387                 }
2388
2389                 public ExprSequence Expr {
2390                         get { return expr; }
2391                 }
2392
2393                 public bool Ordered {
2394                         get { return ordered; }
2395                 }
2396
2397                 internal override void CheckReference (XQueryASTCompiler compiler)
2398                 {
2399                         expr.CheckReference (compiler);
2400                 }
2401
2402 #region CompileAndEvaluate
2403                 public override SequenceType StaticType {
2404                         // FIXME: could be optimized by checking all the expressions
2405                         get { return SequenceType.AnyType; }
2406                 }
2407
2408                 public override bool RequireSorting {
2409                         get { return Ordered; }
2410                 }
2411
2412                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2413                 {
2414                         for (int i = 0; i < Expr.Count; i++)
2415                                 Expr [i] = Expr [i].Compile (compiler);
2416                         return this;
2417                 }
2418
2419                 public override XPathSequence Evaluate (XPathSequence iter)
2420                 {
2421                         throw new NotImplementedException ();
2422                 }
2423 #endregion
2424         }
2425 }
2426
2427 #endif