1 //---------------------------------------------------------------------
2 // <copyright file="Rule.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
12 using System.Diagnostics;
13 using System.Globalization;
15 namespace System.Data.Query.InternalTrees
18 /// A Rule - more specifically, a transformation rule - describes an action that is to
19 /// be taken when a specific kind of subtree is found in the tree
21 internal abstract class Rule
24 /// The "callback" function for each rule.
25 /// Every callback function must return true if the subtree has
26 /// been modified (or a new subtree has been returned); and must return false
27 /// otherwise. If the root of the subtree has not changed, but some internal details
28 /// of the subtree have changed, it is the responsibility of the rule to update any
29 /// local bookkeeping information.
31 /// <param name="context">The rule processing context</param>
32 /// <param name="subTree">the subtree to operate on</param>
33 /// <param name="newSubTree">possibly transformed subtree</param>
34 /// <returns>transformation status - true, if there was some change; false otherwise</returns>
35 internal delegate bool ProcessNodeDelegate(RuleProcessingContext context, Node subTree, out Node newSubTree);
38 private ProcessNodeDelegate m_nodeDelegate;
39 private OpType m_opType;
46 /// <param name="opType">The OpType we're interested in processing</param>
47 /// <param name="nodeProcessDelegate">The callback to invoke</param>
48 protected Rule(OpType opType, ProcessNodeDelegate nodeProcessDelegate)
50 Debug.Assert(nodeProcessDelegate != null, "null process delegate");
51 Debug.Assert(opType != OpType.NotValid, "bad OpType");
52 Debug.Assert(opType != OpType.Leaf, "bad OpType - Leaf");
55 m_nodeDelegate = nodeProcessDelegate;
59 #region protected methods
63 #region public methods
65 /// Does the rule match the current node?
67 /// <param name="node">the node in question</param>
68 /// <returns>true, if a match was found</returns>
69 internal abstract bool Match(Node node);
72 /// We need to invoke the specified callback on the subtree in question - but only
73 /// if the match succeeds
75 /// <param name="ruleProcessingContext">Current rule processing context</param>
76 /// <param name="node">The node (subtree) to process</param>
77 /// <param name="newNode">the (possibly) modified subtree</param>
78 /// <returns>true, if the subtree was modified</returns>
79 internal bool Apply(RuleProcessingContext ruleProcessingContext, Node node, out Node newNode)
81 // invoke the real callback
82 return m_nodeDelegate(ruleProcessingContext, node, out newNode);
86 /// The OpType we're interested in transforming
88 internal OpType RuleOpType
90 get { return m_opType; }
95 /// The method name for the rule
97 internal string MethodName
99 get { return m_nodeDelegate.Method.Name; }
107 /// A SimpleRule is a rule that specifies a specific OpType to look for, and an
108 /// appropriate action to take when such an Op is identified
110 internal sealed class SimpleRule : Rule
112 #region private state
117 /// Basic constructor.
119 /// <param name="opType">The OpType we're interested in</param>
120 /// <param name="processDelegate">The callback to invoke when we see such an Op</param>
121 internal SimpleRule(OpType opType, ProcessNodeDelegate processDelegate)
122 : base(opType, processDelegate)
127 #region overriden methods
128 internal override bool Match(Node node)
130 return node.Op.OpType == this.RuleOpType;
136 /// A PatternMatchRule allows for a pattern to be specified to identify interesting
137 /// subtrees, rather than just an OpType
139 internal sealed class PatternMatchRule: Rule
141 #region private state
142 private Node m_pattern;
147 /// Basic constructor
149 /// <param name="pattern">The pattern to look for</param>
150 /// <param name="processDelegate">The callback to invoke when such a pattern is identified</param>
151 internal PatternMatchRule(Node pattern, ProcessNodeDelegate processDelegate)
152 : base(pattern.Op.OpType, processDelegate)
154 Debug.Assert(pattern != null, "null pattern");
155 Debug.Assert(pattern.Op != null, "null pattern Op");
160 #region private methods
161 private bool Match(Node pattern, Node original)
163 if (pattern.Op.OpType == OpType.Leaf)
165 if (pattern.Op.OpType != original.Op.OpType)
167 if (pattern.Children.Count != original.Children.Count)
169 for (int i = 0; i < pattern.Children.Count; i++)
170 if (!Match(pattern.Children[i], original.Children[i]))
176 #region overridden methods
177 internal override bool Match(Node node)
179 return Match(m_pattern, node);