|
1 /* |
|
2 * Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 using System; |
|
19 using System.Text; |
|
20 using System.Collections; |
|
21 using SymBuildParsingLib.Tree; |
|
22 using SymBuildParsingLib.Token; |
|
23 using SymBuildParsingLib.Common.Objects; |
|
24 using SymbianTree; |
|
25 |
|
26 namespace SymBuildParsingLib.Token |
|
27 { |
|
28 #region SymTokenBalancerDocument |
|
29 public class SymTokenBalancerDocument : SymTokenDocument |
|
30 { |
|
31 #region Constructors & destructor |
|
32 public SymTokenBalancerDocument() |
|
33 { |
|
34 } |
|
35 #endregion |
|
36 |
|
37 #region Internal framework API |
|
38 protected override void ExtractToContainer( SymNode aNode, SymTokenContainer aContainer ) |
|
39 { |
|
40 if ( aNode is SymTokenBalancerNodeEmittedElement ) |
|
41 { |
|
42 SymTokenBalancerNodeEmittedElement node = (SymTokenBalancerNodeEmittedElement) aNode; |
|
43 node.AddToContainerIfEmittable( aContainer ); |
|
44 } |
|
45 } |
|
46 |
|
47 protected override void ExtractToDocument( SymNode aNode, SymTokenDocument aDocument ) |
|
48 { |
|
49 if ( aNode is SymTokenBalancerNodeEmittedElement ) |
|
50 { |
|
51 SymTokenBalancerNodeEmittedElement node = (SymTokenBalancerNodeEmittedElement) aNode; |
|
52 node.AddToDocumentIfEmittable( aDocument ); |
|
53 } |
|
54 } |
|
55 |
|
56 protected override bool NodeIsExtractable( SymNode aNode ) |
|
57 { |
|
58 bool ret = false; |
|
59 // |
|
60 if ( aNode is SymTokenBalancerNodeEmittedElement ) |
|
61 { |
|
62 SymTokenBalancerNodeEmittedElement node = (SymTokenBalancerNodeEmittedElement) aNode; |
|
63 ret = node.Emit; |
|
64 } |
|
65 // |
|
66 return ret; |
|
67 } |
|
68 #endregion |
|
69 } |
|
70 #endregion |
|
71 |
|
72 #region SymTokenBalancerNode |
|
73 public class SymTokenBalancerNode : SymNodeToken |
|
74 { |
|
75 #region Constructors & destructor |
|
76 public SymTokenBalancerNode( SymToken aToken ) |
|
77 : base( aToken ) |
|
78 { |
|
79 } |
|
80 #endregion |
|
81 } |
|
82 #endregion |
|
83 |
|
84 #region SymTokenBalancerMarkerNode |
|
85 public class SymTokenBalancerMarkerNode : SymNodeAddAsChild |
|
86 { |
|
87 #region Constructors & destructor |
|
88 public SymTokenBalancerMarkerNode( SymTokenBalancerMatchCriteria aMatchCriteria ) |
|
89 { |
|
90 iMatchCriteria = aMatchCriteria; |
|
91 } |
|
92 #endregion |
|
93 |
|
94 #region Properties |
|
95 public SymTokenBalancerMatchCriteria MatchCriteria |
|
96 { |
|
97 get { return iMatchCriteria; } |
|
98 } |
|
99 #endregion |
|
100 |
|
101 #region Data members |
|
102 private readonly SymTokenBalancerMatchCriteria iMatchCriteria; |
|
103 #endregion |
|
104 } |
|
105 #endregion |
|
106 |
|
107 #region SymTokenBalancerMarkerLevelNode |
|
108 public class SymTokenBalancerMarkerLevelNode : SymTokenBalancerMarkerNode |
|
109 { |
|
110 #region Constructors & destructor |
|
111 public SymTokenBalancerMarkerLevelNode( SymTokenBalancerMatchCriteria aMatchCriteria ) |
|
112 : base( aMatchCriteria ) |
|
113 { |
|
114 } |
|
115 #endregion |
|
116 |
|
117 #region From SymNode |
|
118 public override void Replace( SymNode aReplacement ) |
|
119 { |
|
120 if ( HasPrevious && Previous is SymTokenBalancerNodeEmittedElement ) |
|
121 { |
|
122 Previous.Remove(); |
|
123 } |
|
124 if ( HasNext && Next is SymTokenBalancerNodeEmittedElement ) |
|
125 { |
|
126 Next.Remove(); |
|
127 } |
|
128 |
|
129 base.Replace( aReplacement ); |
|
130 } |
|
131 #endregion |
|
132 |
|
133 #region API |
|
134 public SymArgumentSubLevel AsArgumentSubLevel( bool aRecurse ) |
|
135 { |
|
136 SymArgumentSubLevel ret = new SymArgumentSubLevel( this ); |
|
137 // |
|
138 if ( aRecurse ) |
|
139 { |
|
140 foreach( SymNode child in ret ) |
|
141 { |
|
142 if ( child is SymTokenBalancerMarkerLevelNode ) |
|
143 { |
|
144 SymTokenBalancerMarkerLevelNode markerNode = (SymTokenBalancerMarkerLevelNode) child; |
|
145 SymArgumentSubLevel subLevel = markerNode.AsArgumentSubLevel( aRecurse ); |
|
146 ret.InsertChild( subLevel, markerNode ); |
|
147 markerNode.Remove(); |
|
148 } |
|
149 } |
|
150 } |
|
151 // |
|
152 return ret; |
|
153 } |
|
154 |
|
155 public void ConvertEmittedElementsToRealTokenNodes( bool aRecurse ) |
|
156 { |
|
157 int i = ChildCount; |
|
158 // |
|
159 while( i > 0 ) |
|
160 { |
|
161 SymNode child = this[ --i ]; |
|
162 // |
|
163 if ( child is SymTokenBalancerNodeEmittedElement ) |
|
164 { |
|
165 SymTokenBalancerNodeEmittedElement emittedElement = (SymTokenBalancerNodeEmittedElement) child; |
|
166 if ( emittedElement.Emit ) |
|
167 { |
|
168 SymNodeToken replacement = new SymNodeToken( emittedElement.Token ); |
|
169 InsertChild( replacement, child ); |
|
170 } |
|
171 child.Remove(); |
|
172 } |
|
173 else if ( child is SymTokenBalancerMarkerLevelNode && aRecurse ) |
|
174 { |
|
175 SymTokenBalancerMarkerLevelNode childLevel = (SymTokenBalancerMarkerLevelNode) child; |
|
176 childLevel.ConvertEmittedElementsToRealTokenNodes( aRecurse ); |
|
177 } |
|
178 } |
|
179 } |
|
180 |
|
181 public int CountTokenByType( SymToken.TClass aClass ) |
|
182 { |
|
183 int count = 0; |
|
184 // |
|
185 foreach( SymNode n in this ) |
|
186 { |
|
187 if ( n is SymNodeToken ) |
|
188 { |
|
189 bool isSpecial = ( n is SymTokenBalancerNode ); |
|
190 // |
|
191 if ( isSpecial == false ) |
|
192 { |
|
193 SymToken t = ((SymNodeToken) n).Token; |
|
194 // |
|
195 if ( t.Class == aClass ) |
|
196 { |
|
197 ++count; |
|
198 } |
|
199 } |
|
200 } |
|
201 } |
|
202 // |
|
203 return count; |
|
204 } |
|
205 |
|
206 public void Subsume() |
|
207 { |
|
208 System.Diagnostics.Debug.Assert( IsComplete ); |
|
209 // |
|
210 SymTokenBalancerNodeEmittedElement previous = EmittedElementPrevious; |
|
211 SymTokenBalancerNodeEmittedElement next = EmittedElementNext; |
|
212 |
|
213 // Insert all my children as siblings of myself (i.e. make my parent's |
|
214 // grandchildren its direct children - i.e. promote them up the tree |
|
215 // by one level). |
|
216 SymNode parent = Parent; |
|
217 ArrayList parentsChildren = Parent.Children; |
|
218 parent.InsertChildrenFrom( this /* my children */, previous.Previous /* move them before the opening bracket */); |
|
219 |
|
220 // Remove the opening bracket token |
|
221 previous.Remove(); |
|
222 |
|
223 // Remove the closing bracket token. |
|
224 next.Remove(); |
|
225 |
|
226 // Remove the level marker token, i.e myself |
|
227 Remove(); |
|
228 } |
|
229 #endregion |
|
230 |
|
231 #region Properties |
|
232 public bool CanBeSubsumed |
|
233 { |
|
234 get |
|
235 { |
|
236 bool canBeSubsumed = false; |
|
237 // |
|
238 if ( IsComplete ) |
|
239 { |
|
240 if ( AreLocalEmittedNodesDiametricallyOposite ) |
|
241 { |
|
242 bool isSimple = IsSimple; |
|
243 // |
|
244 if ( isSimple ) |
|
245 { |
|
246 // Deal with the case whereby we have something like this: ([SOMETHINGELSE]) |
|
247 if ( ( Parent is SymTokenBalancerMarkerLevelNode) && ChildCountLevelNodes == 0 ) |
|
248 { |
|
249 // We don't have any child level nodes and our parent is a level (it always sound be in any case). |
|
250 SymTokenBalancerMarkerLevelNode parent = (SymTokenBalancerMarkerLevelNode) Parent; |
|
251 if ( parent.IsComplete ) |
|
252 { |
|
253 // Check whether the parent is a function. If it is, then we don't want to subsume the children. |
|
254 bool isFunc = parent.IsFunction; |
|
255 if ( isFunc == false ) |
|
256 { |
|
257 // The parent is complete, which means we can compare this level's open and closing tokens |
|
258 // with the parents. |
|
259 canBeSubsumed = ( parent.EmittedElementPrevious.Token.Equals( EmittedElementPrevious.Token ) && |
|
260 parent.EmittedElementNext.Token.Equals( EmittedElementNext.Token ) ); |
|
261 } |
|
262 } |
|
263 else |
|
264 { |
|
265 canBeSubsumed = true; |
|
266 } |
|
267 |
|
268 } |
|
269 else |
|
270 { |
|
271 canBeSubsumed = true; |
|
272 } |
|
273 } |
|
274 else |
|
275 { |
|
276 // Check whether our children contains at least a single argument separator node. |
|
277 // If it does, we can't allow it to be subsumed. |
|
278 if ( ChildCountArgumentNodes == 0 ) |
|
279 { |
|
280 if ( Parent is SymTokenBalancerMarkerLevelNode ) |
|
281 { |
|
282 SymTokenBalancerMarkerLevelNode parent = (SymTokenBalancerMarkerLevelNode) Parent; |
|
283 bool parentIsSimple = parent.IsSimple; |
|
284 canBeSubsumed = parentIsSimple; |
|
285 } |
|
286 } |
|
287 } |
|
288 } |
|
289 } |
|
290 // |
|
291 return canBeSubsumed; |
|
292 } |
|
293 } |
|
294 |
|
295 public bool IsFunction |
|
296 { |
|
297 get |
|
298 { |
|
299 #region Example |
|
300 // |
|
301 // [FUNC_NAME] [(] [*] [)] |
|
302 // | |
|
303 // [alpha_numeric_child] |
|
304 // |
|
305 #endregion |
|
306 |
|
307 bool bracketsAreCorrect = false; |
|
308 bool hasFunctionName = false; |
|
309 bool childIsValid = false; |
|
310 // |
|
311 if ( AreLocalEmittedNodesDiametricallyOposite ) |
|
312 { |
|
313 // Check that the previous node is a function name |
|
314 if ( Previous.HasPrevious ) |
|
315 { |
|
316 SymNode previousPrevious = Previous.Previous; |
|
317 if ( previousPrevious is SymNodeToken ) |
|
318 { |
|
319 SymNodeToken nodeToken = (SymNodeToken) previousPrevious; |
|
320 hasFunctionName = (nodeToken.Token.Class == SymToken.TClass.EClassAlphaNumeric ); |
|
321 } |
|
322 } |
|
323 |
|
324 // Check that the brackets are ( and ) |
|
325 bracketsAreCorrect = ( EmittedElementPrevious.Token.Value == "(" && EmittedElementNext.Token.Value == ")" ); |
|
326 |
|
327 // Check that the level node has but one child and that it |
|
328 // is alphanumeric in nature. |
|
329 if ( ChildCountByType( typeof(SymNodeToken) ) > 0 ) |
|
330 { |
|
331 foreach( SymNode child in this ) |
|
332 { |
|
333 if ( child is SymNodeToken ) |
|
334 { |
|
335 SymNodeToken tokenNode = (SymNodeToken) child; |
|
336 // |
|
337 if ( tokenNode.Token.Class == SymToken.TClass.EClassAlphaNumeric ) |
|
338 { |
|
339 childIsValid = true; |
|
340 break; |
|
341 } |
|
342 } |
|
343 } |
|
344 } |
|
345 } |
|
346 |
|
347 bool isFunction = (bracketsAreCorrect && hasFunctionName && childIsValid ); |
|
348 return isFunction; |
|
349 } |
|
350 } |
|
351 |
|
352 public bool IsSimple |
|
353 { |
|
354 get |
|
355 { |
|
356 bool isSimple = false; |
|
357 // |
|
358 if ( IsFunction ) |
|
359 { |
|
360 isSimple = false; |
|
361 } |
|
362 else if ( ChildCountNonWhiteSpace == 1 ) |
|
363 { |
|
364 // My child is but a single node... |
|
365 isSimple = true; |
|
366 } |
|
367 else if ( ChildCountWhiteSpace == ChildCount ) |
|
368 { |
|
369 // My children are just whitespace |
|
370 isSimple = true; |
|
371 } |
|
372 else if ( ChildCountLevelNodes == 1 ) |
|
373 { |
|
374 int childCountLevelAndAssociatedEmittedNodes = ChildCountLevelAndAssociatedEmittedNodes; |
|
375 int childCount = ChildCount; |
|
376 int whiteSpaceCount = ChildCountWhiteSpace; |
|
377 // |
|
378 if ( (childCount - whiteSpaceCount) == childCountLevelAndAssociatedEmittedNodes ) |
|
379 { |
|
380 // Ignoring the whitespace nodes, all we had was a single level node plus its |
|
381 // two associated emitted elements... |
|
382 isSimple = true; |
|
383 } |
|
384 } |
|
385 // |
|
386 return isSimple; |
|
387 } |
|
388 } |
|
389 |
|
390 public bool IsComplete |
|
391 { |
|
392 get |
|
393 { |
|
394 bool complete = false; |
|
395 |
|
396 // Must have a next and a previous node. Next and previous must be |
|
397 // emitted element nodes |
|
398 if ( HasNext && HasPrevious ) |
|
399 { |
|
400 complete = ( Previous is SymTokenBalancerNodeEmittedElement && Next is SymTokenBalancerNodeEmittedElement ); |
|
401 } |
|
402 |
|
403 return complete; |
|
404 } |
|
405 } |
|
406 |
|
407 public bool AreLocalEmittedNodesDiametricallyOposite |
|
408 { |
|
409 get |
|
410 { |
|
411 bool ret = false; |
|
412 // |
|
413 if ( IsComplete ) |
|
414 { |
|
415 SymTokenBalancerNodeEmittedElement previous = (SymTokenBalancerNodeEmittedElement) Previous; |
|
416 SymTokenBalancerNodeEmittedElement next = (SymTokenBalancerNodeEmittedElement) Next; |
|
417 // |
|
418 if ( previous.MatchCriteria.DiametricToken.Equals( next.Token ) ) |
|
419 { |
|
420 // Paranoid |
|
421 ret = ( next.MatchCriteria.DiametricToken.Equals( previous.Token ) ); |
|
422 } |
|
423 } |
|
424 // |
|
425 return ret; |
|
426 } |
|
427 } |
|
428 |
|
429 public SymNodeToken FunctionName |
|
430 { |
|
431 get |
|
432 { |
|
433 if ( IsFunction == false ) |
|
434 { |
|
435 throw new ArgumentException( "Level node is not a function node" ); |
|
436 } |
|
437 |
|
438 System.Diagnostics.Debug.Assert( Previous.HasPrevious ); |
|
439 System.Diagnostics.Debug.Assert( Previous.Previous is SymNodeToken ); |
|
440 SymNodeToken functionNameToken = (SymNodeToken) Previous.Previous; |
|
441 return functionNameToken; |
|
442 } |
|
443 } |
|
444 |
|
445 public SymTokenContainer ChildTokens |
|
446 { |
|
447 get |
|
448 { |
|
449 SymTokenContainer ret = new SymTokenContainer(); |
|
450 // |
|
451 foreach( SymNode c in this ) |
|
452 { |
|
453 if ( c is SymNodeToken ) |
|
454 { |
|
455 SymNodeToken t = (SymNodeToken) c; |
|
456 ret.Append( t.Token ); |
|
457 } |
|
458 } |
|
459 // |
|
460 return ret; |
|
461 } |
|
462 } |
|
463 |
|
464 public int ChildCountWhiteSpace |
|
465 { |
|
466 get |
|
467 { |
|
468 return CountTokenByType( SymToken.TClass.EClassWhiteSpace ); |
|
469 } |
|
470 } |
|
471 |
|
472 public int ChildCountNonWhiteSpace |
|
473 { |
|
474 get |
|
475 { |
|
476 return ChildCount - ChildCountWhiteSpace; |
|
477 } |
|
478 } |
|
479 |
|
480 public int ChildCountLevelNodes |
|
481 { |
|
482 get |
|
483 { |
|
484 int count = ChildCountByType( typeof(SymTokenBalancerMarkerLevelNode) ); |
|
485 return count; |
|
486 } |
|
487 } |
|
488 |
|
489 public int ChildCountLevelAndAssociatedEmittedNodes |
|
490 { |
|
491 get |
|
492 { |
|
493 int count = 0; |
|
494 // |
|
495 int index = 0; |
|
496 object childLevelNodeObject = ChildByType( typeof(SymTokenBalancerMarkerLevelNode), ref index ); |
|
497 while( childLevelNodeObject != null ) |
|
498 { |
|
499 // Count is incremented by one each time we find a level node |
|
500 SymTokenBalancerMarkerLevelNode childLevelNode = (SymTokenBalancerMarkerLevelNode) childLevelNodeObject; |
|
501 ++count; |
|
502 |
|
503 // It should always have a previous token. |
|
504 System.Diagnostics.Debug.Assert( childLevelNode.HasPrevious ); |
|
505 if ( childLevelNode.Previous is SymTokenBalancerNodeEmittedElement ) |
|
506 { |
|
507 ++count; |
|
508 } |
|
509 |
|
510 // It may have a next node, assuming its complete... |
|
511 if ( childLevelNode.HasNext ) |
|
512 { |
|
513 if ( childLevelNode.Next is SymTokenBalancerNodeEmittedElement ) |
|
514 { |
|
515 ++count; |
|
516 } |
|
517 } |
|
518 |
|
519 // Move to next child level node |
|
520 ++index; |
|
521 childLevelNodeObject = ChildByType( typeof(SymTokenBalancerMarkerLevelNode), ref index ); |
|
522 } |
|
523 // |
|
524 return count; |
|
525 } |
|
526 } |
|
527 |
|
528 public int ChildCountArgumentNodes |
|
529 { |
|
530 get |
|
531 { |
|
532 int count = ChildCountByType( typeof(SymTokenBalancerMarkerArgumentNode) ); |
|
533 return count; |
|
534 } |
|
535 } |
|
536 |
|
537 public SymTokenBalancerNodeEmittedElement EmittedElementPrevious |
|
538 { |
|
539 get |
|
540 { |
|
541 return (SymTokenBalancerNodeEmittedElement) Previous; |
|
542 } |
|
543 } |
|
544 |
|
545 public SymTokenBalancerNodeEmittedElement EmittedElementNext |
|
546 { |
|
547 get |
|
548 { |
|
549 return (SymTokenBalancerNodeEmittedElement) Next; |
|
550 } |
|
551 } |
|
552 |
|
553 #endregion |
|
554 |
|
555 #region Internal methods |
|
556 #endregion |
|
557 } |
|
558 #endregion |
|
559 |
|
560 #region SymTokenBalancerMarkerArgumentNode |
|
561 public class SymTokenBalancerMarkerArgumentNode : SymTokenBalancerMarkerNode |
|
562 { |
|
563 #region Constructors & destructor |
|
564 public SymTokenBalancerMarkerArgumentNode( SymTokenBalancerMatchCriteria aMatchCriteria ) |
|
565 : base( aMatchCriteria ) |
|
566 { |
|
567 } |
|
568 #endregion |
|
569 } |
|
570 #endregion |
|
571 |
|
572 #region SymTokenBalancerNodeEmittedElement |
|
573 public class SymTokenBalancerNodeEmittedElement : SymTokenBalancerMarkerNode |
|
574 { |
|
575 #region Constructors & destructor |
|
576 public SymTokenBalancerNodeEmittedElement( SymToken aToken, SymTokenBalancerMatchCriteria aMatchCriteria ) |
|
577 : base( aMatchCriteria ) |
|
578 { |
|
579 iToken = aToken; |
|
580 } |
|
581 #endregion |
|
582 |
|
583 #region API |
|
584 public void AddToDocumentIfEmittable( SymDocument aDocument ) |
|
585 { |
|
586 if ( Emit ) |
|
587 { |
|
588 SymNodeToken node = new SymNodeToken( Token ); |
|
589 aDocument.CurrentNode.Add( node ); |
|
590 } |
|
591 } |
|
592 |
|
593 public void AddToContainerIfEmittable( SymTokenContainer aContainer ) |
|
594 { |
|
595 if ( Emit ) |
|
596 { |
|
597 aContainer.Append( Token ); |
|
598 } |
|
599 } |
|
600 #endregion |
|
601 |
|
602 #region Properties |
|
603 public SymToken Token |
|
604 { |
|
605 get { return iToken; } |
|
606 } |
|
607 |
|
608 public bool Emit |
|
609 { |
|
610 get { return MatchCriteria.Emit; } |
|
611 } |
|
612 #endregion |
|
613 |
|
614 #region Data members |
|
615 private readonly SymToken iToken; |
|
616 #endregion |
|
617 } |
|
618 #endregion |
|
619 } |