crashanalysercmd/PerfToolsSharedLibraries/Engine/SymBuildParsingLib/Token/SymTokenBalancerNodes.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

/*
* Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

using System;
using System.Text;
using System.Collections;
using SymBuildParsingLib.Tree;
using SymBuildParsingLib.Token;
using SymBuildParsingLib.Common.Objects;
using SymbianTree;

namespace SymBuildParsingLib.Token
{
	#region SymTokenBalancerDocument
	public class SymTokenBalancerDocument : SymTokenDocument
	{
		#region Constructors & destructor
		public SymTokenBalancerDocument()
		{
		}
		#endregion

		#region Internal framework API
		protected override void ExtractToContainer( SymNode aNode, SymTokenContainer aContainer )
		{
			if	( aNode is SymTokenBalancerNodeEmittedElement )
			{
				SymTokenBalancerNodeEmittedElement node = (SymTokenBalancerNodeEmittedElement) aNode;
				node.AddToContainerIfEmittable( aContainer );
			}
		}

		protected override void ExtractToDocument( SymNode aNode, SymTokenDocument aDocument )
		{
			if	( aNode is SymTokenBalancerNodeEmittedElement )
			{
				SymTokenBalancerNodeEmittedElement node = (SymTokenBalancerNodeEmittedElement) aNode;
				node.AddToDocumentIfEmittable( aDocument );
			}
		}

		protected override bool NodeIsExtractable( SymNode aNode )
		{
			bool ret = false;
			//
			if	( aNode is SymTokenBalancerNodeEmittedElement )
			{
				SymTokenBalancerNodeEmittedElement node = (SymTokenBalancerNodeEmittedElement) aNode;
				ret = node.Emit;
			}
			//
			return ret;
		}
		#endregion
	}
	#endregion

	#region SymTokenBalancerNode
	public class SymTokenBalancerNode : SymNodeToken
	{
		#region Constructors & destructor
		public SymTokenBalancerNode( SymToken aToken )
			: base( aToken )
		{
		}
		#endregion
	}
	#endregion

	#region SymTokenBalancerMarkerNode
	public class SymTokenBalancerMarkerNode : SymNodeAddAsChild
	{
		#region Constructors & destructor
		public SymTokenBalancerMarkerNode( SymTokenBalancerMatchCriteria aMatchCriteria )
		{
			iMatchCriteria = aMatchCriteria;
		}
		#endregion

		#region Properties
		public SymTokenBalancerMatchCriteria MatchCriteria
		{
			get { return iMatchCriteria; }
		}
		#endregion

		#region Data members
		private readonly SymTokenBalancerMatchCriteria iMatchCriteria;
		#endregion
	}
	#endregion

	#region SymTokenBalancerMarkerLevelNode
	public class SymTokenBalancerMarkerLevelNode : SymTokenBalancerMarkerNode
	{
		#region Constructors & destructor
		public SymTokenBalancerMarkerLevelNode( SymTokenBalancerMatchCriteria aMatchCriteria )
			: base( aMatchCriteria )
		{
		}
		#endregion

		#region From SymNode		
		public override void Replace( SymNode aReplacement )
		{
			if	( HasPrevious && Previous is SymTokenBalancerNodeEmittedElement )
			{
				Previous.Remove();
			}
			if	( HasNext && Next is SymTokenBalancerNodeEmittedElement )
			{
				Next.Remove();
			}

			base.Replace( aReplacement );
		}
		#endregion

		#region API
		public SymArgumentSubLevel AsArgumentSubLevel( bool aRecurse )
		{
			SymArgumentSubLevel ret = new SymArgumentSubLevel( this );
			//
			if	( aRecurse )
			{
				foreach( SymNode child in ret )
				{
					if	( child is SymTokenBalancerMarkerLevelNode )
					{
						SymTokenBalancerMarkerLevelNode markerNode = (SymTokenBalancerMarkerLevelNode) child;
						SymArgumentSubLevel subLevel = markerNode.AsArgumentSubLevel( aRecurse );
						ret.InsertChild( subLevel, markerNode );
						markerNode.Remove();
					}
				}
			}
			//
			return ret;
		}

		public void ConvertEmittedElementsToRealTokenNodes( bool aRecurse )
		{
			int i = ChildCount;
			//
			while( i > 0 )
			{
				SymNode child = this[ --i ];
				//
				if	( child is SymTokenBalancerNodeEmittedElement )
				{
					SymTokenBalancerNodeEmittedElement emittedElement = (SymTokenBalancerNodeEmittedElement) child;
					if	( emittedElement.Emit )
					{
						SymNodeToken replacement = new SymNodeToken( emittedElement.Token ); 
						InsertChild( replacement, child );
					}
					child.Remove();
				}
				else if ( child is SymTokenBalancerMarkerLevelNode && aRecurse )
				{
					SymTokenBalancerMarkerLevelNode childLevel = (SymTokenBalancerMarkerLevelNode) child;
					childLevel.ConvertEmittedElementsToRealTokenNodes( aRecurse );
				}
			}
		}

		public int CountTokenByType( SymToken.TClass aClass )
		{
			int count = 0;
			//
			foreach( SymNode n in this )
			{
				if	( n is SymNodeToken )
				{
					bool isSpecial = ( n is SymTokenBalancerNode );
					//
					if	( isSpecial == false )
					{
						SymToken t = ((SymNodeToken) n).Token;
						//
						if	( t.Class == aClass )
						{
							++count;
						}
					}
				}
			}
			//
			return count;
		}

		public void Subsume()
		{
			System.Diagnostics.Debug.Assert( IsComplete );
			//
			SymTokenBalancerNodeEmittedElement previous = EmittedElementPrevious;
			SymTokenBalancerNodeEmittedElement next = EmittedElementNext;

			// Insert all my children as siblings of myself (i.e. make my parent's
			// grandchildren its direct children - i.e. promote them up the tree
			// by one level).
			SymNode parent = Parent;
			ArrayList parentsChildren = Parent.Children;
			parent.InsertChildrenFrom( this /* my children */, previous.Previous /* move them before the opening bracket */);

			// Remove the opening bracket token
			previous.Remove();

			// Remove the closing bracket token.
			next.Remove();

			// Remove the level marker token, i.e myself
			Remove();
		}
		#endregion

		#region Properties
		public bool CanBeSubsumed
		{
			get
			{
				bool canBeSubsumed = false;
				//
				if	( IsComplete )
				{
					if	( AreLocalEmittedNodesDiametricallyOposite )
					{
						bool isSimple = IsSimple;
						//
						if	( isSimple )
						{
							// Deal with the case whereby we have something like this: ([SOMETHINGELSE])
							if	( ( Parent is SymTokenBalancerMarkerLevelNode) && ChildCountLevelNodes == 0 )
							{
								// We don't have any child level nodes and our parent is a level (it always sound be in any case).
								SymTokenBalancerMarkerLevelNode parent = (SymTokenBalancerMarkerLevelNode) Parent;
								if	( parent.IsComplete )
								{
									// Check whether the parent is a function. If it is, then we don't want to subsume the children.
									bool isFunc = parent.IsFunction;
									if	( isFunc == false )
									{
										// The parent is complete, which means we can compare this level's open and closing tokens
										// with the parents.
										canBeSubsumed = ( parent.EmittedElementPrevious.Token.Equals( EmittedElementPrevious.Token ) && 
											parent.EmittedElementNext.Token.Equals( EmittedElementNext.Token ) );
									}
								}
								else
								{
									canBeSubsumed = true;
								}
								
							}
							else
							{
								canBeSubsumed = true;
							}
						}
						else
						{
							// Check whether our children contains at least a single argument separator node.
							// If it does, we can't allow it to be subsumed.
							if	( ChildCountArgumentNodes == 0 )
							{
								if	( Parent is SymTokenBalancerMarkerLevelNode )
								{
									SymTokenBalancerMarkerLevelNode parent = (SymTokenBalancerMarkerLevelNode) Parent;
									bool parentIsSimple = parent.IsSimple;
									canBeSubsumed = parentIsSimple;
								}
							}
						}
					}
				}
				//
				return canBeSubsumed;
			}
		}

		public bool IsFunction
		{
			get
			{
				#region Example
				//
				// [FUNC_NAME] [(] [*] [)] 
				//                  |
				//        [alpha_numeric_child]
				//
				#endregion
				
				bool bracketsAreCorrect = false;
				bool hasFunctionName = false;
				bool childIsValid = false;
				//
				if	( AreLocalEmittedNodesDiametricallyOposite )
				{
					// Check that the previous node is a function name
					if	( Previous.HasPrevious )
					{
						SymNode previousPrevious = Previous.Previous;
						if	( previousPrevious is SymNodeToken )
						{
							SymNodeToken nodeToken = (SymNodeToken) previousPrevious;
							hasFunctionName = (nodeToken.Token.Class == SymToken.TClass.EClassAlphaNumeric );
						}
					}

					// Check that the brackets are ( and )
					bracketsAreCorrect = ( EmittedElementPrevious.Token.Value == "(" && EmittedElementNext.Token.Value == ")" );

					// Check that the level node has but one child and that it
					// is alphanumeric in nature.
					if	( ChildCountByType( typeof(SymNodeToken) ) > 0 )
					{
						foreach( SymNode child in this )
						{
							if	( child is SymNodeToken )
							{
								SymNodeToken tokenNode = (SymNodeToken) child;
								//
								if	( tokenNode.Token.Class == SymToken.TClass.EClassAlphaNumeric )
								{
									childIsValid = true;
									break;
								}
							}
						}
					}
				}

				bool isFunction = (bracketsAreCorrect && hasFunctionName && childIsValid );
				return isFunction;
			}
		}

		public bool IsSimple
		{
			get
			{
				bool isSimple = false;
				//
				if	( IsFunction )
				{
					isSimple = false;
				}
				else if	( ChildCountNonWhiteSpace == 1 )
				{
					// My child is but a single node...
					isSimple = true;
				}
				else if ( ChildCountWhiteSpace == ChildCount )
				{
					// My children are just whitespace
					isSimple = true;
				}
				else if ( ChildCountLevelNodes == 1 )
				{
					int childCountLevelAndAssociatedEmittedNodes = ChildCountLevelAndAssociatedEmittedNodes;
					int childCount = ChildCount;
					int whiteSpaceCount = ChildCountWhiteSpace;
					//
					if	( (childCount - whiteSpaceCount) == childCountLevelAndAssociatedEmittedNodes )
					{
						// Ignoring the whitespace nodes, all we had was a single level node plus its
						// two associated emitted elements...
						isSimple = true;
					}
				}
				//
				return isSimple;
			}
		}

		public bool IsComplete
		{
			get
			{
				bool complete = false;

				// Must have a next and a previous node. Next and previous must be
				// emitted element nodes
				if	( HasNext && HasPrevious )
				{
					complete = ( Previous is SymTokenBalancerNodeEmittedElement && Next is SymTokenBalancerNodeEmittedElement );
				}

				return complete;
			}
		}

		public bool AreLocalEmittedNodesDiametricallyOposite
		{
			get
			{
				bool ret = false;
				//
				if	( IsComplete )
				{
					SymTokenBalancerNodeEmittedElement previous = (SymTokenBalancerNodeEmittedElement) Previous;
					SymTokenBalancerNodeEmittedElement next = (SymTokenBalancerNodeEmittedElement) Next;
					//
					if	( previous.MatchCriteria.DiametricToken.Equals( next.Token ) )
					{
						// Paranoid
						ret = ( next.MatchCriteria.DiametricToken.Equals( previous.Token ) );
					}
				}
				//
				return ret;
			}
		}

		public SymNodeToken FunctionName
		{
			get
			{
				if	( IsFunction == false )
				{
					throw new ArgumentException( "Level node is not a function node" );
				}

				System.Diagnostics.Debug.Assert( Previous.HasPrevious );
				System.Diagnostics.Debug.Assert( Previous.Previous is SymNodeToken );
				SymNodeToken functionNameToken = (SymNodeToken) Previous.Previous;
				return functionNameToken;
			}
		}

		public SymTokenContainer ChildTokens
		{
			get
			{
				SymTokenContainer ret = new SymTokenContainer();
				//
				foreach( SymNode c in this )
				{
					if	( c is SymNodeToken )
					{
						SymNodeToken t = (SymNodeToken) c;
						ret.Append( t.Token );
					}
				}
				//
				return ret;
			}
		}

		public int ChildCountWhiteSpace
		{
			get
			{
				return CountTokenByType( SymToken.TClass.EClassWhiteSpace );
			}
		}

		public int ChildCountNonWhiteSpace
		{
			get
			{
				return ChildCount - ChildCountWhiteSpace;
			}
		}

		public int ChildCountLevelNodes
		{
			get
			{
				int count = ChildCountByType( typeof(SymTokenBalancerMarkerLevelNode) );
				return count;
			}
		}

		public int ChildCountLevelAndAssociatedEmittedNodes
		{
			get
			{
				int count = 0;
				//
				int index = 0;
				object childLevelNodeObject = ChildByType( typeof(SymTokenBalancerMarkerLevelNode), ref index );
				while( childLevelNodeObject != null )
				{
					// Count is incremented by one each time we find a level node
					SymTokenBalancerMarkerLevelNode childLevelNode = (SymTokenBalancerMarkerLevelNode) childLevelNodeObject;
					++count;

					// It should always have a previous token.
					System.Diagnostics.Debug.Assert( childLevelNode.HasPrevious );
					if	( childLevelNode.Previous is SymTokenBalancerNodeEmittedElement )
					{
						++count;
					}

					// It may have a next node, assuming its complete...
					if	( childLevelNode.HasNext )
					{
						if	( childLevelNode.Next is SymTokenBalancerNodeEmittedElement )
						{
							++count;
						}
					}

					// Move to next child level node
					++index;
					childLevelNodeObject = ChildByType( typeof(SymTokenBalancerMarkerLevelNode), ref index );
				}
				//
				return count;
			}
		}

		public int ChildCountArgumentNodes
		{
			get
			{
				int count = ChildCountByType( typeof(SymTokenBalancerMarkerArgumentNode) );
				return count;
			}
		}

		public SymTokenBalancerNodeEmittedElement EmittedElementPrevious
		{
			get
			{
				return (SymTokenBalancerNodeEmittedElement) Previous;
			}
		}

		public SymTokenBalancerNodeEmittedElement EmittedElementNext
		{
			get
			{
				return (SymTokenBalancerNodeEmittedElement) Next;
			}
		}

		#endregion

		#region Internal methods
		#endregion
	}
	#endregion

	#region SymTokenBalancerMarkerArgumentNode
	public class SymTokenBalancerMarkerArgumentNode : SymTokenBalancerMarkerNode
	{
		#region Constructors & destructor
		public SymTokenBalancerMarkerArgumentNode( SymTokenBalancerMatchCriteria aMatchCriteria )
			: base( aMatchCriteria )
		{
		}
		#endregion
	}
	#endregion

	#region SymTokenBalancerNodeEmittedElement
	public class SymTokenBalancerNodeEmittedElement : SymTokenBalancerMarkerNode
	{
		#region Constructors & destructor
		public SymTokenBalancerNodeEmittedElement( SymToken aToken, SymTokenBalancerMatchCriteria aMatchCriteria )
			: base( aMatchCriteria )
		{
			iToken = aToken;
		}
		#endregion

		#region API
		public void AddToDocumentIfEmittable( SymDocument aDocument )
		{
			if	( Emit )
			{
				SymNodeToken node = new SymNodeToken( Token );
				aDocument.CurrentNode.Add( node );
			}
		}

		public void AddToContainerIfEmittable( SymTokenContainer aContainer )
		{
			if	( Emit )
			{
				aContainer.Append( Token );
			}
		}
		#endregion

		#region Properties
		public SymToken Token
		{
			get { return iToken; }
		}

		public bool Emit
		{
			get { return MatchCriteria.Emit; }
		}
		#endregion

		#region Data members
		private readonly SymToken iToken;
		#endregion
	}
	#endregion
}