Datei: NDODLL/NDOql/Expressions/OqlExpression.cs

Last Commit (28c8c45)
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Globalization;
5
6 namespace NDOql.Expressions
7 {
8 ····internal interface IManageExpression
9 ····{
10 ········void SetParent( OqlExpression exp );
11 ····}
12
13 ····/// <summary>
14 ····/// Base class for Oql expressions
15 ····/// </summary>
16 ····public class OqlExpression : IManageExpression
17 ····{
18 ········int line;
19 ········int col;
20 ········ExpressionType expressionType;
21 ········string unaryOp;
22 ········string op;
23 ········OqlExpression parent = null;
24 ········List<OqlExpression> children = new List<OqlExpression>();
25 ········object value;
26 ········Dictionary<string, object> annotations = new Dictionary<string, object>();
27
28 ········/// <summary>
29 ········/// Sets an annotation for a certain experession node
30 ········/// </summary>
31 ········/// <param name="key"></param>
32 ········/// <param name="value"></param>
33 ········public void SetAnnotation(string key, object value)
34 ········{
35 ············annotations[key] = value;
36 ········}
37
38 ········/// <summary>
39 ········/// Gets an annotation for a node
40 ········/// </summary>
41 ········/// <typeparam name="T"></typeparam>
42 ········/// <param name="key"></param>
43 ········/// <returns></returns>
44 ········public T GetAnnotation<T>( string key )
45 ········{
46 ············if (!annotations.ContainsKey( key ))
47 ················return default(T);
48
49 ············return (T)annotations[key];
50 ········}
51
52 ········/// <summary>
53 ········/// Gets or sets the line number where the expression appears
54 ········/// </summary>
55 ········public int Line
56 ········{
57 ············get { return line; }
58 ············set { line = value; }
59 ········}
60 ········/// <summary>
61 ········/// Gets or sets the column in the line where the expression appears
62 ········/// </summary>
63 ········public int Column
64 ········{
65 ············get { return col; }
66 ············set { col = value; }
67 ········}
68
69 ········/// <summary>
70 ········/// Gets or sets the expression type
71 ········/// </summary>
72 ········public ExpressionType ExpressionType
73 ········{
74 ············get { return expressionType; }
75 ············set { expressionType = value; }
76 ········}
77
78 ········void ThrowUnaryException()
79 ········{
80 ············throw new OqlExpressionException("Unary Operator doesn't fit to the type of the expression in '" + this.ToString() + "'. Line " + this.line + ", Col " + this.col);
81 ········}
82
83 ········/// <summary>
84 ········/// Gets or sets an unary operator, if one exists
85 ········/// </summary>
86 ········public string UnaryOp
87 ········{
88 ············get { return unaryOp; }
89 ············set
90 ············{
91 ················unaryOp = value;
92 ················if (unaryOp == "NOT")
93 ················{
94 ····················if (this.expressionType != ExpressionType.Boolean
95 ························&& this.expressionType != ExpressionType.Unknown)
96 ························ThrowUnaryException();
97 ················}
98 ················else if (unaryOp == "~" || unaryOp == "-" || unaryOp == "+")
99 ················{
100 ····················if (this.expressionType != ExpressionType.Number
101 ························&& this.expressionType != ExpressionType.Unknown)
102 ························ThrowUnaryException();
103 ················}
104 ············}
105 ········}
106
107 ········/// <summary>
108 ········/// Gets or sets an operator
109 ········/// </summary>
110 ········public string Operator
111 ········{
112 ············get { return op; }
113 ············set { op = value; }
114 ········}
115
116 ········bool hasBrackets;
117 ········/// <summary>
118 ········/// Gets or sets a value, which determines, if an expression should be bracketed
119 ········/// </summary>
120 ········public bool HasBrackets
121 ········{
122 ············get { return hasBrackets; }
123 ············set { hasBrackets = value; }
124 ········}
125
126 ········/// <summary>
127 ········/// Gets the child expressions
128 ········/// </summary>
129 ········public List<OqlExpression> Children
130 ········{
131 ············get { return children; }
132 ········}
133
134 ········/// <summary>
135 ········/// Gets the parent expression
136 ········/// </summary>
137 ········public OqlExpression Parent
138 ········{
139 ············get { return this.parent; }
140 ········}
141
142 ········/// <summary>
143 ········/// </summary>
144 ········/// <param name="exp"></param>
145 ········/// <remarks>
146 ········/// Since there occurs a lot of shuffling around the children during the parse process
147 ········/// we itererate through the tree after parsing and set the parent there.
148 ········/// </remarks>
149 ········void IManageExpression.SetParent( OqlExpression exp )
150 ········{
151 ············this.parent = exp;
152 ········}
153
154 ········/// <summary>
155 ········/// Gets the value of the expression
156 ········/// </summary>
157 ········public object Value
158 ········{
159 ············get { return this.value; }
160 ············set { this.value = value; }
161 ········}
162
163 ········/// <summary>
164 ········/// Constructor
165 ········/// </summary>
166 ········/// <param name="line"></param>
167 ········/// <param name="col"></param>
168 ········public OqlExpression(int line, int col)
169 ········{
170 ············this.line = line;
171 ············this.col = col;
172 ········}
173
174 ········/// <summary>
175 ········/// Determines, if an expression is a leaf in the tree.
176 ········/// </summary>
177 ········public virtual bool IsTerminating
178 ········{
179 ············get { return this.children.Count == 0; }
180 ········}
181
182 ········/// <summary>
183 ········/// Reduces an expression
184 ········/// </summary>
185 ········/// <returns></returns>
186 public OqlExpression Simplify( )
187 ········{
188 ············System.Diagnostics.Debug.Assert(this.children.Count != 0 || this.value != null);
189 ············if (this.children.Count > 1 || this.IsTerminating)
190 ················return this;
191 ············if (unaryOp != null)
192 ············{
193 ················if (this.children[0].unaryOp == null && !this.children[0].hasBrackets)
194 ················{
195 ····················this.children[0].unaryOp = this.unaryOp;
196 ····················return this.children[0];
197 ················}
198 ················else
199 ················{
200 ····················return this;
201 ················}
202 ············}
203 ············return this.children[0];
204 ········}
205
206 ········/// <summary>
207 ········/// Adds a child expressoin
208 ········/// </summary>
209 ········/// <param name="exp"></param>
210 ········public virtual void Add(OqlExpression exp)
211 ········{············
212 ············this.children.Add(exp);
213 ········}
214
215 ········/// <summary>
216 ········/// Adds a child expression and an operator
217 ········/// </summary>
218 ········/// <param name="exp"></param>
219 ········/// <param name="op"></param>
220 ········public virtual void Add(OqlExpression exp, string op)
221 ········{
222 ············System.Diagnostics.Debug.Assert(this.children.Count > 0);
223 ············if (this.Children.Count < 2)
224 ············{
225 ················this.children.Add(exp);
226 ················this.op = op;
227 ············}
228 ············else if (this.op == op)
229 ············{
230 ················this.children.Add(exp);
231 ············}
232 ············else
233 ············{
234 ················OqlExpression left = this.Clone();
235 ················this.children.Clear();
236 ················this.children.Add(left);
237 ················this.op = op;
238 ················this.children.Add(exp);
239 ············}
240 ········}
241
242 ········/// <summary>
243 ········/// Gets all siblings of an expression
244 ········/// </summary>
245 ········public List<OqlExpression> Siblings
246 ········{
247 ············get
248 ············{
249 ················List<OqlExpression> result = new List<OqlExpression>();
250 ················if ( this.parent != null )
251 ················{
252 ····················foreach ( OqlExpression child in parent.children )
253 ····················{
254 ························if ( Object.ReferenceEquals( child, this ) )
255 ····························continue;
256
257 ························result.Add( child );
258 ····················}
259 ················}
260 ················return result;
261 ············}
262 ········}
263
264 ········/// <summary>
265 ········/// Gets the next sibling starting from the current expression
266 ········/// </summary>
267 ········public OqlExpression NextSibling
268 ········{
269 ············get
270 ············{
271 ················if (this.parent != null)
272 ················{
273 ····················bool foundMyself = false;
274 ····················foreach (OqlExpression child in parent.children)
275 ····················{
276 ························if (foundMyself)
277 ····························return child;
278 ························if (Object.ReferenceEquals(child, this))
279 ····························foundMyself = true;
280
281 ····················}
282 ················}
283 ················return null;
284 ············}
285 ········}
286
287 ········/// <summary>
288 ········/// Clones the expression
289 ········/// </summary>
290 ········/// <returns></returns>
291 ········protected virtual OqlExpression Clone()
292 ········{
293 ············OqlExpression exp = new OqlExpression(this.line, this.col);
294 ············exp.children = children;
295 ············exp.op = op;
296 ············exp.unaryOp = unaryOp;
297 ············exp.value = value;
298 ············return exp;
299 ········}
300
301 ········//public List<object> Serialize()
302 ········//{
303 ········//····List<object> list = new List<object>();
304 ········//····Serialize(list);
305 ········//}
306
307 ········//private void Serialize(List<object> list)
308 ········//{
309 ········//····if (this.IsTerminating)
310 ········//····{
311 ········//········list.Add(this);
312 ········//····}
313 ········//····else
314 ········//····{
315 ········//········if (this.hasBrackets)
316 ········//············list.Add("(");
317 ········//········if (this.unaryOp != null)
318 ········//············list.Add(this.unaryOp);
319 ········//····}
320
321 ········//}
322
323 ········///<inheritdoc/>
324 ········public override string ToString()
325 ········{
326 ············StringBuilder sb = new StringBuilder();
327
328 ············if (hasBrackets)
329 ················sb.Append('(');
330 ············if (unaryOp != null)
331 ············{
332 ················sb.Append(unaryOp);
333 ················sb.Append(' ');
334 ············}
335 ············if (ExpressionType == Expressions.ExpressionType.Raw && value != null)
336 ············{
337 ················sb.Append( this.value.ToString() );
338 ················if (!IsTerminating)
339 ····················sb.Append( ' ' );
340 ············}
341 ············else if (this.IsTerminating)
342 ············{
343 ················if (this.value is Double)
344 ····················sb.Append(((Double)this.value).ToString(CultureInfo.InvariantCulture));
345 ················else
346 ····················if (value != null)
347 ····················sb.Append(this.value.ToString());
348 ············}
349 ············if (!this.IsTerminating)
350 ············{
351 ················string op1 = op;
352 ················for (int i = 0; i < children.Count; i++)
353 ················{
354 ····················OqlExpression child = this.children[i];
355 ····················sb.Append(child.ToString());
356 ····················if (i < children.Count - 1)
357 ····················{
358 ························if (!String.IsNullOrEmpty(op))
359 ························{
360 ····························if (op != ",")
361 ································sb.Append(' ');
362 ····························sb.Append(op1);
363 ····························if (op1 == "BETWEEN")
364 ····························{
365 ································op1 = "AND";
366 ····························}
367 ····························sb.Append(' ');
368 ························}
369 ························else
370 ························{
371 ····························sb.Append(' ');
372 ························}
373 ····················}
374 ················}
375 ············}
376 ············if (hasBrackets)
377 ················sb.Append(')');
378 ············
379 ············return sb.ToString();
380 ········}
381
382 ········/// <summary>
383 ········/// Visits all expressions of the tree and returns the expressions to which the predicate applies
384 ········/// </summary>
385 ········/// <param name="predicate"></param>
386 ········/// <returns></returns>
387 ········public IEnumerable<OqlExpression> GetAll(Func<OqlExpression, bool>predicate)
388 ········{
389 ············if (predicate(this))
390 ················yield return this;
391 ············foreach (var child in children)
392 ············{
393 ················foreach (var exp in child.GetAll( predicate ))
394 ················{
395 ····················yield return exp;
396 ················}
397 ············}
398 ········}
399 ····
400 ········/// <summary>
401 ········/// Constructs a deep clone of the expression
402 ········/// </summary>
403 ········public virtual OqlExpression DeepClone
404 ········{
405 ············get
406 ············{
407 ················OqlExpression clone = new OqlExpression( this.line, this.col );
408 ················clone.expressionType = this.expressionType;
409 ················clone.hasBrackets = this.hasBrackets;
410 ················clone.op = this.op;
411 ················clone.unaryOp = this.unaryOp;
412 ················clone.value = this.value;
413 ················clone.annotations = annotations;
414 ················foreach(var child in children)
415 ················{
416 ····················OqlExpression childClone = child.DeepClone;
417 ····················((IManageExpression)childClone).SetParent( clone );
418 ····················clone.Add( childClone );
419 ················}
420 ················return clone;
421 ············}
422 ········}
423 ····}
424 }
425
New Commit (b47b95e)
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Globalization;
5
6 namespace NDOql.Expressions
7 {
8 ····internal interface IManageExpression
9 ····{
10 ········void SetParent( OqlExpression exp );
11 ····}
12
13 ····/// <summary>
14 ····/// Base class for Oql expressions
15 ····/// </summary>
16 ····public class OqlExpression : IManageExpression
17 ····{
18 ········int line;
19 ········int col;
20 ········ExpressionType expressionType;
21 ········string unaryOp;
22 ········string op;
23 ········OqlExpression parent = null;
24 ········List<OqlExpression> children = new List<OqlExpression>();
25 ········object value;
26 ········Dictionary<string, object> annotations = new Dictionary<string, object>();
27
28 ········/// <summary>
29 ········/// Sets an annotation for a certain experession node
30 ········/// </summary>
31 ········/// <param name="key"></param>
32 ········/// <param name="value"></param>
33 ········public void SetAnnotation(string key, object value)
34 ········{
35 ············annotations[key] = value;
36 ········}
37
38 ········/// <summary>
39 ········/// Gets an annotation for a node
40 ········/// </summary>
41 ········/// <typeparam name="T"></typeparam>
42 ········/// <param name="key"></param>
43 ········/// <returns></returns>
44 ········public T GetAnnotation<T>( string key )
45 ········{
46 ············if (!annotations.ContainsKey( key ))
47 ················return default(T);
48
49 ············return (T)annotations[key];
50 ········}
51
52 ········/// <summary>
53 ········/// Gets or sets the line number where the expression appears
54 ········/// </summary>
55 ········public int Line
56 ········{
57 ············get { return line; }
58 ············set { line = value; }
59 ········}
60 ········/// <summary>
61 ········/// Gets or sets the column in the line where the expression appears
62 ········/// </summary>
63 ········public int Column
64 ········{
65 ············get { return col; }
66 ············set { col = value; }
67 ········}
68
69 ········/// <summary>
70 ········/// Gets or sets the expression type
71 ········/// </summary>
72 ········public ExpressionType ExpressionType
73 ········{
74 ············get { return expressionType; }
75 ············set { expressionType = value; }
76 ········}
77
78 ········void ThrowUnaryException()
79 ········{
80 ············throw new OqlExpressionException("Unary Operator doesn't fit to the type of the expression in '" + this.ToString() + "'. Line " + this.line + ", Col " + this.col);
81 ········}
82
83 ········/// <summary>
84 ········/// Gets or sets an unary operator, if one exists
85 ········/// </summary>
86 ········public string UnaryOp
87 ········{
88 ············get { return unaryOp; }
89 ············set
90 ············{
91 ················unaryOp = value;
92 ················if (unaryOp == "NOT")
93 ················{
94 ····················if (this.expressionType != ExpressionType.Boolean
95 ························&& this.expressionType != ExpressionType.Unknown)
96 ························ThrowUnaryException();
97 ················}
98 ················else if (unaryOp == "~" || unaryOp == "-" || unaryOp == "+")
99 ················{
100 ····················if (this.expressionType != ExpressionType.Number
101 ························&& this.expressionType != ExpressionType.Unknown)
102 ························ThrowUnaryException();
103 ················}
104 ············}
105 ········}
106
107 ········/// <summary>
108 ········/// Gets or sets an operator
109 ········/// </summary>
110 ········public string Operator
111 ········{
112 ············get { return op; }
113 ············set { op = value; }
114 ········}
115
116 ········bool hasBrackets;
117 ········/// <summary>
118 ········/// Gets or sets a value, which determines, if an expression should be bracketed
119 ········/// </summary>
120 ········public bool HasBrackets
121 ········{
122 ············get { return hasBrackets; }
123 ············set { hasBrackets = value; }
124 ········}
125
126 ········/// <summary>
127 ········/// Gets the child expressions
128 ········/// </summary>
129 ········public List<OqlExpression> Children
130 ········{
131 ············get { return children; }
132 ········}
133
134 ········/// <summary>
135 ········/// Gets the parent expression
136 ········/// </summary>
137 ········public OqlExpression Parent
138 ········{
139 ············get { return this.parent; }
140 ········}
141
142 ········/// <summary>
143 ········/// </summary>
144 ········/// <param name="exp"></param>
145 ········/// <remarks>
146 ········/// Since there occurs a lot of shuffling around the children during the parse process
147 ········/// we itererate through the tree after parsing and set the parent there.
148 ········/// </remarks>
149 ········void IManageExpression.SetParent( OqlExpression exp )
150 ········{
151 ············this.parent = exp;
152 ········}
153
154 ········/// <summary>
155 ········/// Gets the value of the expression
156 ········/// </summary>
157 ········public object Value
158 ········{
159 ············get { return this.value; }
160 ············set { this.value = value; }
161 ········}
162
163 ········/// <summary>
164 ········/// Constructor
165 ········/// </summary>
166 ········/// <param name="line"></param>
167 ········/// <param name="col"></param>
168 ········public OqlExpression(int line, int col)
169 ········{
170 ············this.line = line;
171 ············this.col = col;
172 ········}
173
174 ········/// <summary>
175 ········/// Determines, if an expression is a leaf in the tree.
176 ········/// </summary>
177 ········public virtual bool IsTerminating
178 ········{
179 ············get { return this.children.Count == 0; }
180 ········}
181
182 ········/// <summary>
183 ········/// Reduces an expression
184 ········/// </summary>
185 ········/// <returns></returns>
186 public virtual OqlExpression Simplify( )
187 ········{
188 ············System.Diagnostics.Debug.Assert(this.children.Count != 0 || this.value != null);
189 ············if (this.children.Count > 1 || this.IsTerminating)
190 ················return this;
191 ············if (unaryOp != null)
192 ············{
193 ················if (this.children[0].unaryOp == null && !this.children[0].hasBrackets)
194 ················{
195 ····················this.children[0].unaryOp = this.unaryOp;
196 ····················return this.children[0];
197 ················}
198 ················else
199 ················{
200 ····················return this;
201 ················}
202 ············}
203 ············return this.children[0];
204 ········}
205
206 ········/// <summary>
207 ········/// Adds a child expressoin
208 ········/// </summary>
209 ········/// <param name="exp"></param>
210 ········public virtual void Add(OqlExpression exp)
211 ········{············
212 ············this.children.Add(exp);
213 ········}
214
215 ········/// <summary>
216 ········/// Adds a child expression and an operator
217 ········/// </summary>
218 ········/// <param name="exp"></param>
219 ········/// <param name="op"></param>
220 ········public virtual void Add(OqlExpression exp, string op)
221 ········{
222 ············System.Diagnostics.Debug.Assert(this.children.Count > 0);
223 ············if (this.Children.Count < 2)
224 ············{
225 ················this.children.Add(exp);
226 ················this.op = op;
227 ············}
228 ············else if (this.op == op)
229 ············{
230 ················this.children.Add(exp);
231 ············}
232 ············else
233 ············{
234 ················OqlExpression left = this.Clone();
235 ················this.children.Clear();
236 ················this.children.Add(left);
237 ················this.op = op;
238 ················this.children.Add(exp);
239 ············}
240 ········}
241
242 ········/// <summary>
243 ········/// Gets all siblings of an expression
244 ········/// </summary>
245 ········public List<OqlExpression> Siblings
246 ········{
247 ············get
248 ············{
249 ················List<OqlExpression> result = new List<OqlExpression>();
250 ················if ( this.parent != null )
251 ················{
252 ····················foreach ( OqlExpression child in parent.children )
253 ····················{
254 ························if ( Object.ReferenceEquals( child, this ) )
255 ····························continue;
256
257 ························result.Add( child );
258 ····················}
259 ················}
260 ················return result;
261 ············}
262 ········}
263
264 ········/// <summary>
265 ········/// Gets the next sibling starting from the current expression
266 ········/// </summary>
267 ········public OqlExpression NextSibling
268 ········{
269 ············get
270 ············{
271 ················if (this.parent != null)
272 ················{
273 ····················bool foundMyself = false;
274 ····················foreach (OqlExpression child in parent.children)
275 ····················{
276 ························if (foundMyself)
277 ····························return child;
278 ························if (Object.ReferenceEquals(child, this))
279 ····························foundMyself = true;
280
281 ····················}
282 ················}
283 ················return null;
284 ············}
285 ········}
286
287 ········/// <summary>
288 ········/// Clones the expression
289 ········/// </summary>
290 ········/// <returns></returns>
291 ········protected virtual OqlExpression Clone()
292 ········{
293 ············OqlExpression exp = new OqlExpression(this.line, this.col);
294 ············exp.children = children;
295 ············exp.op = op;
296 ············exp.unaryOp = unaryOp;
297 ············exp.value = value;
298 ············return exp;
299 ········}
300
301 ········//public List<object> Serialize()
302 ········//{
303 ········//····List<object> list = new List<object>();
304 ········//····Serialize(list);
305 ········//}
306
307 ········//private void Serialize(List<object> list)
308 ········//{
309 ········//····if (this.IsTerminating)
310 ········//····{
311 ········//········list.Add(this);
312 ········//····}
313 ········//····else
314 ········//····{
315 ········//········if (this.hasBrackets)
316 ········//············list.Add("(");
317 ········//········if (this.unaryOp != null)
318 ········//············list.Add(this.unaryOp);
319 ········//····}
320
321 ········//}
322
323 ········///<inheritdoc/>
324 ········public override string ToString()
325 ········{
326 ············StringBuilder sb = new StringBuilder();
327
328 ············if (hasBrackets)
329 ················sb.Append('(');
330 ············if (unaryOp != null)
331 ············{
332 ················sb.Append(unaryOp);
333 ················sb.Append(' ');
334 ············}
335 ············if (ExpressionType == Expressions.ExpressionType.Raw && value != null)
336 ············{
337 ················sb.Append( this.value.ToString() );
338 ················if (!IsTerminating)
339 ····················sb.Append( ' ' );
340 ············}
341 ············else if (this.IsTerminating)
342 ············{
343 ················if (this.value is Double)
344 ····················sb.Append(((Double)this.value).ToString(CultureInfo.InvariantCulture));
345 ················else
346 ····················if (value != null)
347 ····················sb.Append(this.value.ToString());
348 ············}
349 ············if (!this.IsTerminating)
350 ············{
351 ················string op1 = op;
352 ················for (int i = 0; i < children.Count; i++)
353 ················{
354 ····················OqlExpression child = this.children[i];
355 ····················sb.Append(child.ToString());
356 ····················if (i < children.Count - 1)
357 ····················{
358 ························if (!String.IsNullOrEmpty(op))
359 ························{
360 ····························if (op != ",")
361 ································sb.Append(' ');
362 ····························sb.Append(op1);
363 ····························if (op1 == "BETWEEN")
364 ····························{
365 ································op1 = "AND";
366 ····························}
367 ····························sb.Append(' ');
368 ························}
369 ························else
370 ························{
371 ····························sb.Append(' ');
372 ························}
373 ····················}
374 ················}
375 ············}
376 ············if (hasBrackets)
377 ················sb.Append(')');
378 ············
379 ············return sb.ToString();
380 ········}
381
382 ········/// <summary>
383 ········/// Visits all expressions of the tree and returns the expressions to which the predicate applies
384 ········/// </summary>
385 ········/// <param name="predicate"></param>
386 ········/// <returns></returns>
387 ········public IEnumerable<OqlExpression> GetAll(Func<OqlExpression, bool>predicate)
388 ········{
389 ············if (predicate(this))
390 ················yield return this;
391 ············foreach (var child in children)
392 ············{
393 ················foreach (var exp in child.GetAll( predicate ))
394 ················{
395 ····················yield return exp;
396 ················}
397 ············}
398 ········}
399 ····
400 ········/// <summary>
401 ········/// Constructs a deep clone of the expression
402 ········/// </summary>
403 ········public virtual OqlExpression DeepClone
404 ········{
405 ············get
406 ············{
407 ················OqlExpression clone = new OqlExpression( this.line, this.col );
408 ················clone.expressionType = this.expressionType;
409 ················clone.hasBrackets = this.hasBrackets;
410 ················clone.op = this.op;
411 ················clone.unaryOp = this.unaryOp;
412 ················clone.value = this.value;
413 ················clone.annotations = annotations;
414 ················foreach(var child in children)
415 ················{
416 ····················OqlExpression childClone = child.DeepClone;
417 ····················((IManageExpression)childClone).SetParent( clone );
418 ····················clone.Add( childClone );
419 ················}
420 ················return clone;
421 ············}
422 ········}
423 ····}
424 }
425