1 //------------------------------------------------------------------------------
2 // <copyright file="QilPatternFactory.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 using System
.Collections
.Generic
;
9 using System
.Diagnostics
;
10 using System
.Reflection
;
11 using System
.Xml
.Schema
;
13 namespace System
.Xml
.Xsl
.Qil
{
16 /// Additional factory methods for constructing common QIL patterns.
19 /// Some of the methods here are exactly like the ones in QilFactory except
20 /// that they perform constant-folding and other normalization. Others are
21 /// "macro patterns" that simplify the task of constructing otherwise complex patterns.
23 internal class QilPatternFactory
{
27 public QilPatternFactory(QilFactory f
, bool debug
) {
28 Debug
.Assert(f
!= null);
33 public QilFactory BaseFactory { get { return f; }
}
34 public bool IsDebug { get { return this.debug; }
}
36 #region Convenience methods
38 public QilLiteral
String(string val
) {
39 return f
.LiteralString(val
);
42 public QilLiteral
Int32(int val
) {
43 return f
.LiteralInt32(val
);
46 public QilLiteral
Double(double val
) {
47 return f
.LiteralDouble(val
);
50 public QilName
QName(string local
, string uri
, string prefix
) {
51 return f
.LiteralQName(local
, uri
, prefix
);
54 public QilName
QName(string local
, string uri
) {
55 return f
.LiteralQName(local
, uri
, System
.String
.Empty
);
58 public QilName
QName(string local
) {
59 return f
.LiteralQName(local
, System
.String
.Empty
, System
.String
.Empty
);
62 public QilNode
Unknown(XmlQueryType t
) {
68 //-----------------------------------------------
70 //-----------------------------------------------
71 public QilExpression
QilExpression(QilNode root
, QilFactory factory
) {
72 return f
.QilExpression(root
, factory
);
75 public QilList
FunctionList() {
76 return f
.FunctionList();
79 public QilList
GlobalVariableList() {
80 return f
.GlobalVariableList();
83 public QilList
GlobalParameterList() {
84 return f
.GlobalParameterList();
87 public QilList
ActualParameterList() {
88 return f
.ActualParameterList();
91 public QilList
ActualParameterList(QilNode arg1
) {
92 QilList result
= f
.ActualParameterList();
97 public QilList
ActualParameterList(QilNode arg1
, QilNode arg2
) {
98 QilList result
= f
.ActualParameterList();
104 public QilList
ActualParameterList(params QilNode
[] args
) {
105 return f
.ActualParameterList(args
);
108 public QilList
FormalParameterList() {
109 return f
.FormalParameterList();
112 public QilList
FormalParameterList(QilNode arg1
) {
113 QilList result
= f
.FormalParameterList();
118 public QilList
FormalParameterList(QilNode arg1
, QilNode arg2
) {
119 QilList result
= f
.FormalParameterList();
125 public QilList
FormalParameterList(params QilNode
[] args
) {
126 return f
.FormalParameterList(args
);
129 public QilList
SortKeyList() {
130 return f
.SortKeyList();
133 public QilList
SortKeyList(QilSortKey key
) {
134 QilList list
= f
.SortKeyList();
139 public QilList
BranchList(params QilNode
[] args
) {
140 return f
.BranchList(args
);
143 public QilNode
OptimizeBarrier(QilNode child
) {
144 return f
.OptimizeBarrier(child
);
150 //-----------------------------------------------
152 //-----------------------------------------------
153 public QilNode
DataSource(QilNode name
, QilNode baseUri
) {
154 return f
.DataSource(name
, baseUri
);
157 public QilNode
Nop(QilNode child
) {
161 public QilNode
Error(QilNode text
) {
162 return f
.Error(text
);
165 public QilNode
Warning(QilNode text
) {
166 return f
.Warning(text
);
169 #endregion // specials
172 //-----------------------------------------------
174 //-----------------------------------------------
175 public QilIterator
For(QilNode binding
) {
176 return f
.For(binding
);
179 public QilIterator
Let(QilNode binding
) {
180 return f
.Let(binding
);
183 public QilParameter
Parameter(XmlQueryType t
) {
184 return f
.Parameter(t
);
187 public QilParameter
Parameter(QilNode defaultValue
, QilName name
, XmlQueryType t
) {
188 return f
.Parameter(defaultValue
, name
, t
);
191 public QilNode
PositionOf(QilIterator expr
) {
192 return f
.PositionOf(expr
);
195 #endregion // variables
198 //-----------------------------------------------
200 //-----------------------------------------------
201 public QilNode
True() {
205 public QilNode
False() {
209 public QilNode
Boolean(bool b
) {
210 return b
? this.True() : this.False();
213 #endregion // literals
215 #region boolean operators
216 //-----------------------------------------------
218 //-----------------------------------------------
220 // ToDo: Why we have nulls here at all?
221 private static void CheckLogicArg(QilNode arg
) {
222 Debug
.Assert(arg
!= null, "Argulent shouldn't be null");
223 Debug
.Assert(arg
.XmlType
.TypeCode
== XmlTypeCode
.Boolean
&& arg
.XmlType
.IsSingleton
,
224 "The operand must be boolean-typed"
228 public QilNode
And(QilNode left
, QilNode right
) {
230 CheckLogicArg(right
);
233 // True, True => True (right) other, True => other (left)
234 // True, False => False (right) other, False => False (right)
235 // True, other => other (right) other, other => And
236 if (left
.NodeType
== QilNodeType
.True
|| right
.NodeType
== QilNodeType
.False
) {
239 if (left
.NodeType
== QilNodeType
.False
|| right
.NodeType
== QilNodeType
.True
) {
243 return f
.And(left
, right
);
246 public QilNode
Or(QilNode left
, QilNode right
) {
248 CheckLogicArg(right
);
251 // True, True => True (left) other, True => True (right)
252 // True, False => True (left) other, False => other (left)
253 // True, other => True (left) other, other => Or
254 if (left
.NodeType
== QilNodeType
.True
|| right
.NodeType
== QilNodeType
.False
) {
257 if (left
.NodeType
== QilNodeType
.False
|| right
.NodeType
== QilNodeType
.True
) {
261 return f
.Or(left
, right
);
264 public QilNode
Not(QilNode child
) {
266 switch (child
.NodeType
) {
267 case QilNodeType
.True
:
269 case QilNodeType
.False
:
271 case QilNodeType
.Not
:
272 return ((QilUnary
) child
).Child
;
278 #endregion // boolean operators
281 //-----------------------------------------------
283 //-----------------------------------------------
285 public QilNode
Conditional(QilNode condition
, QilNode trueBranch
, QilNode falseBranch
) {
287 switch (condition
.NodeType
) {
288 case QilNodeType
.True
:
290 case QilNodeType
.False
:
292 case QilNodeType
.Not
:
293 return this.Conditional(((QilUnary
)condition
).Child
, falseBranch
, trueBranch
);
296 return f
.Conditional(condition
, trueBranch
, falseBranch
);
299 public QilNode
Choice(QilNode expr
, QilList branches
) {
301 switch (branches
.Count
) {
303 // If expr has no side effects, it will be eliminated by optimizer
304 return f
.Loop(f
.Let(expr
), branches
[0]);
306 return f
.Conditional(f
.Eq(expr
, f
.LiteralInt32(0)), branches
[0], branches
[1]);
309 return f
.Choice(expr
, branches
);
314 #region collection operators
315 //-----------------------------------------------
316 // collection operators
317 //-----------------------------------------------
318 public QilNode
Length(QilNode child
) {
319 return f
.Length(child
);
322 public QilNode
Sequence() {
326 public QilNode
Sequence(QilNode child
) {
330 QilList res
= f
.Sequence();
335 public QilNode
Sequence(QilNode child1
, QilNode child2
) {
336 QilList res
= f
.Sequence();
342 public QilNode
Sequence(params QilNode
[] args
) {
344 switch(args
.Length
) {
345 case 0 : return f
.Sequence();
346 case 1 : return args
[0];
349 QilList res
= f
.Sequence();
350 foreach (QilNode n
in args
)
355 public QilNode
Union(QilNode left
, QilNode right
) {
356 return f
.Union(left
, right
);
359 public QilNode
Sum(QilNode collection
) {
360 return f
.Sum(collection
);
362 #endregion // collection operators
364 #region arithmetic operators
365 //-----------------------------------------------
366 // arithmetic operators
367 //-----------------------------------------------
368 public QilNode
Negate(QilNode child
) {
369 return f
.Negate(child
);
372 public QilNode
Add(QilNode left
, QilNode right
) {
373 return f
.Add(left
, right
);
376 public QilNode
Subtract(QilNode left
, QilNode right
) {
377 return f
.Subtract(left
, right
);
380 public QilNode
Multiply(QilNode left
, QilNode right
) {
381 return f
.Multiply(left
, right
);
384 public QilNode
Divide(QilNode left
, QilNode right
) {
385 return f
.Divide(left
, right
);
388 public QilNode
Modulo(QilNode left
, QilNode right
) {
389 return f
.Modulo(left
, right
);
392 #endregion // arithmetic operators
394 #region string operators
395 //-----------------------------------------------
397 //-----------------------------------------------
398 public QilNode
StrLength(QilNode str
) {
399 return f
.StrLength(str
);
402 public QilNode
StrConcat(QilNode values
) {
404 if (values
.XmlType
.IsSingleton
)
407 return f
.StrConcat(values
);
410 public QilNode
StrConcat(params QilNode
[] args
) {
411 return StrConcat((IList
<QilNode
>)args
);
414 public QilNode
StrConcat(IList
<QilNode
> args
) {
418 return f
.LiteralString(string.Empty
);
420 return StrConcat(args
[0]);
423 return StrConcat(f
.Sequence(args
));
426 public QilNode
StrParseQName(QilNode str
, QilNode ns
) {
427 return f
.StrParseQName(str
, ns
);
429 #endregion // string operators
431 #region value comparison operators
432 //-----------------------------------------------
433 // value comparison operators
434 //-----------------------------------------------
435 public QilNode
Ne(QilNode left
, QilNode right
) {
436 return f
.Ne(left
, right
);
439 public QilNode
Eq(QilNode left
, QilNode right
) {
440 return f
.Eq(left
, right
);
443 public QilNode
Gt(QilNode left
, QilNode right
) {
444 return f
.Gt(left
, right
);
447 public QilNode
Ge(QilNode left
, QilNode right
) {
448 return f
.Ge(left
, right
);
451 public QilNode
Lt(QilNode left
, QilNode right
) {
452 return f
.Lt(left
, right
);
455 public QilNode
Le(QilNode left
, QilNode right
) {
456 return f
.Le(left
, right
);
459 #endregion // value comparison operators
461 #region node comparison operators
462 //-----------------------------------------------
463 // node comparison operators
464 //-----------------------------------------------
465 public QilNode
Is(QilNode left
, QilNode right
) {
466 return f
.Is(left
, right
);
469 public QilNode
After(QilNode left
, QilNode right
) {
470 return f
.After(left
, right
);
473 public QilNode
Before(QilNode left
, QilNode right
) {
474 return f
.Before(left
, right
);
477 #endregion // node comparison operators
480 //-----------------------------------------------
482 //-----------------------------------------------
483 public QilNode
Loop(QilIterator variable
, QilNode body
) {
485 //((Loop (For $Binding) ($Binding) ) => ($binding))
486 if (body
== variable
.Binding
) {
490 return f
.Loop(variable
, body
);
493 public QilNode
Filter(QilIterator variable
, QilNode expr
) {
495 //((Filter (For $Binding) (True ) ) => ($binding))
496 if (expr
.NodeType
== QilNodeType
.True
) {
497 return variable
.Binding
;
499 // The following optimization is not safe if the iterator has side effects
500 //((Filter (For $Binding) (False) ) => (Sequence))
502 return f
.Filter(variable
, expr
);
508 //-----------------------------------------------
510 //-----------------------------------------------
511 public QilNode
Sort(QilIterator iter
, QilNode keys
) {
512 return f
.Sort(iter
, keys
);
515 public QilSortKey
SortKey(QilNode key
, QilNode collation
) {
516 return f
.SortKey(key
, collation
);
519 public QilNode
DocOrderDistinct(QilNode collection
) {
520 if (collection
.NodeType
== QilNodeType
.DocOrderDistinct
) {
523 return f
.DocOrderDistinct(collection
);
526 #endregion // sorting
528 #region function definition and invocation
529 //-----------------------------------------------
530 // function definition and invocation
531 //-----------------------------------------------
532 public QilFunction
Function(QilList args
, QilNode sideEffects
, XmlQueryType resultType
) {
533 Debug
.Assert(args
.NodeType
== QilNodeType
.FormalParameterList
);
534 return f
.Function(args
, sideEffects
, resultType
);
536 public QilFunction
Function(QilList args
, QilNode defn
, QilNode sideEffects
) {
537 Debug
.Assert(args
.NodeType
== QilNodeType
.FormalParameterList
);
538 return f
.Function(args
, defn
, sideEffects
, defn
.XmlType
);
541 public QilNode
Invoke(QilFunction func
, QilList args
) {
542 Debug
.Assert(args
.NodeType
== QilNodeType
.ActualParameterList
);
543 Debug
.Assert(func
.Arguments
.Count
== args
.Count
);
544 return f
.Invoke(func
, args
);
546 #endregion // function definition and invocation
548 #region XML navigation
549 //-----------------------------------------------
551 //-----------------------------------------------
552 public QilNode
Content(QilNode context
) {
553 return f
.Content(context
);
556 public QilNode
Parent(QilNode context
) {
557 return f
.Parent(context
);
560 public QilNode
Root(QilNode context
) {
561 return f
.Root(context
);
564 public QilNode
XmlContext() {
565 return f
.XmlContext();
568 public QilNode
Descendant(QilNode expr
) {
569 return f
.Descendant(expr
);
572 public QilNode
DescendantOrSelf(QilNode context
) {
573 return f
.DescendantOrSelf(context
);
576 public QilNode
Ancestor(QilNode expr
) {
577 return f
.Ancestor(expr
);
580 public QilNode
AncestorOrSelf(QilNode expr
) {
581 return f
.AncestorOrSelf(expr
);
584 public QilNode
Preceding(QilNode expr
) {
585 return f
.Preceding(expr
);
588 public QilNode
FollowingSibling(QilNode expr
) {
589 return f
.FollowingSibling(expr
);
592 public QilNode
PrecedingSibling(QilNode expr
) {
593 return f
.PrecedingSibling(expr
);
596 public QilNode
NodeRange(QilNode left
, QilNode right
) {
597 return f
.NodeRange(left
, right
);
600 public QilBinary
Deref(QilNode context
, QilNode id
) {
601 return f
.Deref(context
, id
);
603 #endregion // XML navigation
605 #region XML construction
606 //-----------------------------------------------
608 //-----------------------------------------------
609 public QilNode
ElementCtor(QilNode name
, QilNode content
) {
610 return f
.ElementCtor(name
, content
);
613 public QilNode
AttributeCtor(QilNode name
, QilNode val
) {
614 return f
.AttributeCtor(name
, val
);
617 public QilNode
CommentCtor(QilNode content
) {
618 return f
.CommentCtor(content
);
621 public QilNode
PICtor(QilNode name
, QilNode content
) {
622 return f
.PICtor(name
, content
);
625 public QilNode
TextCtor(QilNode content
) {
626 return f
.TextCtor(content
);
629 public QilNode
RawTextCtor(QilNode content
) {
630 return f
.RawTextCtor(content
);
633 public QilNode
DocumentCtor(QilNode child
) {
634 return f
.DocumentCtor(child
);
637 public QilNode
NamespaceDecl(QilNode prefix
, QilNode uri
) {
638 return f
.NamespaceDecl(prefix
, uri
);
641 public QilNode
RtfCtor(QilNode content
, QilNode baseUri
) {
642 return f
.RtfCtor(content
, baseUri
);
645 #endregion // XML construction
647 #region Node properties
648 //-----------------------------------------------
650 //-----------------------------------------------
651 public QilNode
NameOf(QilNode expr
) {
652 return f
.NameOf(expr
);
655 public QilNode
LocalNameOf(QilNode expr
) {
656 return f
.LocalNameOf(expr
);
659 public QilNode
NamespaceUriOf(QilNode expr
) {
660 return f
.NamespaceUriOf(expr
);
663 public QilNode
PrefixOf(QilNode expr
) {
664 return f
.PrefixOf(expr
);
667 #endregion // Node properties
669 #region Type operators
670 //-----------------------------------------------
672 //-----------------------------------------------
673 public QilNode
TypeAssert(QilNode expr
, XmlQueryType t
) {
674 return f
.TypeAssert(expr
, t
);
677 public QilNode
IsType(QilNode expr
, XmlQueryType t
) {
678 Debug
.Assert(t
!= null, "Type can't be null");
679 return f
.IsType(expr
, t
);
682 public QilNode
IsEmpty(QilNode
set) {
683 return f
.IsEmpty(set);
686 #endregion // Type operators
688 #region XPath operators
689 //-----------------------------------------------
691 //-----------------------------------------------
692 public QilNode
XPathNodeValue(QilNode expr
) {
693 return f
.XPathNodeValue(expr
);
696 public QilNode
XPathFollowing(QilNode expr
) {
697 return f
.XPathFollowing(expr
);
700 public QilNode
XPathNamespace(QilNode expr
) {
701 return f
.XPathNamespace(expr
);
704 public QilNode
XPathPreceding(QilNode expr
) {
705 return f
.XPathPreceding(expr
);
708 #endregion // XPath operators
711 //-----------------------------------------------
713 //-----------------------------------------------
714 public QilNode
XsltGenerateId(QilNode expr
) {
715 return f
.XsltGenerateId(expr
);
718 public QilNode
XsltInvokeEarlyBound(QilNode name
, MethodInfo d
, XmlQueryType t
, IList
<QilNode
> args
) {
719 QilList list
= f
.ActualParameterList();
721 return f
.XsltInvokeEarlyBound(name
, f
.LiteralObject(d
), list
, t
);
724 public QilNode
XsltInvokeLateBound(QilNode name
, IList
<QilNode
> args
) {
725 QilList list
= f
.ActualParameterList();
727 return f
.XsltInvokeLateBound(name
, list
);
730 public QilNode
XsltCopy(QilNode expr
, QilNode content
) {
731 return f
.XsltCopy(expr
, content
);
734 public QilNode
XsltCopyOf(QilNode expr
) {
735 return f
.XsltCopyOf(expr
);
738 public QilNode
XsltConvert(QilNode expr
, XmlQueryType t
) {
739 return f
.XsltConvert(expr
, t
);