fix typo
[mcs.git] / class / Mono.Xml.Ext / Mono.Xml.XPath2 / XPath2Expression.cs
blobcdcb88e0ea583aac5b4465bcc5b06a6570bd2b9d
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.
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 using Mono.Xml;
40 namespace Mono.Xml.XPath2
42 public class ExprSequence : CollectionBase
44 public ExprSequence ()
48 public void Add (ExprSingle expr)
50 List.Add (expr);
53 public void AddRange (ICollection items)
55 if (items != null)
56 foreach (ExprSingle e in items)
57 List.Add (e);
60 public void Insert (int pos, ExprSingle expr)
62 List.Insert (pos, expr);
65 public ExprSingle this [int i] {
66 get { return List [i] as ExprSingle; }
67 set { List [i] = value; }
70 internal void CheckReference (XQueryASTCompiler compiler)
72 foreach (ExprSingle expr in List)
73 expr.CheckReference (compiler);
77 public abstract partial class ExprSingle
79 internal abstract void CheckReference (XQueryASTCompiler compiler);
81 #region CompileAndEvaluate
82 internal static readonly XPathAtomicValue AtomicTrue = new XPathAtomicValue (true, InternalPool.XsBoolean);
83 internal static readonly XPathAtomicValue AtomicFalse = new XPathAtomicValue (false, InternalPool.XsBoolean);
85 XQueryStaticContext ctx;
87 internal ExprSingle Compile (XQueryASTCompiler compiler)
89 this.ctx = ctx;
90 return CompileCore (compiler);
93 // If internal&&protected is available in C#, it is the best signature.
94 internal abstract ExprSingle CompileCore (XQueryASTCompiler compiler);
96 internal XQueryStaticContext Context {
97 get { return ctx; }
100 public abstract SequenceType StaticType { get; }
102 /** <summary>
103 This is the core part of ExprSingle. It is
104 generally used to evaluate expression and returns
105 XPathItem sequence (iterator). The result is unordered
107 public abstract XPathSequence Evaluate (XPathSequence iter);
109 public virtual XPathSequence EvaluateOrdered (XPathSequence iter)
111 if (RequireSorting) {
112 ArrayList al = new ArrayList ();
113 foreach (XPathItem item in Evaluate (iter))
114 al.Add (item);
115 return new ListIterator (iter.Context, al);
117 else
118 return Evaluate (iter);
121 public virtual void Serialize (XPathSequence iter)
123 XmlWriter w = iter.Context.Writer;
124 XPathSequence result = Evaluate (iter);
125 bool initial = true;
126 foreach (XPathItem item in result) {
127 if (initial)
128 initial = false;
129 else
130 w.WriteWhitespace (" ");
131 WriteXPathItem (item, w);
135 private void WriteXPathItem (XPathItem item, XmlWriter w)
137 if (item.IsNode) {
138 XPathNavigator nav = item as XPathNavigator;
139 if (w.WriteState != WriteState.Start && nav.NodeType == XPathNodeType.Root)
140 throw new XmlQueryException ("Current output can not accept root node.");
141 if (w.WriteState == WriteState.Attribute)
142 w.WriteString (nav.Value);
143 else
144 w.WriteNode (nav, false);
145 } else
146 w.WriteString (item.Value);
149 // get EBV (fn:boolean())
150 public virtual bool EvaluateAsBoolean (XPathSequence iter)
152 XPathSequence result = Evaluate (iter);
153 if (!result.MoveNext ())
154 return false;
155 XPathItem v = result.Current;
156 if (v is XPathNavigator)
157 return true;
158 if (result.MoveNext ())
159 return true;
160 switch (v.XmlType.TypeCode) {
161 case XmlTypeCode.Boolean:
162 return v.ValueAsBoolean;
163 case XmlTypeCode.String:
164 case XmlTypeCode.UntypedAtomic:
165 return v.Value != String.Empty;
166 case XmlTypeCode.Float:
167 return v.ValueAsSingle != Single.NaN && v.ValueAsSingle != 0.0;
168 case XmlTypeCode.Double:
169 return v.ValueAsDouble != Double.NaN && v.ValueAsSingle != 0.0;
170 case XmlTypeCode.Decimal:
171 return v.ValueAsDecimal != 0;
172 case XmlTypeCode.Integer:
173 case XmlTypeCode.NonPositiveInteger:
174 case XmlTypeCode.NegativeInteger:
175 case XmlTypeCode.Long:
176 case XmlTypeCode.Int:
177 case XmlTypeCode.Short:
178 case XmlTypeCode.Byte:
179 case XmlTypeCode.UnsignedInt:
180 case XmlTypeCode.UnsignedShort:
181 case XmlTypeCode.UnsignedByte:
182 return v.ValueAsInt64 != 0;
183 case XmlTypeCode.NonNegativeInteger:
184 case XmlTypeCode.UnsignedLong:
185 case XmlTypeCode.PositiveInteger:
186 return (ulong) (v.ValueAs (typeof (ulong))) != 0;
188 // otherwise, return true
189 return true;
192 public virtual int EvaluateAsInt (XPathSequence iter)
194 XPathAtomicValue v = Atomize (Evaluate (iter));
195 return v != null ? v.ValueAsInt32 : 0;
198 public virtual string EvaluateAsString (XPathSequence iter)
200 XPathAtomicValue v = Atomize (Evaluate (iter));
201 return v != null ? v.Value : String.Empty;
204 public static XPathAtomicValue Atomize (XPathItem item)
206 XPathNavigator nav = item as XPathNavigator;
207 if (nav != null) {
208 if (nav.SchemaInfo != null) {
209 XmlSchemaType type = nav.SchemaInfo.SchemaType;
210 XmlSchemaComplexType ct = type as XmlSchemaComplexType;
211 if (ct != null && ct.ContentType == XmlSchemaContentType.ElementOnly)
212 throw new XmlQueryException ("An attempt to get atomized value against element-only node happend.");
213 switch (type.TypeCode) {
214 case XmlTypeCode.Item:
215 // case XmlTypeCode.Untyped:
216 type = XmlSchemaType.GetBuiltInSimpleType (XmlTypeCode.UntypedAtomic);
217 break;
219 return new XPathAtomicValue (nav.TypedValue, type);
221 else
222 return new XPathAtomicValue (nav.Value, InternalPool.XdtUntypedAtomic);
224 else
225 return (XPathAtomicValue) item;
228 // FIXME: What if iter contains list value?
229 public static XPathAtomicValue Atomize (XPathSequence iter)
231 if (!iter.MoveNext ())
232 return null;
233 XPathNavigator nav = iter.Current as XPathNavigator;
234 if (nav != null) {
235 // FIXME: is it really always untypedAtomic?
236 // It might be complex content.
237 XmlSchemaType type = nav.SchemaInfo == null ? InternalPool.XdtUntypedAtomic : nav.SchemaInfo.SchemaType;
238 return new XPathAtomicValue (nav.TypedValue, type);
240 else
241 return (XPathAtomicValue) iter.Current;
244 public virtual XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
246 return Atomize (Evaluate (iter));
249 public virtual bool RequireSorting {
250 get { return false; }
252 #endregion
255 // FLWORExpr
257 internal partial class FLWORExpr : ExprSingle
259 public FLWORExpr (ForLetClauseCollection forlet, ExprSequence whereClause, OrderSpecList orderBy, ExprSingle ret)
261 this.fl = forlet;
262 if (whereClause != null)
263 this.whereClause = new ParenthesizedExpr (whereClause);
264 this.orderBy = orderBy;
265 this.ret = ret;
268 ForLetClauseCollection fl;
269 ExprSingle whereClause;
270 OrderSpecList orderBy;
271 ExprSingle ret;
273 public ForLetClauseCollection ForLetClauses {
274 get { return fl; }
277 public ExprSingle WhereClause {
278 get { return whereClause; }
281 public OrderSpecList OrderBy {
282 get { return orderBy; }
285 public ExprSingle ReturnExpr {
286 get { return ret; }
287 set { ret = value; }
290 // ExprSingle Overrides
292 internal override void CheckReference (XQueryASTCompiler compiler)
294 foreach (ForLetClause flc in fl)
295 foreach (ForLetSingleBody single in flc)
296 single.CheckReference (compiler);
297 if (whereClause != null)
298 whereClause.CheckReference (compiler);
299 if (orderBy != null)
300 foreach (OrderSpec os in orderBy)
301 os.Expression.CheckReference (compiler);
302 ret.CheckReference (compiler);
305 #region CompileAndEvaluate
306 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
308 foreach (ForLetClause flc in ForLetClauses) {
309 foreach (ForLetSingleBody flsb in flc) {
310 flsb.Expression = flsb.Expression.Compile (compiler);
311 if (flsb.ReturnType != null)
312 compiler.CheckType (flsb.Expression, flsb.ReturnType);
315 if (WhereClause != null)
316 whereClause = whereClause.Compile (compiler);
317 if (OrderBy != null)
318 foreach (OrderSpec os in OrderBy)
319 os.Expression = os.Expression.Compile (compiler);
320 ReturnExpr = ReturnExpr.Compile (compiler);
322 return this;
325 public override SequenceType StaticType {
326 get { return ReturnExpr.StaticType; }
329 public override XPathSequence Evaluate (XPathSequence iter)
331 return new FLWORIterator (iter, this);
333 #endregion
336 internal class ForLetClauseCollection : CollectionBase
338 public void Add (ForLetClause clause)
340 List.Add (clause);
343 public void Insert (int pos, ForLetClause clause)
345 List.Insert (pos, clause);
348 public ForLetClause this [int i] {
349 get { return (ForLetClause) List [i]; }
353 internal class OrderSpecList : CollectionBase
355 bool isStable;
357 public OrderSpecList ()
361 public bool IsStable {
362 get { return isStable; }
363 set { isStable = value; }
366 public void Insert (int pos, OrderSpec os)
368 List.Insert (pos, os);
371 public void Add (OrderSpec spec)
373 List.Add (spec);
376 public OrderSpec this [int i] {
377 get { return (OrderSpec) List [i]; }
381 internal class OrderSpec
383 public OrderSpec (ExprSingle expr, OrderModifier modifier)
385 this.expr = expr;
386 this.mod = modifier;
389 ExprSingle expr;
390 OrderModifier mod;
392 public ExprSingle Expression {
393 get {return expr; }
394 set { expr = value; }
397 public OrderModifier Modifier {
398 get { return mod; }
399 set { mod = value; }
403 internal class OrderModifier
405 public OrderModifier (XmlSortOrder order, XmlSortOrder emptyOrder, string collation)
407 this.sortOrder = sortOrder;
408 this.emptyOrder = emptyOrder;
409 if (collation != null)
410 this.coll = new CultureInfo (collation);
413 XmlSortOrder sortOrder;
414 XmlSortOrder emptyOrder;
415 CultureInfo coll;
417 public XmlSortOrder SortOrder {
418 get { return sortOrder; }
421 public XmlSortOrder EmptyOrder {
422 get { return emptyOrder; }
425 public CultureInfo Collation {
426 get { return coll; }
430 internal class ForLetClause : CollectionBase
432 public ForLetSingleBody this [int i] {
433 get { return (ForLetSingleBody) List [i]; }
437 internal class ForClause : ForLetClause
439 public ForClause ()
443 public void Insert (int pos, ForSingleBody body)
445 List.Insert (pos, body);
448 public void Add (ForSingleBody body)
450 List.Add (body);
454 internal class LetClause : ForLetClause
456 public LetClause ()
460 public void Insert (int pos, LetSingleBody body)
462 List.Insert (pos, body);
465 public void Add (LetSingleBody body)
467 List.Add (body);
471 internal abstract class ForLetSingleBody
473 XmlQualifiedName varName;
474 SequenceType type;
475 ExprSingle expr;
477 public ForLetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr)
479 this.varName = varName;
480 this.type = type;
481 this.expr = expr;
484 public XmlQualifiedName VarName {
485 get { return varName; }
488 public SequenceType ReturnType {
489 get { return type; }
492 public ExprSingle Expression {
493 get { return expr; }
494 set { expr = value; }
497 internal void CheckReference (XQueryASTCompiler compiler)
499 if (type != null)
500 compiler.CheckSchemaType (type);
501 expr.CheckReference (compiler);
505 internal class ForSingleBody : ForLetSingleBody
507 public ForSingleBody (XmlQualifiedName varName, SequenceType type, XmlQualifiedName positionalVar, ExprSingle expr)
508 : base (varName, type, expr)
510 this.positionalVar = positionalVar;
513 XmlQualifiedName positionalVar;
515 public XmlQualifiedName PositionalVar {
516 get { return positionalVar; }
520 internal class LetSingleBody : ForLetSingleBody
522 public LetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr)
523 : base (varName, type, expr)
528 // QuantifiedExpr
530 internal class QuantifiedExpr : ExprSingle
532 QuantifiedExprBodyList body;
533 ExprSingle satisfies;
534 bool every;
536 public QuantifiedExpr (bool every, QuantifiedExprBodyList body, ExprSingle satisfies)
538 this.every = every;
539 this.body = body;
540 this.satisfies = satisfies;
543 public bool Every {
544 get { return every; }
547 public QuantifiedExprBodyList BodyList {
548 get { return body; }
551 public ExprSingle Satisfies {
552 get { return satisfies; }
553 set { satisfies = value; }
556 internal override void CheckReference (XQueryASTCompiler compiler)
558 foreach (QuantifiedExprBody one in body) {
559 if (one.Type != null)
560 compiler.CheckSchemaType (one.Type);
561 one.Expression.CheckReference (compiler);
563 Satisfies.CheckReference (compiler);
566 #region CompileAndEvaluate
567 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
569 Satisfies = Satisfies.Compile (compiler);
570 for (int i = 0; i < BodyList.Count; i++) {
571 BodyList [i].Expression = BodyList [i].Expression.Compile (compiler);
572 if (BodyList [i].Type != null)
573 compiler.CheckType (BodyList [i].Expression, BodyList [i].Type);
575 return this;
578 public override SequenceType StaticType {
579 get { return SequenceType.Boolean; }
582 public override XPathSequence Evaluate (XPathSequence iter)
584 return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
587 public override bool EvaluateAsBoolean (XPathSequence iter)
589 return EvaluateQuantification (iter, BodyList.GetEnumerator ());
592 private bool EvaluateQuantification (XPathSequence iter, IEnumerator bodies)
594 if (bodies.MoveNext ()) {
595 QuantifiedExprBody qb = bodies.Current as QuantifiedExprBody;
596 XPathSequence seq = qb.Expression.Evaluate (iter);
597 bool passed = false;
598 foreach (XPathItem item in seq) {
599 passed = true;
600 // FIXME: consider qb.Type
601 try {
602 iter.Context.PushVariable (qb.VarName, item);
603 if (EvaluateQuantification (iter, bodies)) {
604 if (!Every)
605 return true;
607 else if (Every)
608 return false;
609 } finally {
610 iter.Context.PopVariable ();
613 return passed;
615 return Satisfies.EvaluateAsBoolean (iter);
617 #endregion
620 internal class QuantifiedExprBodyList : CollectionBase
622 public QuantifiedExprBodyList ()
626 public void Add (QuantifiedExprBody body)
628 List.Add (body);
631 public void Insert (int pos, QuantifiedExprBody body)
633 List.Insert (pos, body);
636 public QuantifiedExprBody this [int i] {
637 get { return (QuantifiedExprBody) List [i]; }
641 internal class QuantifiedExprBody
643 private XmlQualifiedName varName;
644 private SequenceType type;
645 private ExprSingle expr;
647 public QuantifiedExprBody (XmlQualifiedName varName,
648 SequenceType type, ExprSingle expr)
650 this.varName = varName;
651 this.type = type ;
652 this.expr = expr;
655 public XmlQualifiedName VarName {
656 get { return varName; }
659 public SequenceType Type {
660 get { return type; }
663 public ExprSingle Expression {
664 get { return expr; }
665 set { expr = value; }
669 // TypeswitchExpr
671 internal class TypeswitchExpr : ExprSingle
673 ExprSequence switchExpr;
674 CaseClauseList caseList;
675 XmlQualifiedName defaultVarName;
676 ExprSingle defaultReturn;
678 public TypeswitchExpr (ExprSequence switchExpr, CaseClauseList caseList, XmlQualifiedName defaultVarName, ExprSingle defaultReturn)
680 this.switchExpr = switchExpr;
681 this.caseList = caseList;
682 this.defaultVarName = defaultVarName;
683 this.defaultReturn = defaultReturn;
686 public ExprSequence SwitchExpr {
687 get { return switchExpr; }
690 public CaseClauseList Cases {
691 get { return caseList; }
694 public XmlQualifiedName DefaultVarName {
695 get { return defaultVarName; }
698 public ExprSingle DefaultReturn {
699 get { return defaultReturn; }
700 set { defaultReturn = value; }
703 internal override void CheckReference (XQueryASTCompiler compiler)
705 switchExpr.CheckReference (compiler);
706 foreach (CaseClause cc in caseList) {
707 compiler.CheckSchemaType (cc.Type);
708 cc.Expr.CheckReference (compiler);
710 defaultReturn.CheckReference (compiler);
713 #region CompileAndEvaluate
714 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
716 for (int i = 0; i < SwitchExpr.Count; i++)
717 SwitchExpr [i] = SwitchExpr [i].Compile (compiler);
718 foreach (CaseClause cc in Cases)
719 cc.Expr = cc.Expr.Compile (compiler);
720 DefaultReturn = DefaultReturn.Compile (compiler);
721 return this;
724 // FIXME: it can be optimized by checking all case clauses.
725 public override SequenceType StaticType {
726 get { return SequenceType.AnyType; }
729 public override XPathSequence Evaluate (XPathSequence iter)
731 // FIXME: should move to iterator?
732 XPathSequence cond = new ExprSequenceIterator (iter, SwitchExpr);
733 XPathSequence ret = null;
735 foreach (CaseClause ccc in Cases) {
736 if (ccc.Type.Matches (cond)) {
737 if (ccc.VarName != XmlQualifiedName.Empty)
738 iter.Context.PushVariable (ccc.VarName, cond);
739 ret = ccc.Expr.Evaluate (iter);
740 // FIXME: The design should make sure that in-scope variables are held on actual iteration.
741 if (ccc.VarName != XmlQualifiedName.Empty)
742 iter.Context.PopVariable ();
743 return ret;
747 if (DefaultVarName != XmlQualifiedName.Empty)
748 iter.Context.PushVariable (DefaultVarName, cond);
749 ret = DefaultReturn.Evaluate (iter);
750 if (DefaultVarName != XmlQualifiedName.Empty)
751 iter.Context.PopVariable ();
752 return ret;
754 #endregion
757 internal class CaseClauseList : CollectionBase
759 public void Insert (int pos, CaseClause cc)
761 List.Insert (pos, cc);
764 public void Add (CaseClause cc)
766 List.Add (cc);
769 public CaseClause this [int i] {
770 get { return (CaseClause) List [i]; }
774 internal class CaseClause
776 public CaseClause (SequenceType type, ExprSingle expr, XmlQualifiedName varName)
778 this.type = type;
779 this.expr = expr;
780 this.varName = varName;
783 SequenceType type;
784 ExprSingle expr;
785 XmlQualifiedName varName;
787 public SequenceType Type {
788 get { return type; }
791 public ExprSingle Expr {
792 get { return expr; }
793 set { expr = value; }
796 public XmlQualifiedName VarName {
797 get { return varName; }
798 set { varName = value; }
802 // IfExpr
804 internal class IfExpr : ExprSingle
806 public IfExpr (ExprSequence condition, ExprSingle trueExpr, ExprSingle falseExpr)
808 this.condition = new ParenthesizedExpr (condition);
809 this.trueExpr = trueExpr;
810 this.falseExpr = falseExpr;
813 ExprSingle condition;
814 ExprSingle trueExpr;
815 ExprSingle falseExpr;
817 public ExprSingle Condition {
818 get { return condition; }
819 set { condition = value; }
822 public ExprSingle TrueExpr {
823 get { return trueExpr; }
824 set { trueExpr = value; }
827 public ExprSingle FalseExpr {
828 get { return falseExpr; }
829 set { falseExpr = value; }
832 internal override void CheckReference (XQueryASTCompiler compiler)
834 condition.CheckReference (compiler);
835 trueExpr.CheckReference (compiler);
836 falseExpr.CheckReference (compiler);
839 #region CompileAndEvaluate
840 SequenceType computedReturnType;
842 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
844 condition = condition.Compile (compiler);
845 // FIXME: check if condition is constant, and returns trueExpr or falseExpr
846 TrueExpr = TrueExpr.Compile (compiler);
847 FalseExpr = FalseExpr.Compile (compiler);
848 return this;
851 public override SequenceType StaticType {
852 get {
853 if (Context == null)
854 return SequenceType.AnyType;
855 if (computedReturnType == null)
856 computedReturnType = SequenceType.ComputeCommonBase (TrueExpr.StaticType, FalseExpr.StaticType);
857 return computedReturnType;
861 public override XPathSequence Evaluate (XPathSequence iter)
863 if (condition.EvaluateAsBoolean (iter))
864 return TrueExpr.Evaluate (iter);
865 return FalseExpr.Evaluate (iter);
867 #endregion
871 // logical expr
873 internal abstract class BinaryOperationExpr : ExprSingle
875 protected BinaryOperationExpr (ExprSingle left, ExprSingle right)
877 this.left = left;
878 this.right = right;
881 ExprSingle left, right;
883 public ExprSingle Left {
884 get { return left; }
885 set { left = value; }
888 public ExprSingle Right{
889 get { return right; }
890 set { right = value; }
893 internal override void CheckReference (XQueryASTCompiler compiler)
895 left.CheckReference (compiler);
896 right.CheckReference (compiler);
899 #region CompileAndEvaluate
900 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
902 Left = Left.Compile (compiler);
903 Right = Right.Compile (compiler);
904 return this;
906 #endregion
910 internal class OrExpr : BinaryOperationExpr
912 public OrExpr (ExprSingle left, ExprSingle right)
913 : base (left, right)
917 #region CompileAndEvaluate
918 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
920 base.CompileCore (compiler);
921 // FIXME: check constant value and return true or false
922 return this;
925 public override SequenceType StaticType {
926 get { return SequenceType.Boolean; }
929 public override bool EvaluateAsBoolean (XPathSequence iter)
931 return Left.EvaluateAsBoolean (iter) || Right.EvaluateAsBoolean (iter);
934 public override XPathSequence Evaluate (XPathSequence iter)
936 return new SingleItemIterator (EvaluateAsBoolean (iter) ?AtomicTrue : AtomicFalse, iter.Context);
940 - compiler -
941 return leftExprBool (context) || rightExprBool (context);
943 #endregion
946 internal class AndExpr : BinaryOperationExpr
948 public AndExpr (ExprSingle left, ExprSingle right)
949 : base (left, right)
953 #region CompileAndEvaluate
954 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
956 base.CompileCore (compiler);
957 // FIXME: check constant value and return true or false
958 return this;
961 public override SequenceType StaticType {
962 get { return SequenceType.Boolean; }
965 public override bool EvaluateAsBoolean (XPathSequence iter)
967 return Left.EvaluateAsBoolean (iter) && Right.EvaluateAsBoolean (iter);
970 public override XPathSequence Evaluate (XPathSequence iter)
972 return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
976 - compiler -
977 return leftExprBool (context) && rightExprBool (context);
979 #endregion
982 // TypeOperation expr
984 internal abstract class TypeOperationExpr : ExprSingle
986 protected TypeOperationExpr (ExprSingle expr, SequenceType type)
988 this.expr = expr;
989 this.type = type;
992 ExprSingle expr;
993 SequenceType type;
995 public ExprSingle Expr {
996 get { return expr; }
997 set { expr = value; }
1000 public SequenceType TargetType {
1001 get { return type; }
1004 internal override void CheckReference (XQueryASTCompiler compiler)
1006 expr.CheckReference (compiler);
1007 compiler.CheckSchemaType (type);
1011 internal abstract class AtomicTypeOperationExpr : ExprSingle
1013 protected AtomicTypeOperationExpr (ExprSingle expr, XmlTypeCode type, bool optional)
1015 this.expr = expr;
1016 this.targetType = SequenceType.Create (type, optional ? Occurence.Optional : Occurence.One);
1019 ExprSingle expr;
1020 SequenceType targetType;
1022 internal ExprSingle Expr {
1023 get { return expr; }
1024 set { expr = value; }
1028 public XmlTypeCode TypeCode {
1029 get { return typeCode; }
1032 public bool Optional {
1033 get { return optional; }
1036 internal SequenceType TargetType {
1037 get { return targetType; }
1040 internal override void CheckReference (XQueryASTCompiler compiler)
1042 expr.CheckReference (compiler);
1046 internal class InstanceOfExpr : TypeOperationExpr
1048 public InstanceOfExpr (ExprSingle expr, SequenceType type)
1049 : base (expr, type)
1053 #region CompileAndEvaluate
1054 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1056 Expr = Expr.Compile (compiler);
1057 // FIXME: check return type and if it never matches then return false
1058 return this;
1061 public override SequenceType StaticType {
1062 get { return SequenceType.Boolean; }
1065 public override bool EvaluateAsBoolean (XPathSequence iter)
1067 bool occured = false;
1068 bool onlyOnce = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.Optional);
1069 bool required = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.OneOrMore);
1070 foreach (XPathItem item in iter) {
1071 if (occured && onlyOnce)
1072 return false;
1073 if (!TargetType.IsInstance (item))
1074 return false;
1076 return occured || !required;
1079 public override XPathSequence Evaluate (XPathSequence iter)
1081 return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
1083 #endregion
1086 internal class TreatExpr : TypeOperationExpr
1088 public TreatExpr (ExprSingle expr, SequenceType type)
1089 : base (expr, type)
1093 #region CompileAndEvaluate
1094 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1096 Expr = Expr.Compile (compiler);
1097 // FIXME: check return type and if it never matches then return false
1098 return this;
1101 public override SequenceType StaticType {
1102 get { return SequenceType.AnyType; }
1105 public override XPathSequence Evaluate (XPathSequence iter)
1107 if (TargetType.CanConvert (iter))
1108 return iter;
1109 else
1110 throw new XmlQueryException (String.Format ("Cannot treat as {1}", TargetType));
1112 #endregion
1115 internal class CastableExpr : AtomicTypeOperationExpr
1117 public CastableExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional)
1118 : base (expr, atomicType, optional)
1122 #region CompileAndEvaluate
1123 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1125 Expr = Expr.Compile (compiler);
1126 // FIXME: check return type and if it never matches then return boolean
1127 return this;
1130 public override SequenceType StaticType {
1131 get { return SequenceType.Boolean; }
1134 public override XPathSequence Evaluate (XPathSequence iter)
1136 return new SingleItemIterator (new XPathAtomicValue (EvaluateAsBoolean (iter), InternalPool.XsBoolean), iter.Context);
1139 public override bool EvaluateAsBoolean (XPathSequence iter)
1141 bool occured = false;
1142 bool onlyOnce = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.Optional);
1143 bool required = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.OneOrMore);
1144 foreach (XPathItem item in iter) {
1145 if (occured && onlyOnce)
1146 return false;
1147 if (!TargetType.CanConvert (item))
1148 return false;
1150 return occured || !required;
1152 #endregion
1155 internal class CastExpr : AtomicTypeOperationExpr
1157 public CastExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional)
1158 : base (expr, atomicType, optional)
1162 #region CompileAndEvaluate
1163 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1165 Expr = Expr.Compile (compiler);
1166 // FIXME: check return type and if it never matches then return boolean
1167 return this;
1170 public override SequenceType StaticType {
1171 get { return TargetType; }
1174 public override XPathSequence Evaluate (XPathSequence iter)
1176 if (TargetType.CanConvert (iter))
1177 return new ConvertingIterator (iter, TargetType);
1178 else
1179 throw new XmlQueryException (String.Format ("Cannot cast as {1}", TargetType));
1181 #endregion
1184 // ComparisonExpr
1186 internal class ComparisonExpr : BinaryOperationExpr
1188 public ComparisonExpr (ExprSingle left, ExprSingle right, ComparisonOperator oper)
1189 : base (left, right)
1191 this.oper = oper;
1194 ComparisonOperator oper;
1196 public ComparisonOperator Operation {
1197 get { return oper; }
1200 #region CompileAndEvaluate
1201 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1203 Left = Left.Compile (compiler);
1204 Right = Right.Compile (compiler);
1205 // FIXME: check return type and if it never matches then return boolean
1206 return this;
1209 public override SequenceType StaticType {
1210 get { return SequenceType.Boolean; }
1213 public override XPathSequence Evaluate (XPathSequence iter)
1215 bool isEmpty;
1216 bool result = EvaluateAsBoolean (iter, out isEmpty);
1217 if (isEmpty)
1218 return new XPathEmptySequence (iter.Context);
1219 return new SingleItemIterator (result ? AtomicTrue : AtomicFalse, iter.Context);
1222 public override bool EvaluateAsBoolean (XPathSequence iter)
1224 bool isEmpty;
1225 return EvaluateAsBoolean (iter, out isEmpty);
1228 private bool EvaluateAsBoolean (XPathSequence iter, out bool isEmpty)
1230 XPathSequence lseq, rseq;
1231 isEmpty = false;
1233 switch (Operation) {
1234 // FIXME: it is curious but currently gmcs requires full typename.
1235 case Mono.Xml.XPath2.ComparisonOperator.ValueEQ:
1236 case Mono.Xml.XPath2.ComparisonOperator.ValueNE:
1237 case Mono.Xml.XPath2.ComparisonOperator.ValueLT:
1238 case Mono.Xml.XPath2.ComparisonOperator.ValueLE:
1239 case Mono.Xml.XPath2.ComparisonOperator.ValueGT:
1240 case Mono.Xml.XPath2.ComparisonOperator.ValueGE:
1241 XPathItem itemVL = ExamineOneItem (Left.Evaluate (iter));
1242 XPathItem itemVR = ExamineOneItem (Right.Evaluate (iter));
1243 if (itemVL == null || itemVR == null) {
1244 isEmpty = true;
1245 return false;
1247 return CompareAtomic (itemVL, itemVR);
1249 case Mono.Xml.XPath2.ComparisonOperator.GeneralEQ:
1250 case Mono.Xml.XPath2.ComparisonOperator.GeneralNE:
1251 case Mono.Xml.XPath2.ComparisonOperator.GeneralLT:
1252 case Mono.Xml.XPath2.ComparisonOperator.GeneralLE:
1253 case Mono.Xml.XPath2.ComparisonOperator.GeneralGT:
1254 case Mono.Xml.XPath2.ComparisonOperator.GeneralGE:
1255 lseq = Left.Evaluate (iter);
1256 rseq = Right.Evaluate (iter);
1257 foreach (XPathItem itemGL in lseq) {
1258 foreach (XPathItem itemGR in rseq.Clone ()) {
1259 if (CompareAtomic (itemGL, itemGR))
1260 return true;
1263 return false;
1265 case Mono.Xml.XPath2.ComparisonOperator.NodeIs:
1266 case Mono.Xml.XPath2.ComparisonOperator.NodeFWD:
1267 case Mono.Xml.XPath2.ComparisonOperator.NodeBWD:
1268 XPathNavigator lnav = ExamineOneNode (Left.Evaluate (iter));
1269 XPathNavigator rnav = ExamineOneNode (Right.Evaluate (iter));
1270 if (lnav == null || rnav == null) {
1271 isEmpty = true;
1272 return false;
1274 switch (Operation) {
1275 case Mono.Xml.XPath2.ComparisonOperator.NodeIs:
1276 return lnav.IsSamePosition (rnav);
1277 case Mono.Xml.XPath2.ComparisonOperator.NodeFWD:
1278 return lnav.ComparePosition (rnav) == XmlNodeOrder.Before;
1279 case Mono.Xml.XPath2.ComparisonOperator.NodeBWD:
1280 return lnav.ComparePosition (rnav) == XmlNodeOrder.After;
1282 break;
1284 throw new SystemException ("XQuery internal error: should not happen.");
1287 // returns null if sequence was empty
1288 private XPathItem ExamineOneItem (XPathSequence seq)
1290 if (!seq.MoveNext ())
1291 return null;
1292 XPathItem item = seq.Current;
1293 if (seq.MoveNext ())
1294 throw new XmlQueryException ("Operand of value comparison expression must be evaluated as a sequence that contains exactly one item.");
1295 return item;
1298 // returns null if sequence was empty
1299 private XPathNavigator ExamineOneNode (XPathSequence seq)
1301 if (!seq.MoveNext ())
1302 return null;
1303 XPathNavigator nav = seq.Current as XPathNavigator;
1304 if (nav == null || seq.MoveNext ())
1305 throw new XmlQueryException ("Operand of node comparison expression must be evaluated as a sequence that contains exactly one node.");
1306 return nav;
1309 private bool CompareAtomic (XPathItem itemL, XPathItem itemR)
1311 XmlSchemaSimpleType ua = InternalPool.XdtUntypedAtomic;
1312 XmlSchemaSimpleType str = InternalPool.XsString;
1313 // FIXME: XPathNavigator might be complex content.
1314 bool uaL = itemL.XmlType == null || itemL.XmlType == ua;
1315 bool uaR = itemR.XmlType == null || itemR.XmlType == ua;
1316 bool bothUA = uaL && uaR;
1317 XPathAtomicValue avL =
1318 (uaL) ?
1319 bothUA ? new XPathAtomicValue (itemL.Value, str) :
1320 new XPathAtomicValue (itemL.Value, itemR.XmlType) :
1321 Atomize (itemL);
1322 XPathAtomicValue avR =
1323 uaR ?
1324 bothUA ? new XPathAtomicValue (itemR.Value, str) :
1325 new XPathAtomicValue (itemR.Value, itemL.XmlType) :
1326 Atomize (itemR);
1328 switch (Operation) {
1329 // FIXME: it is curious but currently gmcs requires full typename.
1330 case Mono.Xml.XPath2.ComparisonOperator.ValueEQ:
1331 case Mono.Xml.XPath2.ComparisonOperator.GeneralEQ:
1332 return XQueryComparisonOperator.ValueEQ (avL, avR);
1333 case Mono.Xml.XPath2.ComparisonOperator.ValueNE:
1334 case Mono.Xml.XPath2.ComparisonOperator.GeneralNE:
1335 return XQueryComparisonOperator.ValueNE (avL, avR);
1336 case Mono.Xml.XPath2.ComparisonOperator.ValueLT:
1337 case Mono.Xml.XPath2.ComparisonOperator.GeneralLT:
1338 return XQueryComparisonOperator.ValueLT (avL, avR);
1339 case Mono.Xml.XPath2.ComparisonOperator.ValueLE:
1340 case Mono.Xml.XPath2.ComparisonOperator.GeneralLE:
1341 return XQueryComparisonOperator.ValueLE (avL, avR);
1342 case Mono.Xml.XPath2.ComparisonOperator.ValueGT:
1343 case Mono.Xml.XPath2.ComparisonOperator.GeneralGT:
1344 return XQueryComparisonOperator.ValueGT (avL, avR);
1345 case Mono.Xml.XPath2.ComparisonOperator.ValueGE:
1346 case Mono.Xml.XPath2.ComparisonOperator.GeneralGE:
1347 return XQueryComparisonOperator.ValueGE (avL, avR);
1349 return false; // should not happen
1351 #endregion
1354 public enum ComparisonOperator {
1355 ValueEQ,
1356 ValueNE,
1357 ValueLT,
1358 ValueLE,
1359 ValueGT,
1360 ValueGE,
1361 GeneralEQ,
1362 GeneralNE,
1363 GeneralLT,
1364 GeneralLE,
1365 GeneralGT,
1366 GeneralGE,
1367 NodeIs,
1368 NodeFWD,
1369 NodeBWD
1372 // Range
1374 internal class RangeExpr : BinaryOperationExpr
1376 public RangeExpr (ExprSingle left, ExprSingle right)
1377 : base (left, right)
1381 #region CompileAndEvaluate
1382 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1384 Left = Left.Compile (compiler);
1385 Right = Right.Compile (compiler);
1386 return this;
1389 public override SequenceType StaticType {
1390 get { return SequenceType.IntegerList; }
1393 public override XPathSequence Evaluate (XPathSequence iter)
1395 int start = Left.EvaluateAsInt (iter);
1396 int end = Right.EvaluateAsInt (iter);
1397 return new IntegerRangeIterator (iter.Context, start, end);
1400 public override void Serialize (XPathSequence iter)
1402 int start = Left.EvaluateAsInt (iter);
1403 int end = Right.EvaluateAsInt (iter);
1404 for (int i = start; i <= end; i++) {
1405 iter.Context.Writer.WriteValue (i);
1406 if (i < end)
1407 iter.Context.Writer.WriteWhitespace (" ");
1410 #endregion
1413 // arithmetic operation expr
1415 public enum ArithmeticOperator {
1416 Add,
1417 Sub,
1418 Mul,
1419 Div,
1420 IDiv,
1421 IMod
1424 internal class ArithmeticOperationExpr : BinaryOperationExpr
1426 public ArithmeticOperationExpr (ExprSingle left, ExprSingle right, ArithmeticOperator oper)
1427 : base (left, right)
1429 this.oper = oper;
1432 ArithmeticOperator oper;
1434 public ArithmeticOperator Operation {
1435 get { return oper; }
1438 #region CompileAndEvaluate
1439 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1441 Left = Left.Compile (compiler);
1442 Right = Right.Compile (compiler);
1443 return this;
1446 // FIXME: It can be optimized by comparing l/r value types.
1447 public override SequenceType StaticType {
1448 get { return SequenceType.AnyType; }
1451 public override XPathSequence Evaluate (XPathSequence iter)
1453 XPathSequence lseq = Left.Evaluate (iter);
1454 if (!lseq.MoveNext ())
1455 return new XPathEmptySequence (iter.Context);
1456 XPathSequence rseq = Right.Evaluate (iter);
1457 if (!rseq.MoveNext ())
1458 return new XPathEmptySequence (iter.Context);
1459 XPathAtomicValue lvalue = Atomize (lseq.Current);
1460 XPathAtomicValue rvalue = Atomize (rseq.Current);
1461 if (lseq.MoveNext ())
1462 throw new XmlQueryException ("XP0006: Left operand resulted in an sequence that contains more than one item.");
1463 if (rseq.MoveNext ())
1464 throw new XmlQueryException ("XP0006: Left operand resulted in an sequence that contains more than one item.");
1466 // FIXME: handle "untypedAtomic to xs:double" casting
1468 return new SingleItemIterator (Compute (lvalue, rvalue), iter.Context);
1471 private XPathAtomicValue Compute (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
1473 switch (Operation) {
1474 case ArithmeticOperator.Add:
1475 return XQueryArithmeticOperator.Add (lvalue, rvalue);
1476 case ArithmeticOperator.Sub:
1477 return XQueryArithmeticOperator.Subtract (lvalue, rvalue);
1478 case ArithmeticOperator.Mul:
1479 return XQueryArithmeticOperator.Multiply (lvalue, rvalue);
1480 case ArithmeticOperator.Div:
1481 return XQueryArithmeticOperator.Divide (lvalue, rvalue);
1482 case ArithmeticOperator.IDiv:
1483 return XQueryArithmeticOperator.IntDivide (lvalue, rvalue);
1484 case ArithmeticOperator.IMod:
1485 return XQueryArithmeticOperator.Remainder (lvalue, rvalue);
1486 default:
1487 throw new SystemException ("XQuery internal error: should not happen.");
1490 #endregion
1493 internal class MinusExpr : ExprSingle
1495 public MinusExpr (ExprSingle expr)
1497 this.expr = expr;
1500 ExprSingle expr;
1502 public ExprSingle Expr {
1503 get { return expr; }
1504 set { expr = value; }
1507 internal override void CheckReference (XQueryASTCompiler compiler)
1509 expr.CheckReference (compiler);
1512 #region CompileAndEvaluate
1513 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1515 return new ArithmeticOperationExpr (new DecimalLiteralExpr (-1), Expr, ArithmeticOperator.Mul).Compile (compiler);
1518 public override SequenceType StaticType {
1519 get { return Expr.StaticType; }
1522 public override XPathSequence Evaluate (XPathSequence iter)
1524 throw new SystemException ("XQuery internal error: should not happen.");
1526 #endregion
1529 // aggregation expr
1531 public enum AggregationType {
1532 Union,
1533 Intersect,
1534 Except
1537 internal class GroupExpr : BinaryOperationExpr
1539 public GroupExpr (ExprSingle left, ExprSingle right, AggregationType aggrType)
1540 : base (left, right)
1542 this.aggrType = aggrType;
1545 AggregationType aggrType;
1547 public AggregationType AggregationType {
1548 get { return aggrType; }
1551 #region CompileAndEvaluate
1552 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1554 Left = Left.Compile (compiler);
1555 Right = Right.Compile (compiler);
1556 return this;
1559 // FIXME: It can be optimized by comparing l/r value types.
1560 public override SequenceType StaticType {
1561 get { return SequenceType.AnyType; }
1564 // only applicable against node-sets
1565 public override XPathSequence Evaluate (XPathSequence iter)
1567 return new GroupIterator (iter, this);
1569 #endregion
1572 // validate expr
1574 internal class ValidateExpr : ExprSingle
1576 XmlSchemaContentProcessing schemaMode;
1577 ExprSequence expr;
1579 public ValidateExpr (XmlSchemaContentProcessing schemaMode, ExprSequence expr)
1581 this.schemaMode = schemaMode;
1582 this.expr = expr;
1585 public ExprSequence Expr {
1586 get { return expr; }
1589 public XmlSchemaContentProcessing SchemaMode {
1590 get { return schemaMode; }
1593 internal override void CheckReference (XQueryASTCompiler compiler)
1595 expr.CheckReference (compiler);
1598 #region CompileAndEvaluate
1599 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1601 for (int i = 0; i < expr.Count; i++)
1602 expr [i] = expr [i].Compile (compiler);
1603 return this;
1606 public override SequenceType StaticType {
1607 get { return SequenceType.AnyType; }
1610 public override XPathSequence Evaluate (XPathSequence iter)
1612 // TBD (see 3.13).
1613 throw new NotImplementedException ();
1615 #endregion
1618 // Path expr
1620 internal abstract class PathExpr : ExprSingle
1624 // '/'
1625 internal class PathRootExpr : PathExpr
1627 public PathRootExpr ()
1631 internal override void CheckReference (XQueryASTCompiler compiler)
1635 #region CompileAndEvaluate
1636 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1638 return this;
1641 public override SequenceType StaticType {
1642 get { return SequenceType.Document; }
1645 public override XPathSequence Evaluate (XPathSequence iter)
1647 XPathNavigator nav = iter.Context.CurrentItem as XPathNavigator;
1648 if (nav == null)
1649 throw new XmlQueryException ("Context item is not a node when evaluating expression '/'.");
1650 nav = nav.Clone ();
1651 nav.MoveToRoot ();
1652 return new SingleItemIterator (nav, iter.Context);
1654 #endregion
1657 internal abstract class PathStepExpr : PathExpr
1659 ExprSingle first;
1660 ExprSingle next;
1662 public PathStepExpr (ExprSingle first, ExprSingle next)
1664 this.first = first;
1665 this.next = next;
1668 public ExprSingle First {
1669 get { return first; }
1670 set { first = value; }
1673 public ExprSingle Next {
1674 get { return next; }
1675 set { next = value; }
1678 internal override void CheckReference (XQueryASTCompiler compiler)
1680 first.CheckReference (compiler);
1681 next.CheckReference (compiler);
1684 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1686 first = first.Compile (compiler);
1687 next = next.Compile (compiler);
1688 return this;
1693 // 'foo/bar'
1694 internal class PathSlashExpr : PathStepExpr
1696 public PathSlashExpr (ExprSingle first, ExprSingle next)
1697 : base (first, next)
1701 #region CompileAndEvaluate
1702 // FIXME: It can be optimized by comparing l/r value types.
1703 public override SequenceType StaticType {
1704 get { return SequenceType.Node; }
1707 public override XPathSequence Evaluate (XPathSequence iter)
1709 return new PathStepIterator (First.Evaluate (iter), this);
1711 #endregion
1714 // 'foo//bar'
1715 internal class PathSlash2Expr : PathStepExpr
1717 public PathSlash2Expr (ExprSingle first, ExprSingle next)
1718 : base (first, next)
1722 #region CompileAndEvaluate
1723 // FIXME: It can be optimized by comparing l/r value types.
1724 public override SequenceType StaticType {
1725 get { return SequenceType.Node; }
1728 public override XPathSequence Evaluate (XPathSequence iter)
1730 XPathSequence seq = First.Evaluate (iter);
1731 if (!seq.MoveNext ())
1732 return new XPathEmptySequence (iter.Context);
1733 return new PathStepIterator (
1734 new DescendantOrSelfIterator (seq.Current as XPathNavigator, seq.Context), this);
1736 #endregion
1739 internal class AxisStepExpr : PathExpr
1741 public AxisStepExpr (XPathAxis axis, XPath2NodeTest test)
1743 this.axis = axis;
1744 if (test == null)
1745 nameTest = XmlQualifiedName.Empty;
1746 else {
1747 if (test.NameTest != null)
1748 this.nameTest = test.NameTest;
1749 else
1750 this.kindTest = test.KindTest;
1754 XPathAxis axis;
1755 XmlQualifiedName nameTest;
1756 KindTest kindTest;
1758 public XPathAxis Axis {
1759 get { return axis; }
1762 public XmlQualifiedName NameTest {
1763 get { return nameTest; }
1764 set { nameTest = value; }
1767 public KindTest KindTest {
1768 get { return kindTest; }
1769 set { kindTest = value; }
1772 internal override void CheckReference (XQueryASTCompiler compiler)
1774 if (KindTest != null)
1775 KindTest.CheckReference (compiler);
1778 #region CompileAndEvaluate
1779 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1781 if (KindTest != null)
1782 KindTest.Compile (compiler);
1783 return this;
1786 public override SequenceType StaticType {
1787 get {
1788 switch (Axis.AxisType) {
1789 case XPathAxisType.Attribute:
1790 return SequenceType.Attribute;
1791 case XPathAxisType.Namespace:
1792 return SequenceType.Namespace;
1794 // FIXME: we can more filtering by KindTest
1795 return SequenceType.Node;
1799 public override XPathSequence Evaluate (XPathSequence iter)
1801 XQueryContext ctx = iter.Context;
1803 if (iter.Position == 0) {
1804 iter = iter.Clone ();
1805 if (!iter.MoveNext ())
1806 return new XPathEmptySequence (iter.Context);
1809 XPathNavigator nav = iter.Current as XPathNavigator;
1810 if (nav == null)
1811 throw new XmlQueryException ("Node set is expected.");
1813 NodeIterator argIter = null;
1815 switch (Axis.AxisType) {
1816 case XPathAxisType.Child:
1817 argIter = new ChildIterator (nav, ctx); break;
1818 case XPathAxisType.Descendant:
1819 argIter = new DescendantIterator (nav, ctx); break;
1820 case XPathAxisType.Attribute:
1821 argIter = new AttributeIterator (nav, ctx); break;
1822 case XPathAxisType.Self:
1823 argIter = new SelfIterator (nav, ctx); break;
1824 case XPathAxisType.DescendantOrSelf:
1825 argIter = new DescendantOrSelfIterator (nav, ctx); break;
1826 case XPathAxisType.FollowingSibling:
1827 argIter = new FollowingSiblingIterator (nav, ctx); break;
1828 case XPathAxisType.Following:
1829 argIter = new FollowingIterator (nav, ctx); break;
1830 case XPathAxisType.Parent:
1831 argIter = new ParentIterator (nav, ctx); break;
1832 case XPathAxisType.Ancestor:
1833 argIter = new AncestorIterator (nav, ctx); break;
1834 case XPathAxisType.PrecedingSibling:
1835 argIter = new PrecedingSiblingIterator (nav, ctx); break;
1836 case XPathAxisType.Preceding:
1837 argIter = new PrecedingIterator (nav, ctx); break;
1838 case XPathAxisType.AncestorOrSelf:
1839 argIter = new AncestorOrSelfIterator (nav, ctx); break;
1840 case XPathAxisType.Namespace: // only applicable under XPath 2.0: not XQuery 1.0
1841 argIter = new NamespaceIterator (nav, ctx); break;
1843 return new AxisIterator (argIter, this);
1846 internal bool Matches (XPathNavigator nav)
1848 if (nameTest != null)
1849 return nameTest == XmlQualifiedName.Empty ||
1850 ((nameTest.Name == nav.LocalName || nameTest.Name == "*") &&
1851 (nameTest.Namespace == nav.NamespaceURI || nameTest.Namespace == "*"));
1852 else
1853 return kindTest.Matches (nav);
1855 #endregion
1858 internal class FilterStepExpr : PathExpr
1860 public FilterStepExpr (ExprSingle expr, ExprSequence predicate)
1862 this.expr = expr;
1863 this.predicate = predicate;
1866 ExprSingle expr;
1867 ExprSequence predicate;
1869 public ExprSingle Expr {
1870 get { return expr; }
1871 set { expr = value; }
1874 public ExprSequence Predicate {
1875 get { return predicate; }
1878 internal override void CheckReference (XQueryASTCompiler compiler)
1880 expr.CheckReference (compiler);
1881 predicate.CheckReference (compiler);
1884 #region CompileAndEvaluate
1885 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1887 Expr = Expr.Compile (compiler);
1888 for (int i = 0; i < predicate.Count; i++)
1889 predicate [i] = predicate [i].Compile (compiler);
1890 return this;
1893 public override SequenceType StaticType {
1894 get { return Expr.StaticType; }
1897 public override XPathSequence Evaluate (XPathSequence iter)
1899 return new FilteredIterator (iter, this);
1901 #endregion
1905 // predicates == exprsequence list == list of list of exprsingle
1906 internal class PredicateList : CollectionBase
1908 public void Add (ExprSequence expr)
1910 List.Add (expr);
1913 public void Insert (int pos, ExprSequence expr)
1915 List.Insert (pos, expr);
1918 public ExprSequence this [int i] {
1919 get { return (ExprSequence) List [i]; }
1924 internal class XPath2NodeTest
1926 public XPath2NodeTest (XmlQualifiedName nameTest)
1928 this.NameTest = nameTest;
1931 public XPath2NodeTest (KindTest kindTest)
1933 this.KindTest = kindTest;
1936 public XmlQualifiedName NameTest;
1938 public KindTest KindTest;
1941 internal class EnclosedExpr : ExprSingle
1943 ExprSequence expr;
1945 public EnclosedExpr (ExprSequence expr)
1947 this.expr = expr;
1950 public ExprSequence Expr {
1951 get { return expr; }
1954 internal override void CheckReference (XQueryASTCompiler compiler)
1956 expr.CheckReference (compiler);
1959 #region CompileAndEvaluate
1960 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1962 if (Expr.Count == 1)
1963 return Expr [0].Compile (compiler);
1964 for (int i = 0; i < Expr.Count; i++)
1965 Expr [i] = Expr [i].Compile (compiler);
1966 return this;
1969 // FIXME: can be optimized by checking all items in Expr
1970 public override SequenceType StaticType {
1971 get { return SequenceType.AnyType; }
1974 public override XPathSequence Evaluate (XPathSequence iter)
1976 return new ExprSequenceIterator (iter, Expr);
1978 #endregion
1981 // PrimaryExpr
1983 internal abstract class PrimaryExpr : ExprSingle
1985 internal override void CheckReference (XQueryASTCompiler compiler)
1989 #region CompileAndEvaluate
1990 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1992 return this;
1995 public override XPathSequence Evaluate (XPathSequence iter)
1997 return new SingleItemIterator (EvaluateAsAtomic (iter), iter.Context);
1999 #endregion
2002 internal class StringLiteralExpr : PrimaryExpr
2004 string literal;
2006 public StringLiteralExpr (string literal)
2008 this.literal = literal;
2011 public string Literal {
2012 get { return literal; }
2015 #region CompileAndEvaluate
2016 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("string", XmlSchema.Namespace));
2018 public override SequenceType StaticType {
2019 get { return SequenceType.AtomicString; }
2022 public override string EvaluateAsString (XPathSequence iter)
2024 return Literal;
2027 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2029 return new XPathAtomicValue (Literal, stringType);
2031 #endregion
2034 internal class DecimalLiteralExpr : PrimaryExpr
2036 decimal value;
2038 public DecimalLiteralExpr (decimal value)
2040 this.value = value;
2043 public decimal Value {
2044 get { return value; }
2047 #region CompileAndEvaluate
2048 XmlSchemaSimpleType decimalType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("decimal", XmlSchema.Namespace));
2050 public override SequenceType StaticType {
2051 get { return SequenceType.Decimal; }
2054 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2056 return new XPathAtomicValue (Value, decimalType);
2058 #endregion
2061 internal class DoubleLiteralExpr : PrimaryExpr
2063 double value;
2065 public DoubleLiteralExpr (double value)
2067 this.value = value;
2070 public double Value {
2071 get { return value; }
2074 #region CompileAndEvaluate
2075 XmlSchemaSimpleType doubleType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("double", XmlSchema.Namespace));
2077 public override SequenceType StaticType {
2078 get { return SequenceType.Double; }
2081 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2083 return new XPathAtomicValue (Value, doubleType);
2085 #endregion
2088 internal class VariableReferenceExpr : PrimaryExpr
2090 XmlQualifiedName varName;
2092 public VariableReferenceExpr (XmlQualifiedName varName)
2094 this.varName = varName;
2097 public XmlQualifiedName VariableName {
2098 get { return varName; }
2101 // FIXME: variable name must be stacked in any area
2102 // whereever variables are defined.
2103 internal override void CheckReference (XQueryASTCompiler compiler)
2105 compiler.CheckVariableName (varName);
2108 #region CompileAndEvaluate
2109 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2111 // FIXME: try to resolve static context variable and return the actual value expression
2112 return this;
2115 public override SequenceType StaticType {
2116 get { return SequenceType.AnyType; }
2119 public override XPathSequence Evaluate (XPathSequence iter)
2121 XPathSequence variable = iter.Context.ResolveVariable (VariableName);
2122 // FIXME: if Evaluate() accepts XPathSequence, then XPathSequence must be public class (to make IXPath2Variable public).
2123 return variable;
2125 #endregion
2128 internal class ParenthesizedExpr : PrimaryExpr
2130 ExprSequence expr;
2132 public ParenthesizedExpr (ExprSequence expr)
2134 if (expr == null)
2135 expr = new ExprSequence ();
2136 this.expr = expr;
2139 ExprSequence Expr {
2140 get { return expr; }
2143 #region CompileAndEvaluate
2144 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2146 if (Expr.Count == 1)
2147 return Expr [0].Compile (compiler);
2148 for (int i = 0; i < Expr.Count; i++)
2149 Expr [i] = Expr [i].Compile (compiler);
2150 return this;
2153 // FIXME: can be optimized by checking all items in Expr
2154 public override SequenceType StaticType {
2155 get { return SequenceType.AnyType; }
2158 public override XPathSequence Evaluate (XPathSequence iter)
2160 switch (Expr.Count) {
2161 case 0:
2162 return new XPathEmptySequence (iter.Context);
2163 case 1:
2164 return Expr [0].Evaluate (iter);
2165 default:
2166 return new ExprSequenceIterator (iter, Expr);
2169 #endregion
2172 // "."
2173 internal class ContextItemExpr : PrimaryExpr
2175 public ContextItemExpr ()
2179 #region CompileAndEvaluate
2180 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2182 return this;
2185 public override SequenceType StaticType {
2186 get { return SequenceType.AnyType; }
2189 public override XPathSequence Evaluate (XPathSequence iter)
2191 return new SingleItemIterator (iter.Context.CurrentItem, iter.Context);
2193 #endregion
2196 internal abstract class FunctionCallExprBase : PrimaryExpr
2198 XmlQualifiedName name;
2199 ExprSequence args;
2201 public FunctionCallExprBase (XmlQualifiedName name, ExprSequence args)
2203 if (args == null)
2204 throw new ArgumentNullException (String.Format ("Function argument expressions for {0} is null.", name));
2205 this.name = name;
2206 this.args = args;
2209 public XmlQualifiedName Name {
2210 get { return name; }
2213 public ExprSequence Args {
2214 get { return args; }
2217 internal override void CheckReference (XQueryASTCompiler compiler)
2219 compiler.CheckFunctionName (name);
2222 #region CompileAndEvaluate
2224 internal static DefaultFunctionCall Create (
2225 XmlQualifiedName name,
2226 ExprSingle [] args,
2227 XQueryStaticContext ctx)
2229 switch (name.Namespace) {
2230 case XQueryFunction.Namespace:
2231 switch (name.Name) {
2232 case "node-name":
2233 return new FnNodeNameCall (ctx, args);
2234 case "nilled":
2235 return new FnNilledCall (ctx, args);
2236 case "string":
2237 return new FnStringCall (ctx, args);
2238 case "data":
2239 return new FnDataCall (ctx, args);
2240 case "base-uri":
2241 return new FnBaseUriCall (ctx, args);
2242 case "document-uri":
2243 return new FnDocumentUriCall (ctx, args);
2244 case "error":
2245 return new FnErrorCall (ctx, args);
2246 case "trace":
2247 return new FnTraceCall (ctx, args);
2248 case "abs":
2249 return new FnAbsCall (ctx, args);
2250 case "ceiling":
2251 return new FnCeilingCall (ctx, args);
2252 case "floor":
2253 return new FnFloorCall (ctx, args);
2254 case "round":
2255 return new FnRoundCall (ctx, args);
2256 case "round-half-to-even":
2257 return new FnRoundHalfToEvenCall (ctx, args);
2258 case "codepoints-to-string":
2259 return new FnCodepointsToStringCall (ctx, args);
2260 case "string-to-codepoints":
2261 return new FnStringCallToCodepointsCall (ctx, args);
2263 goto default;
2264 case InternalPool.XdtNamespace:
2265 case XmlSchema.Namespace:
2266 XmlSchemaType type = XmlSchemaType.GetBuiltInSimpleType (name);
2267 if (type != null)
2268 return new AtomicConstructorCall (ctx, SequenceType.Create (type, Occurence.One), args);
2269 type = XmlSchemaType.GetBuiltInComplexType (name);
2270 if (type == null)
2271 goto default;
2272 return null;
2273 default:
2274 XQueryFunction func = ctx.CompileContext.InEffectFunctions [name];
2275 if (func != null)
2276 return new CustomFunctionCallExpression (ctx, args, func);
2277 return null;
2282 internal void CheckArguments (XQueryASTCompiler compiler)
2284 if (args.Count < MinArgs || args.Count > MaxArgs)
2285 // FIXME: add more info
2286 throw new XmlQueryCompileException (String.Format ("{0} is invalid for the number of {1} function argument. MinArgs = {2}, MaxArgs = {3}.", args.Count, name, MinArgs, MaxArgs));
2289 public abstract int MinArgs { get; }
2290 public abstract int MaxArgs { get; }
2291 #endregion
2294 internal class FunctionCallExpr : FunctionCallExprBase
2296 public FunctionCallExpr (XmlQualifiedName name, ExprSequence args)
2297 : base (name, args)
2301 XQueryFunction function;
2303 public XQueryFunction Function {
2304 get { return function; }
2307 #region CompileAndEvaluate
2308 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2310 // resolve function
2311 function = compiler.ResolveFunction (Name);
2312 CheckArguments (compiler);
2313 for (int i = 0; i < Args.Count; i++)
2314 Args [i] = Args [i].Compile (compiler);
2315 return this;
2318 public override int MinArgs {
2319 get { return function.MinArgs; }
2322 public override int MaxArgs {
2323 get { return function.MaxArgs; }
2326 public override SequenceType StaticType {
2327 get { return function.ReturnType; }
2330 public override XPathSequence Evaluate (XPathSequence iter)
2332 return Function.Evaluate (iter, Args);
2335 // FIXME: add all overrides that delegates to XQueryFunction
2336 #endregion
2340 #region CompileAndEvaluate
2342 // It is instantiated per function call expression.
2343 // (e.g. the example below contains 4 FunctionCallExpression instances:
2344 // "replace(node-name (node-before(/*)), 'foo', node-name($var))"
2345 internal class CustomFunctionCallExpr : FunctionCallExprBase
2347 public CustomFunctionCallExpr (ExprSequence args, XQueryFunction function)
2348 : base (function.Name, args)
2350 this.function = function;
2353 XQueryFunction function;
2355 public XQueryFunction Function {
2356 get { return function; }
2359 public override int MinArgs {
2360 get { return function.MinArgs; }
2363 public override int MaxArgs {
2364 get { return function.MaxArgs; }
2367 public override SequenceType StaticType {
2368 get { return function.ReturnType; }
2371 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2373 CheckArguments (compiler);
2374 for (int i = 0; i < Args.Count; i++)
2375 Args [i] = Args [i].Compile (compiler);
2376 return this;
2379 public override XPathSequence Evaluate (XPathSequence iter)
2381 return Function.Evaluate (iter, Args);
2384 // FIXME: add all overrides that delegates to XQueryFunction
2386 #endregion
2389 // Ordered / Unordered
2390 internal class OrderSpecifiedExpr : ExprSingle
2392 bool ordered;
2393 ExprSequence expr;
2395 public OrderSpecifiedExpr (ExprSequence expr, bool ordered)
2397 this.ordered = ordered;
2398 this.expr = expr;
2401 public ExprSequence Expr {
2402 get { return expr; }
2405 public bool Ordered {
2406 get { return ordered; }
2409 internal override void CheckReference (XQueryASTCompiler compiler)
2411 expr.CheckReference (compiler);
2414 #region CompileAndEvaluate
2415 public override SequenceType StaticType {
2416 // FIXME: could be optimized by checking all the expressions
2417 get { return SequenceType.AnyType; }
2420 public override bool RequireSorting {
2421 get { return Ordered; }
2424 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2426 for (int i = 0; i < Expr.Count; i++)
2427 Expr [i] = Expr [i].Compile (compiler);
2428 return this;
2431 public override XPathSequence Evaluate (XPathSequence iter)
2433 throw new NotImplementedException ();
2435 #endregion
2439 #endif