**** Merged from MCS ****
[mono-project.git] / mcs / class / System.XML / System.Xml.Query / XPath2Expression.cs
blob52af884ce22bf95552efe063c77b77bc1ce25a9b
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;
39 namespace Mono.Xml.XPath2
41 public class ExprSequence : CollectionBase
43 public ExprSequence ()
47 public void Add (ExprSingle expr)
49 List.Add (expr);
52 public void AddRange (ICollection items)
54 if (items != null)
55 foreach (ExprSingle e in items)
56 List.Add (e);
59 public void Insert (int pos, ExprSingle expr)
61 List.Insert (pos, expr);
64 public ExprSingle this [int i] {
65 get { return List [i] as ExprSingle; }
66 set { List [i] = value; }
69 internal void CheckReference (XQueryASTCompiler compiler)
71 foreach (ExprSingle expr in List)
72 expr.CheckReference (compiler);
76 public abstract partial class ExprSingle
78 internal abstract void CheckReference (XQueryASTCompiler compiler);
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);
84 XQueryStaticContext ctx;
86 internal ExprSingle Compile (XQueryASTCompiler compiler)
88 this.ctx = ctx;
89 return CompileCore (compiler);
92 // If internal&&protected is available in C#, it is the best signature.
93 internal abstract ExprSingle CompileCore (XQueryASTCompiler compiler);
95 internal XQueryStaticContext Context {
96 get { return ctx; }
99 public abstract SequenceType StaticType { get; }
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
106 public abstract XPathSequence Evaluate (XPathSequence iter);
108 public virtual XPathSequence EvaluateOrdered (XPathSequence iter)
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);
116 else
117 return Evaluate (iter);
120 public virtual void Serialize (XPathSequence iter)
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);
134 private void WriteXPathItem (XPathItem item, XmlWriter w)
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);
148 // get EBV (fn:boolean())
149 public virtual bool EvaluateAsBoolean (XPathSequence iter)
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;
187 // otherwise, return true
188 return true;
191 public virtual int EvaluateAsInt (XPathSequence iter)
193 XPathAtomicValue v = Atomize (Evaluate (iter));
194 return v != null ? v.ValueAsInt32 : 0;
197 public virtual string EvaluateAsString (XPathSequence iter)
199 XPathAtomicValue v = Atomize (Evaluate (iter));
200 return v != null ? v.Value : String.Empty;
203 public static XPathAtomicValue Atomize (XPathItem item)
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);
212 else
213 return (XPathAtomicValue) item;
216 // FIXME: What if iter contains list value?
217 public static XPathAtomicValue Atomize (XPathSequence iter)
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);
228 else
229 return (XPathAtomicValue) iter.Current;
232 public virtual XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
234 return Atomize (Evaluate (iter));
237 public virtual bool RequireSorting {
238 get { return false; }
240 #endregion
243 // FLWORExpr
245 internal partial class FLWORExpr : ExprSingle
247 public FLWORExpr (ForLetClauseCollection forlet, ExprSequence whereClause, OrderSpecList orderBy, ExprSingle ret)
249 this.fl = forlet;
250 if (whereClause != null)
251 this.whereClause = new ParenthesizedExpr (whereClause);
252 this.orderBy = orderBy;
253 this.ret = ret;
256 ForLetClauseCollection fl;
257 ExprSingle whereClause;
258 OrderSpecList orderBy;
259 ExprSingle ret;
261 public ForLetClauseCollection ForLetClauses {
262 get { return fl; }
265 public ExprSingle WhereClause {
266 get { return whereClause; }
269 public OrderSpecList OrderBy {
270 get { return orderBy; }
273 public ExprSingle ReturnExpr {
274 get { return ret; }
275 set { ret = value; }
278 // ExprSingle Overrides
280 internal override void CheckReference (XQueryASTCompiler compiler)
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);
293 #region CompileAndEvaluate
294 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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);
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);
310 return this;
313 public override SequenceType StaticType {
314 get { return ReturnExpr.StaticType; }
317 public override XPathSequence Evaluate (XPathSequence iter)
319 return new FLWORIterator (iter, this);
321 #endregion
324 internal class ForLetClauseCollection : CollectionBase
326 public void Add (ForLetClause clause)
328 List.Add (clause);
331 public void Insert (int pos, ForLetClause clause)
333 List.Insert (pos, clause);
336 public ForLetClause this [int i] {
337 get { return (ForLetClause) List [i]; }
341 internal class OrderSpecList : CollectionBase
343 bool isStable;
345 public OrderSpecList ()
349 public bool IsStable {
350 get { return isStable; }
351 set { isStable = value; }
354 public void Insert (int pos, OrderSpec os)
356 List.Insert (pos, os);
359 public void Add (OrderSpec spec)
361 List.Add (spec);
364 public OrderSpec this [int i] {
365 get { return (OrderSpec) List [i]; }
369 internal class OrderSpec
371 public OrderSpec (ExprSingle expr, OrderModifier modifier)
373 this.expr = expr;
374 this.mod = modifier;
377 ExprSingle expr;
378 OrderModifier mod;
380 public ExprSingle Expression {
381 get {return expr; }
382 set { expr = value; }
385 public OrderModifier Modifier {
386 get { return mod; }
387 set { mod = value; }
391 internal class OrderModifier
393 public OrderModifier (XmlSortOrder order, XmlSortOrder emptyOrder, string collation)
395 this.sortOrder = sortOrder;
396 this.emptyOrder = emptyOrder;
397 if (collation != null)
398 this.coll = new CultureInfo (collation);
401 XmlSortOrder sortOrder;
402 XmlSortOrder emptyOrder;
403 CultureInfo coll;
405 public XmlSortOrder SortOrder {
406 get { return sortOrder; }
409 public XmlSortOrder EmptyOrder {
410 get { return emptyOrder; }
413 public CultureInfo Collation {
414 get { return coll; }
418 internal class ForLetClause : CollectionBase
420 public ForLetSingleBody this [int i] {
421 get { return (ForLetSingleBody) List [i]; }
425 internal class ForClause : ForLetClause
427 public ForClause ()
431 public void Insert (int pos, ForSingleBody body)
433 List.Insert (pos, body);
436 public void Add (ForSingleBody body)
438 List.Add (body);
442 internal class LetClause : ForLetClause
444 public LetClause ()
448 public void Insert (int pos, LetSingleBody body)
450 List.Insert (pos, body);
453 public void Add (LetSingleBody body)
455 List.Add (body);
459 internal abstract class ForLetSingleBody
461 XmlQualifiedName varName;
462 SequenceType type;
463 ExprSingle expr;
465 public ForLetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr)
467 this.varName = varName;
468 this.type = type;
469 this.expr = expr;
472 public XmlQualifiedName VarName {
473 get { return varName; }
476 public SequenceType ReturnType {
477 get { return type; }
480 public ExprSingle Expression {
481 get { return expr; }
482 set { expr = value; }
485 internal void CheckReference (XQueryASTCompiler compiler)
487 if (type != null)
488 compiler.CheckSchemaType (type);
489 expr.CheckReference (compiler);
493 internal class ForSingleBody : ForLetSingleBody
495 public ForSingleBody (XmlQualifiedName varName, SequenceType type, XmlQualifiedName positionalVar, ExprSingle expr)
496 : base (varName, type, expr)
498 this.positionalVar = positionalVar;
501 XmlQualifiedName positionalVar;
503 public XmlQualifiedName PositionalVar {
504 get { return positionalVar; }
508 internal class LetSingleBody : ForLetSingleBody
510 public LetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr)
511 : base (varName, type, expr)
516 // QuantifiedExpr
518 internal class QuantifiedExpr : ExprSingle
520 QuantifiedExprBodyList body;
521 ExprSingle satisfies;
522 bool every;
524 public QuantifiedExpr (bool every, QuantifiedExprBodyList body, ExprSingle satisfies)
526 this.every = every;
527 this.body = body;
528 this.satisfies = satisfies;
531 public bool Every {
532 get { return every; }
535 public QuantifiedExprBodyList BodyList {
536 get { return body; }
539 public ExprSingle Satisfies {
540 get { return satisfies; }
541 set { satisfies = value; }
544 internal override void CheckReference (XQueryASTCompiler compiler)
546 foreach (QuantifiedExprBody one in body) {
547 if (one.Type != null)
548 compiler.CheckSchemaType (one.Type);
549 one.Expression.CheckReference (compiler);
551 Satisfies.CheckReference (compiler);
554 #region CompileAndEvaluate
555 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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);
563 return this;
566 public override SequenceType StaticType {
567 get { return SequenceType.Boolean; }
570 public override XPathSequence Evaluate (XPathSequence iter)
572 return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
575 public override bool EvaluateAsBoolean (XPathSequence iter)
577 return EvaluateQuantification (iter, BodyList.GetEnumerator ());
580 private bool EvaluateQuantification (XPathSequence iter, IEnumerator bodies)
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;
595 else if (Every)
596 return false;
597 } finally {
598 iter.Context.PopVariable ();
601 return passed;
603 return Satisfies.EvaluateAsBoolean (iter);
605 #endregion
608 internal class QuantifiedExprBodyList : CollectionBase
610 public QuantifiedExprBodyList ()
614 public void Add (QuantifiedExprBody body)
616 List.Add (body);
619 public void Insert (int pos, QuantifiedExprBody body)
621 List.Insert (pos, body);
624 public QuantifiedExprBody this [int i] {
625 get { return (QuantifiedExprBody) List [i]; }
629 internal class QuantifiedExprBody
631 private XmlQualifiedName varName;
632 private SequenceType type;
633 private ExprSingle expr;
635 public QuantifiedExprBody (XmlQualifiedName varName,
636 SequenceType type, ExprSingle expr)
638 this.varName = varName;
639 this.type = type ;
640 this.expr = expr;
643 public XmlQualifiedName VarName {
644 get { return varName; }
647 public SequenceType Type {
648 get { return type; }
651 public ExprSingle Expression {
652 get { return expr; }
653 set { expr = value; }
657 // TypeswitchExpr
659 internal class TypeswitchExpr : ExprSingle
661 ExprSequence switchExpr;
662 CaseClauseList caseList;
663 XmlQualifiedName defaultVarName;
664 ExprSingle defaultReturn;
666 public TypeswitchExpr (ExprSequence switchExpr, CaseClauseList caseList, XmlQualifiedName defaultVarName, ExprSingle defaultReturn)
668 this.switchExpr = switchExpr;
669 this.caseList = caseList;
670 this.defaultVarName = defaultVarName;
671 this.defaultReturn = defaultReturn;
674 public ExprSequence SwitchExpr {
675 get { return switchExpr; }
678 public CaseClauseList Cases {
679 get { return caseList; }
682 public XmlQualifiedName DefaultVarName {
683 get { return defaultVarName; }
686 public ExprSingle DefaultReturn {
687 get { return defaultReturn; }
688 set { defaultReturn = value; }
691 internal override void CheckReference (XQueryASTCompiler compiler)
693 switchExpr.CheckReference (compiler);
694 foreach (CaseClause cc in caseList) {
695 compiler.CheckSchemaType (cc.Type);
696 cc.Expr.CheckReference (compiler);
698 defaultReturn.CheckReference (compiler);
701 #region CompileAndEvaluate
702 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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;
712 // FIXME: it can be optimized by checking all case clauses.
713 public override SequenceType StaticType {
714 get { return SequenceType.AnyType; }
717 public override XPathSequence Evaluate (XPathSequence iter)
719 // FIXME: should move to iterator?
720 XPathSequence cond = new ExprSequenceIterator (iter, SwitchExpr);
721 XPathSequence ret = null;
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;
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;
742 #endregion
745 internal class CaseClauseList : CollectionBase
747 public void Insert (int pos, CaseClause cc)
749 List.Insert (pos, cc);
752 public void Add (CaseClause cc)
754 List.Add (cc);
757 public CaseClause this [int i] {
758 get { return (CaseClause) List [i]; }
762 internal class CaseClause
764 public CaseClause (SequenceType type, ExprSingle expr, XmlQualifiedName varName)
766 this.type = type;
767 this.expr = expr;
768 this.varName = varName;
771 SequenceType type;
772 ExprSingle expr;
773 XmlQualifiedName varName;
775 public SequenceType Type {
776 get { return type; }
779 public ExprSingle Expr {
780 get { return expr; }
781 set { expr = value; }
784 public XmlQualifiedName VarName {
785 get { return varName; }
786 set { varName = value; }
790 // IfExpr
792 internal class IfExpr : ExprSingle
794 public IfExpr (ExprSequence condition, ExprSingle trueExpr, ExprSingle falseExpr)
796 this.condition = new ParenthesizedExpr (condition);
797 this.trueExpr = trueExpr;
798 this.falseExpr = falseExpr;
801 ExprSingle condition;
802 ExprSingle trueExpr;
803 ExprSingle falseExpr;
805 public ExprSingle Condition {
806 get { return condition; }
807 set { condition = value; }
810 public ExprSingle TrueExpr {
811 get { return trueExpr; }
812 set { trueExpr = value; }
815 public ExprSingle FalseExpr {
816 get { return falseExpr; }
817 set { falseExpr = value; }
820 internal override void CheckReference (XQueryASTCompiler compiler)
822 condition.CheckReference (compiler);
823 trueExpr.CheckReference (compiler);
824 falseExpr.CheckReference (compiler);
827 #region CompileAndEvaluate
828 SequenceType computedReturnType;
830 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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;
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;
849 public override XPathSequence Evaluate (XPathSequence iter)
851 if (condition.EvaluateAsBoolean (iter))
852 return TrueExpr.Evaluate (iter);
853 return FalseExpr.Evaluate (iter);
855 #endregion
859 // logical expr
861 internal abstract class BinaryOperationExpr : ExprSingle
863 protected BinaryOperationExpr (ExprSingle left, ExprSingle right)
865 this.left = left;
866 this.right = right;
869 ExprSingle left, right;
871 public ExprSingle Left {
872 get { return left; }
873 set { left = value; }
876 public ExprSingle Right{
877 get { return right; }
878 set { right = value; }
881 internal override void CheckReference (XQueryASTCompiler compiler)
883 left.CheckReference (compiler);
884 right.CheckReference (compiler);
887 #region CompileAndEvaluate
888 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
890 Left = Left.Compile (compiler);
891 Right = Right.Compile (compiler);
892 return this;
894 #endregion
898 internal class OrExpr : BinaryOperationExpr
900 public OrExpr (ExprSingle left, ExprSingle right)
901 : base (left, right)
905 #region CompileAndEvaluate
906 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
908 base.CompileCore (compiler);
909 // FIXME: check constant value and return true or false
910 return this;
913 public override SequenceType StaticType {
914 get { return SequenceType.Boolean; }
917 public override bool EvaluateAsBoolean (XPathSequence iter)
919 return Left.EvaluateAsBoolean (iter) || Right.EvaluateAsBoolean (iter);
922 public override XPathSequence Evaluate (XPathSequence iter)
924 return new SingleItemIterator (EvaluateAsBoolean (iter) ?AtomicTrue : AtomicFalse, iter.Context);
928 - compiler -
929 return leftExprBool (context) || rightExprBool (context);
931 #endregion
934 internal class AndExpr : BinaryOperationExpr
936 public AndExpr (ExprSingle left, ExprSingle right)
937 : base (left, right)
941 #region CompileAndEvaluate
942 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
944 base.CompileCore (compiler);
945 // FIXME: check constant value and return true or false
946 return this;
949 public override SequenceType StaticType {
950 get { return SequenceType.Boolean; }
953 public override bool EvaluateAsBoolean (XPathSequence iter)
955 return Left.EvaluateAsBoolean (iter) && Right.EvaluateAsBoolean (iter);
958 public override XPathSequence Evaluate (XPathSequence iter)
960 return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
964 - compiler -
965 return leftExprBool (context) && rightExprBool (context);
967 #endregion
970 // TypeOperation expr
972 internal abstract class TypeOperationExpr : ExprSingle
974 protected TypeOperationExpr (ExprSingle expr, SequenceType type)
976 this.expr = expr;
977 this.type = type;
980 ExprSingle expr;
981 SequenceType type;
983 public ExprSingle Expr {
984 get { return expr; }
985 set { expr = value; }
988 public SequenceType TargetType {
989 get { return type; }
992 internal override void CheckReference (XQueryASTCompiler compiler)
994 expr.CheckReference (compiler);
995 compiler.CheckSchemaType (type);
999 internal abstract class AtomicTypeOperationExpr : ExprSingle
1001 protected AtomicTypeOperationExpr (ExprSingle expr, XmlTypeCode type, bool optional)
1003 this.expr = expr;
1004 this.targetType = SequenceType.Create (type, optional ? Occurence.Optional : Occurence.One);
1007 ExprSingle expr;
1008 SequenceType targetType;
1010 internal ExprSingle Expr {
1011 get { return expr; }
1012 set { expr = value; }
1016 public XmlTypeCode TypeCode {
1017 get { return typeCode; }
1020 public bool Optional {
1021 get { return optional; }
1024 internal SequenceType TargetType {
1025 get { return targetType; }
1028 internal override void CheckReference (XQueryASTCompiler compiler)
1030 expr.CheckReference (compiler);
1034 internal class InstanceOfExpr : TypeOperationExpr
1036 public InstanceOfExpr (ExprSingle expr, SequenceType type)
1037 : base (expr, type)
1041 #region CompileAndEvaluate
1042 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1044 Expr = Expr.Compile (compiler);
1045 // FIXME: check return type and if it never matches then return false
1046 return this;
1049 public override SequenceType StaticType {
1050 get { return SequenceType.Boolean; }
1053 public override bool EvaluateAsBoolean (XPathSequence iter)
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;
1064 return occured || !required;
1067 public override XPathSequence Evaluate (XPathSequence iter)
1069 return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context);
1071 #endregion
1074 internal class TreatExpr : TypeOperationExpr
1076 public TreatExpr (ExprSingle expr, SequenceType type)
1077 : base (expr, type)
1081 #region CompileAndEvaluate
1082 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1084 Expr = Expr.Compile (compiler);
1085 // FIXME: check return type and if it never matches then return false
1086 return this;
1089 public override SequenceType StaticType {
1090 get { return SequenceType.AnyType; }
1093 public override XPathSequence Evaluate (XPathSequence iter)
1095 if (TargetType.CanConvert (iter))
1096 return iter;
1097 else
1098 throw new XmlQueryException (String.Format ("Cannot treat as {1}", TargetType));
1100 #endregion
1103 internal class CastableExpr : AtomicTypeOperationExpr
1105 public CastableExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional)
1106 : base (expr, atomicType, optional)
1110 #region CompileAndEvaluate
1111 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1113 Expr = Expr.Compile (compiler);
1114 // FIXME: check return type and if it never matches then return boolean
1115 return this;
1118 public override SequenceType StaticType {
1119 get { return SequenceType.Boolean; }
1122 public override XPathSequence Evaluate (XPathSequence iter)
1124 return new SingleItemIterator (new XPathAtomicValue (EvaluateAsBoolean (iter), XmlSchemaSimpleType.XsBoolean), iter.Context);
1127 public override bool EvaluateAsBoolean (XPathSequence iter)
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;
1138 return occured || !required;
1140 #endregion
1143 internal class CastExpr : AtomicTypeOperationExpr
1145 public CastExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional)
1146 : base (expr, atomicType, optional)
1150 #region CompileAndEvaluate
1151 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1153 Expr = Expr.Compile (compiler);
1154 // FIXME: check return type and if it never matches then return boolean
1155 return this;
1158 public override SequenceType StaticType {
1159 get { return TargetType; }
1162 public override XPathSequence Evaluate (XPathSequence iter)
1164 if (TargetType.CanConvert (iter))
1165 return new ConvertingIterator (iter, TargetType);
1166 else
1167 throw new XmlQueryException (String.Format ("Cannot cast as {1}", TargetType));
1169 #endregion
1172 // ComparisonExpr
1174 internal class ComparisonExpr : BinaryOperationExpr
1176 public ComparisonExpr (ExprSingle left, ExprSingle right, ComparisonOperator oper)
1177 : base (left, right)
1179 this.oper = oper;
1182 ComparisonOperator oper;
1184 public ComparisonOperator Operation {
1185 get { return oper; }
1188 #region CompileAndEvaluate
1189 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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;
1197 public override SequenceType StaticType {
1198 get { return SequenceType.Boolean; }
1201 public override XPathSequence Evaluate (XPathSequence iter)
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);
1210 public override bool EvaluateAsBoolean (XPathSequence iter)
1212 bool isEmpty;
1213 return EvaluateAsBoolean (iter, out isEmpty);
1216 private bool EvaluateAsBoolean (XPathSequence iter, out bool isEmpty)
1218 XPathSequence lseq, rseq;
1219 isEmpty = false;
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;
1235 return CompareAtomic (itemVL, itemVR);
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;
1251 return false;
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;
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;
1270 break;
1272 throw new SystemException ("XQuery internal error: should not happen.");
1275 // returns null if sequence was empty
1276 private XPathItem ExamineOneItem (XPathSequence seq)
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;
1286 // returns null if sequence was empty
1287 private XPathNavigator ExamineOneNode (XPathSequence seq)
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;
1297 private bool CompareAtomic (XPathItem itemL, XPathItem itemR)
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);
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);
1337 return false; // should not happen
1339 #endregion
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
1360 // Range
1362 internal class RangeExpr : BinaryOperationExpr
1364 public RangeExpr (ExprSingle left, ExprSingle right)
1365 : base (left, right)
1369 #region CompileAndEvaluate
1370 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1372 Left = Left.Compile (compiler);
1373 Right = Right.Compile (compiler);
1374 return this;
1377 public override SequenceType StaticType {
1378 get { return SequenceType.IntegerList; }
1381 public override XPathSequence Evaluate (XPathSequence iter)
1383 int start = Left.EvaluateAsInt (iter);
1384 int end = Right.EvaluateAsInt (iter);
1385 return new IntegerRangeIterator (iter.Context, start, end);
1388 public override void Serialize (XPathSequence iter)
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 (" ");
1398 #endregion
1401 // arithmetic operation expr
1403 public enum ArithmeticOperator {
1404 Add,
1405 Sub,
1406 Mul,
1407 Div,
1408 IDiv,
1409 IMod
1412 internal class ArithmeticOperationExpr : BinaryOperationExpr
1414 public ArithmeticOperationExpr (ExprSingle left, ExprSingle right, ArithmeticOperator oper)
1415 : base (left, right)
1417 this.oper = oper;
1420 ArithmeticOperator oper;
1422 public ArithmeticOperator Operation {
1423 get { return oper; }
1426 #region CompileAndEvaluate
1427 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1429 Left = Left.Compile (compiler);
1430 Right = Right.Compile (compiler);
1431 return this;
1434 // FIXME: It can be optimized by comparing l/r value types.
1435 public override SequenceType StaticType {
1436 get { return SequenceType.AnyType; }
1439 public override XPathSequence Evaluate (XPathSequence iter)
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.");
1454 // FIXME: handle "untypedAtomic to xs:double" casting
1456 return new SingleItemIterator (Compute (lvalue, rvalue), iter.Context);
1459 private XPathAtomicValue Compute (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
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.");
1478 #endregion
1481 internal class MinusExpr : ExprSingle
1483 public MinusExpr (ExprSingle expr)
1485 this.expr = expr;
1488 ExprSingle expr;
1490 public ExprSingle Expr {
1491 get { return expr; }
1492 set { expr = value; }
1495 internal override void CheckReference (XQueryASTCompiler compiler)
1497 expr.CheckReference (compiler);
1500 #region CompileAndEvaluate
1501 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1503 return new ArithmeticOperationExpr (new DecimalLiteralExpr (-1), Expr, ArithmeticOperator.Mul).Compile (compiler);
1506 public override SequenceType StaticType {
1507 get { return Expr.StaticType; }
1510 public override XPathSequence Evaluate (XPathSequence iter)
1512 throw new SystemException ("XQuery internal error: should not happen.");
1514 #endregion
1517 // aggregation expr
1519 public enum AggregationType {
1520 Union,
1521 Intersect,
1522 Except
1525 internal class GroupExpr : BinaryOperationExpr
1527 public GroupExpr (ExprSingle left, ExprSingle right, AggregationType aggrType)
1528 : base (left, right)
1530 this.aggrType = aggrType;
1533 AggregationType aggrType;
1535 public AggregationType AggregationType {
1536 get { return aggrType; }
1539 #region CompileAndEvaluate
1540 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1542 Left = Left.Compile (compiler);
1543 Right = Right.Compile (compiler);
1544 return this;
1547 // FIXME: It can be optimized by comparing l/r value types.
1548 public override SequenceType StaticType {
1549 get { return SequenceType.AnyType; }
1552 // only applicable against node-sets
1553 public override XPathSequence Evaluate (XPathSequence iter)
1555 return new GroupIterator (iter, this);
1557 #endregion
1560 // validate expr
1562 internal class ValidateExpr : ExprSingle
1564 XmlSchemaContentProcessing schemaMode;
1565 ExprSequence expr;
1567 public ValidateExpr (XmlSchemaContentProcessing schemaMode, ExprSequence expr)
1569 this.schemaMode = schemaMode;
1570 this.expr = expr;
1573 public ExprSequence Expr {
1574 get { return expr; }
1577 public XmlSchemaContentProcessing SchemaMode {
1578 get { return schemaMode; }
1581 internal override void CheckReference (XQueryASTCompiler compiler)
1583 expr.CheckReference (compiler);
1586 #region CompileAndEvaluate
1587 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1589 for (int i = 0; i < expr.Count; i++)
1590 expr [i] = expr [i].Compile (compiler);
1591 return this;
1594 public override SequenceType StaticType {
1595 get { return SequenceType.AnyType; }
1598 public override XPathSequence Evaluate (XPathSequence iter)
1600 // TBD (see 3.13).
1601 throw new NotImplementedException ();
1603 #endregion
1606 // Path expr
1608 internal abstract class PathExpr : ExprSingle
1612 // '/'
1613 internal class PathRootExpr : PathExpr
1615 public PathRootExpr ()
1619 internal override void CheckReference (XQueryASTCompiler compiler)
1623 #region CompileAndEvaluate
1624 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1626 return this;
1629 public override SequenceType StaticType {
1630 get { return SequenceType.Document; }
1633 public override XPathSequence Evaluate (XPathSequence iter)
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);
1642 #endregion
1645 internal abstract class PathStepExpr : PathExpr
1647 ExprSingle first;
1648 ExprSingle next;
1650 public PathStepExpr (ExprSingle first, ExprSingle next)
1652 this.first = first;
1653 this.next = next;
1656 public ExprSingle First {
1657 get { return first; }
1658 set { first = value; }
1661 public ExprSingle Next {
1662 get { return next; }
1663 set { next = value; }
1666 internal override void CheckReference (XQueryASTCompiler compiler)
1668 first.CheckReference (compiler);
1669 next.CheckReference (compiler);
1672 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1674 first = first.Compile (compiler);
1675 next = next.Compile (compiler);
1676 return this;
1681 // 'foo/bar'
1682 internal class PathSlashExpr : PathStepExpr
1684 public PathSlashExpr (ExprSingle first, ExprSingle next)
1685 : base (first, next)
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; }
1695 public override XPathSequence Evaluate (XPathSequence iter)
1697 return new PathStepIterator (First.Evaluate (iter), this);
1699 #endregion
1702 // 'foo//bar'
1703 internal class PathSlash2Expr : PathStepExpr
1705 public PathSlash2Expr (ExprSingle first, ExprSingle next)
1706 : base (first, next)
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; }
1716 public override XPathSequence Evaluate (XPathSequence iter)
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);
1724 #endregion
1727 internal class AxisStepExpr : PathExpr
1729 public AxisStepExpr (XPathAxis axis, XPath2NodeTest test)
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;
1742 XPathAxis axis;
1743 XmlQualifiedName nameTest;
1744 KindTest kindTest;
1746 public XPathAxis Axis {
1747 get { return axis; }
1750 public XmlQualifiedName NameTest {
1751 get { return nameTest; }
1752 set { nameTest = value; }
1755 public KindTest KindTest {
1756 get { return kindTest; }
1757 set { kindTest = value; }
1760 internal override void CheckReference (XQueryASTCompiler compiler)
1762 if (KindTest != null)
1763 KindTest.CheckReference (compiler);
1766 #region CompileAndEvaluate
1767 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1769 if (KindTest != null)
1770 KindTest.Compile (compiler);
1771 return this;
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;
1782 // FIXME: we can more filtering by KindTest
1783 return SequenceType.Node;
1787 public override XPathSequence Evaluate (XPathSequence iter)
1789 XQueryContext ctx = iter.Context;
1791 if (iter.Position == 0) {
1792 iter = iter.Clone ();
1793 if (!iter.MoveNext ())
1794 return new XPathEmptySequence (iter.Context);
1797 XPathNavigator nav = iter.Current as XPathNavigator;
1798 if (nav == null)
1799 throw new XmlQueryException ("Node set is expected.");
1801 NodeIterator argIter = null;
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;
1831 return new AxisIterator (argIter, this);
1834 internal bool Matches (XPathNavigator nav)
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);
1843 #endregion
1846 internal class FilterStepExpr : PathExpr
1848 public FilterStepExpr (ExprSingle expr, ExprSequence predicate)
1850 this.expr = expr;
1851 this.predicate = predicate;
1854 ExprSingle expr;
1855 ExprSequence predicate;
1857 public ExprSingle Expr {
1858 get { return expr; }
1859 set { expr = value; }
1862 public ExprSequence Predicate {
1863 get { return predicate; }
1866 internal override void CheckReference (XQueryASTCompiler compiler)
1868 expr.CheckReference (compiler);
1869 predicate.CheckReference (compiler);
1872 #region CompileAndEvaluate
1873 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1875 Expr = Expr.Compile (compiler);
1876 for (int i = 0; i < predicate.Count; i++)
1877 predicate [i] = predicate [i].Compile (compiler);
1878 return this;
1881 public override SequenceType StaticType {
1882 get { return Expr.StaticType; }
1885 public override XPathSequence Evaluate (XPathSequence iter)
1887 return new FilteredIterator (iter, this);
1889 #endregion
1893 // predicates == exprsequence list == list of list of exprsingle
1894 internal class PredicateList : CollectionBase
1896 public void Add (ExprSequence expr)
1898 List.Add (expr);
1901 public void Insert (int pos, ExprSequence expr)
1903 List.Insert (pos, expr);
1906 public ExprSequence this [int i] {
1907 get { return (ExprSequence) List [i]; }
1912 internal class XPath2NodeTest
1914 public XPath2NodeTest (XmlQualifiedName nameTest)
1916 this.NameTest = nameTest;
1919 public XPath2NodeTest (KindTest kindTest)
1921 this.KindTest = kindTest;
1924 public XmlQualifiedName NameTest;
1926 public KindTest KindTest;
1929 internal class EnclosedExpr : ExprSingle
1931 ExprSequence expr;
1933 public EnclosedExpr (ExprSequence expr)
1935 this.expr = expr;
1938 public ExprSequence Expr {
1939 get { return expr; }
1942 internal override void CheckReference (XQueryASTCompiler compiler)
1944 expr.CheckReference (compiler);
1947 #region CompileAndEvaluate
1948 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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;
1957 // FIXME: can be optimized by checking all items in Expr
1958 public override SequenceType StaticType {
1959 get { return SequenceType.AnyType; }
1962 public override XPathSequence Evaluate (XPathSequence iter)
1964 return new ExprSequenceIterator (iter, Expr);
1966 #endregion
1969 // PrimaryExpr
1971 internal abstract class PrimaryExpr : ExprSingle
1973 internal override void CheckReference (XQueryASTCompiler compiler)
1977 #region CompileAndEvaluate
1978 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
1980 return this;
1983 public override XPathSequence Evaluate (XPathSequence iter)
1985 return new SingleItemIterator (EvaluateAsAtomic (iter), iter.Context);
1987 #endregion
1990 internal class StringLiteralExpr : PrimaryExpr
1992 string literal;
1994 public StringLiteralExpr (string literal)
1996 this.literal = literal;
1999 public string Literal {
2000 get { return literal; }
2003 #region CompileAndEvaluate
2004 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("string", XmlSchema.Namespace));
2006 public override SequenceType StaticType {
2007 get { return SequenceType.AtomicString; }
2010 public override string EvaluateAsString (XPathSequence iter)
2012 return Literal;
2015 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2017 return new XPathAtomicValue (Literal, stringType);
2019 #endregion
2022 internal class DecimalLiteralExpr : PrimaryExpr
2024 decimal value;
2026 public DecimalLiteralExpr (decimal value)
2028 this.value = value;
2031 public decimal Value {
2032 get { return value; }
2035 #region CompileAndEvaluate
2036 XmlSchemaSimpleType decimalType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("decimal", XmlSchema.Namespace));
2038 public override SequenceType StaticType {
2039 get { return SequenceType.Decimal; }
2042 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2044 return new XPathAtomicValue (Value, decimalType);
2046 #endregion
2049 internal class DoubleLiteralExpr : PrimaryExpr
2051 double value;
2053 public DoubleLiteralExpr (double value)
2055 this.value = value;
2058 public double Value {
2059 get { return value; }
2062 #region CompileAndEvaluate
2063 XmlSchemaSimpleType doubleType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("double", XmlSchema.Namespace));
2065 public override SequenceType StaticType {
2066 get { return SequenceType.Double; }
2069 public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter)
2071 return new XPathAtomicValue (Value, doubleType);
2073 #endregion
2076 internal class VariableReferenceExpr : PrimaryExpr
2078 XmlQualifiedName varName;
2080 public VariableReferenceExpr (XmlQualifiedName varName)
2082 this.varName = varName;
2085 public XmlQualifiedName VariableName {
2086 get { return varName; }
2089 // FIXME: variable name must be stacked in any area
2090 // whereever variables are defined.
2091 internal override void CheckReference (XQueryASTCompiler compiler)
2093 compiler.CheckVariableName (varName);
2096 #region CompileAndEvaluate
2097 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2099 // FIXME: try to resolve static context variable and return the actual value expression
2100 return this;
2103 public override SequenceType StaticType {
2104 get { return SequenceType.AnyType; }
2107 public override XPathSequence Evaluate (XPathSequence iter)
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;
2113 #endregion
2116 internal class ParenthesizedExpr : PrimaryExpr
2118 ExprSequence expr;
2120 public ParenthesizedExpr (ExprSequence expr)
2122 if (expr == null)
2123 expr = new ExprSequence ();
2124 this.expr = expr;
2127 ExprSequence Expr {
2128 get { return expr; }
2131 #region CompileAndEvaluate
2132 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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;
2141 // FIXME: can be optimized by checking all items in Expr
2142 public override SequenceType StaticType {
2143 get { return SequenceType.AnyType; }
2146 public override XPathSequence Evaluate (XPathSequence iter)
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);
2157 #endregion
2160 // "."
2161 internal class ContextItemExpr : PrimaryExpr
2163 public ContextItemExpr ()
2167 #region CompileAndEvaluate
2168 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2170 return this;
2173 public override SequenceType StaticType {
2174 get { return SequenceType.AnyType; }
2177 public override XPathSequence Evaluate (XPathSequence iter)
2179 return new SingleItemIterator (iter.Context.CurrentItem, iter.Context);
2181 #endregion
2184 internal abstract class FunctionCallExprBase : PrimaryExpr
2186 XmlQualifiedName name;
2187 ExprSequence args;
2189 public FunctionCallExprBase (XmlQualifiedName name, ExprSequence args)
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;
2197 public XmlQualifiedName Name {
2198 get { return name; }
2201 public ExprSequence Args {
2202 get { return args; }
2205 internal override void CheckReference (XQueryASTCompiler compiler)
2207 compiler.CheckFunctionName (name);
2210 #region CompileAndEvaluate
2212 internal static DefaultFunctionCall Create (
2213 XmlQualifiedName name,
2214 ExprSingle [] args,
2215 XQueryStaticContext ctx)
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);
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;
2270 internal void CheckArguments (XQueryASTCompiler compiler)
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));
2277 public abstract int MinArgs { get; }
2278 public abstract int MaxArgs { get; }
2279 #endregion
2282 internal class FunctionCallExpr : FunctionCallExprBase
2284 public FunctionCallExpr (XmlQualifiedName name, ExprSequence args)
2285 : base (name, args)
2289 XQueryFunction function;
2291 public XQueryFunction Function {
2292 get { return function; }
2295 #region CompileAndEvaluate
2296 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
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;
2306 public override int MinArgs {
2307 get { return function.MinArgs; }
2310 public override int MaxArgs {
2311 get { return function.MaxArgs; }
2314 public override SequenceType StaticType {
2315 get { return function.ReturnType; }
2318 public override XPathSequence Evaluate (XPathSequence iter)
2320 return Function.Evaluate (iter, Args);
2323 // FIXME: add all overrides that delegates to XQueryFunction
2324 #endregion
2328 #region CompileAndEvaluate
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
2335 public CustomFunctionCallExpr (ExprSequence args, XQueryFunction function)
2336 : base (function.Name, args)
2338 this.function = function;
2341 XQueryFunction function;
2343 public XQueryFunction Function {
2344 get { return function; }
2347 public override int MinArgs {
2348 get { return function.MinArgs; }
2351 public override int MaxArgs {
2352 get { return function.MaxArgs; }
2355 public override SequenceType StaticType {
2356 get { return function.ReturnType; }
2359 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2361 CheckArguments (compiler);
2362 for (int i = 0; i < Args.Count; i++)
2363 Args [i] = Args [i].Compile (compiler);
2364 return this;
2367 public override XPathSequence Evaluate (XPathSequence iter)
2369 return Function.Evaluate (iter, Args);
2372 // FIXME: add all overrides that delegates to XQueryFunction
2374 #endregion
2377 // Ordered / Unordered
2378 internal class OrderSpecifiedExpr : ExprSingle
2380 bool ordered;
2381 ExprSequence expr;
2383 public OrderSpecifiedExpr (ExprSequence expr, bool ordered)
2385 this.ordered = ordered;
2386 this.expr = expr;
2389 public ExprSequence Expr {
2390 get { return expr; }
2393 public bool Ordered {
2394 get { return ordered; }
2397 internal override void CheckReference (XQueryASTCompiler compiler)
2399 expr.CheckReference (compiler);
2402 #region CompileAndEvaluate
2403 public override SequenceType StaticType {
2404 // FIXME: could be optimized by checking all the expressions
2405 get { return SequenceType.AnyType; }
2408 public override bool RequireSorting {
2409 get { return Ordered; }
2412 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
2414 for (int i = 0; i < Expr.Count; i++)
2415 Expr [i] = Expr [i].Compile (compiler);
2416 return this;
2419 public override XPathSequence Evaluate (XPathSequence iter)
2421 throw new NotImplementedException ();
2423 #endregion
2427 #endif