crashanalysercmd/PerfToolsSharedLibraries/Engine/SymBuildParsingLib/Parser/Framework/Utils/SymFunctionParser.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.Token;
using SymBuildParsingLib.Tree;
using SymBuildParsingLib.Common.Objects;
using SymbianTree;

namespace SymBuildParsingLib.Parser.Framework.Utils
{
	public class SymFunctionParser : SymTokenBalancer
	{
		#region Observer interface
		public delegate void ArgumentAvailable( SymArgument aArgument, SymToken aDelimitingToken );
		#endregion

		#region Events
		public event ArgumentAvailable EventArgumentAvailableHandler;
		#endregion

		#region Constructors & destructor
		public SymFunctionParser()
		{
		}
		#endregion

		#region API
		public virtual void RegisterFunctionParserTokens()
		{
			// Base class registration
			RegisterBalancerTokens();

			// These are the important tokens relating to function arguments
			SymToken bracketTokenOpening = new SymToken( "(", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
			SymToken bracketTokenClosing = new SymToken( ")", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
			SymToken squareBracketTokenOpening = new SymToken( "[", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
			SymToken squareBracketTokenClosing = new SymToken( "]", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
			SymToken templateBracketTokenOpening = new SymToken( "<", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
			SymToken templateBracketTokenClosing = new SymToken( ">", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );

			// We want to track levels for square brackets and template arguments in order to ensure we balance correctly.
			// We don't want to remove any redundancy here as these may have special meaning.
			RegisterOpeningToken( squareBracketTokenOpening, squareBracketTokenClosing, true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 0, TAssociatedBehaviour.EBehaviourNone );
			RegisterClosingToken( squareBracketTokenClosing, squareBracketTokenOpening, true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 0, TAssociatedBehaviour.EBehaviourNone );
			RegisterOpeningToken( templateBracketTokenOpening, templateBracketTokenClosing, true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 0, TAssociatedBehaviour.EBehaviourNone );
			RegisterClosingToken( templateBracketTokenClosing, templateBracketTokenOpening, true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 0, TAssociatedBehaviour.EBehaviourNone );

			// Define our argument separation token(s).
			TAssociatedBehaviour flags = TAssociatedBehaviour.EBehaviourNone;
			flags |= TAssociatedBehaviour.EBehaviourCreateSubTree;
			flags |= TAssociatedBehaviour.EBehaviourRemoveReduntantBracketing;
			//
			SymToken commaDelimiterToken = new SymToken( ",", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
			RegisterArgumentSeparatorToken( commaDelimiterToken, new SymTokenBalancerMatchCriteria( SymToken.NullToken(), false, true, TLevelExpectations.ELevelExpectationsAtLevel, 1, flags ) );
			RegisterArgumentSeparatorToken( commaDelimiterToken, new SymTokenBalancerMatchCriteria( SymToken.NullToken(), true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 1, TAssociatedBehaviour.EBehaviourNone ) );
		}

		public virtual SymArgument MakeArgument()
		{
			SymNode levelNodeToObtainArgumentsFrom = CurrentNode;

			// Try to work out whether we have a leve node at the current
			// scope which should be preferred t
			object levelNodeObject = levelNodeToObtainArgumentsFrom.ChildByType( typeof(SymTokenBalancerMarkerLevelNode) );
			if	( levelNodeObject != null )
			{
				levelNodeToObtainArgumentsFrom = (SymNode) levelNodeObject;
			}

			return MakeArgument( levelNodeToObtainArgumentsFrom );
		}

		public virtual SymArgument MakeArgument( SymNode aLevelToMakeArgumentsFrom )
		{
			SymArgument argument = new SymArgument();

			// Convert (recursively) any emitted elements to real tokens
			if	( aLevelToMakeArgumentsFrom is SymTokenBalancerMarkerLevelNode )
			{
				SymTokenBalancerMarkerLevelNode levelNode = (SymTokenBalancerMarkerLevelNode) aLevelToMakeArgumentsFrom;
				levelNode.ConvertEmittedElementsToRealTokenNodes( true /*recurse*/ );
			}

			// Now actually obtain the argument tokens
			int count = aLevelToMakeArgumentsFrom.ChildCount;
			int i = 0;
			//
			while( i < count )
			{
				SymNode n = aLevelToMakeArgumentsFrom[ 0 ];

				// We always remove any other nodes, irrespective of their type.
				// This is to ensure that the document tree does not get cluttered
				// with redundant argument token info.
				n.Remove();

				// Now we decide what to do...
				if	( n is SymTokenBalancerMarkerArgumentNode )
				{
					// We've reached the argument itself. This is the
					// signal to stop processing. We remove the argument node
					// since its not relevant to the production of the tree.
					break;
				}
				else if ( n is SymTokenBalancerMarkerLevelNode )
				{
					// Create a new sub-argument node and copy over the 
					// children.
					SymTokenBalancerMarkerLevelNode levelNode = (SymTokenBalancerMarkerLevelNode) n;
					SymArgumentSubLevel subLevel = levelNode.AsArgumentSubLevel( true );
					argument.CurrentNode.Add( subLevel );
				}
				else if ( n is SymTokenBalancerNodeEmittedElement )
				{
					System.Diagnostics.Debug.Assert( false ); // shouldn't get here anymore!
				}
				else if	( n is SymNodeToken )
				{
					// Node is implicitly removed since it transfers
					// from one tree to another.
					argument.CurrentNode.Add( n );
				}

				count = aLevelToMakeArgumentsFrom.ChildCount;
			}
			//
			SymTokenUtils.RemoveWhiteSpace( argument, true );
			return argument;
		}

		public string MakeFunctionName()
		{
			StringBuilder name = new StringBuilder();

			// Pull out all the level one tokens from the balancer. These form
			// the function/define name.
			foreach( SymNode n in DocumentTree )
			{
				if	( n is SymTokenBalancerMarkerNode )
				{
					// Not part of the name
					break;
				}
				else if ( n is SymTokenBalancerNodeEmittedElement )
				{
					// Not part of the name - also, this is indicator to stop iterating!
					break;
				}
				else if ( n is SymNodeToken )
				{
					SymNodeToken tokenNode = (SymNodeToken) n;
					name.Append( tokenNode.Token.Value );
				}
			}

			return name.ToString();
		}
		#endregion

		#region API - registration
		public void RegisterArgumentSeparatorToken( SymToken aToken, SymTokenBalancerMatchCriteria aCriteria )
		{
			SymToken copy = new SymToken( aToken );
			copy.Tag = aCriteria;
			//
			if	( IsTokenExactMatch( copy, iArgumentSeparators ) == false )
			{
				iArgumentSeparators.Append( copy );
			}
		}
		#endregion

		#region From SymTokenBalancer
		public override bool OfferToken( SymToken aToken )
		{
			bool consumed = false;
			int currentLevelNumber = CurrentLevelNumber;

			// Check for bracket matches
			SymTokenBalancerMatchCriteria tokenExtendedInfo;
			if	( IsArgumentSeparatorMatch( aToken, out tokenExtendedInfo, currentLevelNumber ) )
			{
				ArgumentStarted( aToken, tokenExtendedInfo );
				consumed = true;
			}
			
			// If it wasn't an arg token or it was, but it wasn't at the 
			// correct (expected) level, then give it to the base class
			// to handle.
			if	( consumed == false )
			{
				consumed = base.OfferToken( aToken );
			}
			//
			return consumed;
		}
		#endregion

		#region Notification framework
		protected virtual void NotifyArgumentAvailable( SymArgument aArgument, SymToken aDelimitingToken )
		{
			if	( EventArgumentAvailableHandler != null )
			{
				EventArgumentAvailableHandler( aArgument, aDelimitingToken );
			}
		}
		#endregion

		#region New internal framework
		protected virtual void ArgumentStarted( SymToken aToken, SymTokenBalancerMatchCriteria aCriteria )
		{
			System.Diagnostics.Debug.Write( aToken.Value );

			int currentLevelNumber = CurrentLevelNumber;

			// Perform any base class end level behaviour
			PerformEndLevelBehaviour( CurrentNode, aCriteria );

			// Add the emit node (the rest of the code will work out whether it needs to quote it when the final
			// tree is formed).
			SymTokenBalancerNodeEmittedElement argEmitElement = new SymTokenBalancerNodeEmittedElement( aToken, aCriteria );
			DocumentTree.CurrentNode.Add( argEmitElement );

			// Always add the argument node
			SymTokenBalancerMarkerArgumentNode argNode = new SymTokenBalancerMarkerArgumentNode( aCriteria );
			DocumentTree.CurrentNode.Add( argNode );

			if	( aCriteria.IsAssociatedBehaviourCreateSubTree )
			{
				// Make a new argument definition based upon the tokens we have in
				// the main document tree.
				SymArgument argument = MakeArgument( DocumentTree.CurrentNode );

				// Then notify the observer
				NotifyArgumentAvailable( argument, aToken );
			}
		}
		#endregion

		#region Internal utility methods
		protected bool IsArgumentSeparatorMatch( SymToken aToken, out SymTokenBalancerMatchCriteria aCriteria, int aLevelNumber )
		{
			aCriteria = null;
			bool matchFound = false;
			//
			int index = iArgumentSeparators.IndexOf( aToken );
			while( index >= 0 && matchFound == false )
			{
				SymToken token = iArgumentSeparators[ index ];
				System.Diagnostics.Debug.Assert ( token.Tag != null && token.Tag is SymTokenBalancerMatchCriteria );
				SymTokenBalancerMatchCriteria criteria = (SymTokenBalancerMatchCriteria) token.Tag;

				if	( criteria.Matches( aLevelNumber ) )
				{
					aCriteria = criteria;
					matchFound = true;
				}
				else
				{
					index = iArgumentSeparators.IndexOf( aToken, index+1 );
				}
			}

			return matchFound;
		}

		#endregion

		#region Data members
		private SymTokenContainer iArgumentSeparators = new SymTokenContainer();
		#endregion
	}
}