Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Query / InternalTrees / Rule.cs
1 //---------------------------------------------------------------------
2 // <copyright file="Rule.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner  [....]
7 // @backupOwner [....]
8 //---------------------------------------------------------------------
9
10 using System;
11 using System.Collections.Generic;
12 using System.Diagnostics;
13 using System.Globalization;
14
15 namespace System.Data.Query.InternalTrees
16 {
17     /// <summary>
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
20     /// </summary>
21     internal abstract class Rule
22     {
23         /// <summary>
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.
30         /// </summary>
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);
36
37         #region private state
38         private ProcessNodeDelegate m_nodeDelegate;
39         private OpType m_opType;
40         #endregion
41
42         #region Constructors
43         /// <summary>
44         /// Basic constructor
45         /// </summary>
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)
49         {
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");
53
54             m_opType = opType;
55             m_nodeDelegate = nodeProcessDelegate;
56         }
57         #endregion
58
59         #region protected methods
60
61         #endregion
62
63         #region public methods
64         /// <summary>
65         /// Does the rule match the current node?
66         /// </summary>
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);
70
71         /// <summary>
72         /// We need to invoke the specified callback on the subtree in question - but only
73         /// if the match succeeds
74         /// </summary>
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)
80         {
81             // invoke the real callback
82             return m_nodeDelegate(ruleProcessingContext, node, out newNode);
83         }
84
85         /// <summary>
86         /// The OpType we're interested in transforming
87         /// </summary>
88         internal OpType RuleOpType
89         {
90             get { return m_opType; }
91         }
92
93 #if DEBUG
94         /// <summary>
95         /// The method name for the rule
96         /// </summary>
97         internal string MethodName
98         {
99             get { return m_nodeDelegate.Method.Name; }
100         }
101 #endif
102
103         #endregion
104     }
105
106     /// <summary>
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
109     /// </summary>
110     internal sealed class SimpleRule : Rule
111     {
112         #region private state
113         #endregion
114
115         #region constructors
116         /// <summary>
117         /// Basic constructor.
118         /// </summary>
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)
123         {
124         }
125         #endregion
126
127         #region overriden methods
128         internal override bool Match(Node node)
129         {
130             return node.Op.OpType == this.RuleOpType;
131         }
132         #endregion
133     }
134
135     /// <summary>
136     /// A PatternMatchRule allows for a pattern to be specified to identify interesting
137     /// subtrees, rather than just an OpType
138     /// </summary>
139     internal sealed class PatternMatchRule: Rule
140     {
141         #region private state
142         private Node m_pattern;
143         #endregion
144
145         #region constructors
146         /// <summary>
147         /// Basic constructor
148         /// </summary>
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)
153         {
154             Debug.Assert(pattern != null, "null pattern");
155             Debug.Assert(pattern.Op != null, "null pattern Op");
156             m_pattern = pattern;
157         }
158         #endregion
159
160         #region private methods
161         private bool Match(Node pattern, Node original)
162         {
163             if (pattern.Op.OpType == OpType.Leaf)
164                 return true;
165             if (pattern.Op.OpType != original.Op.OpType)
166                 return false;
167             if (pattern.Children.Count != original.Children.Count)
168                 return false;
169             for (int i = 0; i < pattern.Children.Count; i++)
170                 if (!Match(pattern.Children[i], original.Children[i]))
171                     return false;
172             return true;
173         }
174         #endregion
175
176         #region overridden methods
177         internal override bool Match(Node node)
178         {
179             return Match(m_pattern, node);
180         }
181         #endregion
182     }
183 }