/* PromotableTypeCheck.c */
/*****************************************************************************/
/*                                                                           */
/*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
/*    Copyright (C) 1994  Thomas R. Lawrence                                 */
/*                                                                           */
/*    This program is free software; you can redistribute it and/or modify   */
/*    it under the terms of the GNU General Public License as published by   */
/*    the Free Software Foundation; either version 2 of the License, or      */
/*    (at your option) any later version.                                    */
/*                                                                           */
/*    This program is distributed in the hope that it will be useful,        */
/*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*    GNU General Public License for more details.                           */
/*                                                                           */
/*    You should have received a copy of the GNU General Public License      */
/*    along with this program; if not, write to the Free Software            */
/*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                           */
/*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
/*                                                                           */
/*****************************************************************************/

#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"

#include "PromotableTypeCheck.h"
#include "Memory.h"
#include "ASTUnaryOperator.h"
#include "ASTExpression.h"


/* this routine sees if the right hand type can be promoted (if necessary) to */
/* become the left hand type.  True is returned if that is the case. */
MyBoolean				CanRightBeMadeToMatchLeft(DataTypes LeftType, DataTypes RightType)
	{
		if (LeftType == eDouble)
			{
				if ((RightType == eInteger) || (RightType == eFloat) || (RightType == eFixed))
					{
						return True;
					}
			}
		return (LeftType == RightType);
	}


/* this routine sees if the right hand type MUST be promoted to become */
/* the left hand type.  it is not allowed to call with non-compatible types */
MyBoolean				MustRightBePromotedToLeft(DataTypes LeftType, DataTypes RightType)
	{
		/* see if we have to promote */
		if (LeftType == RightType)
			{
				return False;
			}

		/* we have to promote, so see if we can */
		ERROR(LeftType != eDouble,PRERR(ForceAbort,
			"MustRightBePromotedToLeft:  types are not promotable"));
		ERROR((RightType != eInteger) && (RightType != eFloat) && (RightType != eDouble)
			&& (RightType != eFixed),PRERR(ForceAbort,
			"MustRightBePromotedToLeft:  types are not promotable"));
		/* we've filtered out all other possibililities, so they must be promoted */
		return True;
	}


/* perform a type promotion on an expression */
struct ASTExpressionRec*	PromoteTheExpression(DataTypes OriginalType,
									DataTypes DesiredType, struct ASTExpressionRec* OriginalExpression,
									long LineNumber, struct TrashTrackRec* TrashTracker)
	{
		ASTUnaryOpRec*		UnaryOperator;
		ASTExpressionRec*	ResultingExpression;

		ERROR(DesiredType != eDouble,PRERR(ForceAbort,
			"PromoteTheExpression:  types are not promotable"));
		switch (OriginalType)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"PromoteTheExpression:  unknown type"));
					break;
				case eBoolean:
				case eArrayOfBoolean:
				case eArrayOfInteger:
				case eArrayOfFloat:
				case eArrayOfDouble:
				case eArrayOfFixed:
					EXECUTE(PRERR(ForceAbort,"PromoteTheExpression:  types are not promotable"));
					break;
				case eDouble:
					EXECUTE(PRERR(ForceAbort,"PromoteTheExpression:  type promotion unnecessary"));
					break;

				case eInteger:
				case eFloat:
				case eFixed:
					UnaryOperator = NewUnaryOperator(eUnaryCastToDouble,OriginalExpression,
						TrashTracker,LineNumber);
					if (UnaryOperator == NIL)
						{
							return NIL;
						}
					ResultingExpression = NewExprUnaryOperator(UnaryOperator,TrashTracker,
						LineNumber);
					if (ResultingExpression == NIL)
						{
							return NIL;
						}
					return ResultingExpression;
			}
		EXECUTE(PRERR(ForceAbort,"PromoteTheExpression:  control reached end of function"));
	}


/* make sure the type is scalar */
MyBoolean				IsItAScalarType(DataTypes TheType)
	{
		MyBoolean			Result;

		switch (TheType)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"IsItAScalarType:  not a scalar type"));
					break;
				case eArrayOfBoolean:
				case eArrayOfInteger:
				case eArrayOfFloat:
				case eArrayOfDouble:
				case eArrayOfFixed:
					Result = False;
					break;
				case eBoolean:
				case eInteger:
				case eFloat:
				case eDouble:
				case eFixed:
					Result = True;
					break;
			}
		return Result;
	}


/* make sure it is some kind of sequenced scalar */
MyBoolean				IsItASequencedScalarType(DataTypes TheType)
	{
		MyBoolean			Result;

		switch (TheType)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"IsItASequencedScalarType:  not a scalar type"));
					break;
				case eArrayOfBoolean:
				case eArrayOfInteger:
				case eArrayOfFloat:
				case eArrayOfDouble:
				case eArrayOfFixed:
				case eBoolean:
					Result = False;
					break;
				case eInteger:
				case eFloat:
				case eDouble:
				case eFixed:
					Result = True;
					break;
			}
		return Result;
	}


/* make sure it is some kind of indexed type */
MyBoolean				IsItAnIndexedType(DataTypes TheType)
	{
		MyBoolean			Result;

		switch (TheType)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"IsItAnIndexedType:  not a scalar type"));
					break;
				case eBoolean:
				case eInteger:
				case eFloat:
				case eDouble:
				case eFixed:
					Result = False;
					break;
				case eArrayOfBoolean:
				case eArrayOfInteger:
				case eArrayOfFloat:
				case eArrayOfDouble:
				case eArrayOfFixed:
					Result = True;
					break;
			}
		return Result;
	}
