//
//  EXPExpression.m
//  Expression
//
//  Created by Ashley on 06/03/2006.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//

#import "EXPExpression.h"
#import "EXPConstant.h"
#import "EXPParameter.h"
//#import "EXPFunction.h"
#import "EXPUnaryOp.h"
#import "EXPBinOp.h"
#import "EXPTernOp.h"
#import "EXPSymbolTable.h"
//#import "EXPStackMachine.h"

static int _numEXPExpressionsInited = 0;
static int _numEXPExpressionsDealloced = 0;

@implementation EXPExpression

+ (id) expression8:(EXPExpressionList *)parser
{
	id p;
	
//	[parser skipspace];
	if ([parser isEndOfFile]) {
		return nil;
	}
	
	[parser readSymbol];
	
	if ([parser isLiteral]) {
		double val = [[parser symbol] floatValue];
		p = [[[EXPConstant alloc] initWithName:nil] autorelease];
		[p setValue:val];
	} else if ([parser isIdentifier]) {
		p = [parser symbol];
		
		if ([parser testSymbol:@"("]) {
			NSMutableArray *argumentList = [[NSMutableArray alloc] init];
			
            do {
				EXPExpression *arg = [EXPExpression expression:parser];
				[argumentList addObject:arg];
//				[arg release];
            } while ([parser testSymbol:@","]);
            
            if (![parser testSymbol:@")"]) {
            }
			
			[p setArgumentList:argumentList];
			[argumentList release];
		}
		
		if ([parser testSymbol:@"++"]) {
			EXPUnaryPostIncrement *pp = [[[EXPUnaryPostIncrement alloc] initWithLeft:p] autorelease];
			p = pp;
		}

	} else if ([[parser symbol] isEqualToString:@"("]) {
		p = [EXPExpression expression:parser];
		if (![parser testSymbol:@")"]) {
			NSLog(@"Right bracket expected!");
		}
	} else {
//		NSLog(@"EXPExpression --- expression7: Unidentified symbol %@.", [parser symbol]);
		p = nil;
	}

	return [p autorelease];
}

+ (id) expression7:(EXPExpressionList *)parser
{
	id p;
	
	BOOL preIncrement = [parser testSymbol:@"++"];
	p = [EXPExpression expression8:parser];
	
	if (preIncrement) {
		EXPUnaryPreIncrement *pp = [[[EXPUnaryPostIncrement alloc] initWithLeft:p] autorelease];
		p = pp;
	}

	return [p autorelease];
}

+ (id) expression6:(EXPExpressionList *)parser
{
	id p = [EXPExpression expression7:parser];
	if (p==nil) {
		return nil;
	}
	
	while ([parser testSymbol:@"^"]) {
		id pp = [EXPExpression expression7:parser];
		if (pp==nil) {
			return nil;
		}

		EXPBinOp *op = [[[EXPPwrOp alloc] initWithLeft:p AndRight:pp] autorelease];
		p = op;
	}

	return [p autorelease];
}

+ (id)expression5:(EXPExpressionList *)parser
{
	BOOL unaryMinus = [parser testSymbol:@"-"];
	(void)[parser testSymbol:@"+"];
	
	id p = [EXPExpression expression6:parser];
	if (p==nil) {
		return nil;
	}

	while ([parser testSymbol:@"*"] || [parser testSymbol:@"/"]) {
		EXPBinOp *op;
		BOOL b = [[parser symbol] isEqualToString:@"*"];
		if (b) {
			op = [[EXPMultOp alloc] initWithLeft:p AndRight:nil];
		} else {
			op = [[EXPDivOp alloc] initWithLeft:p AndRight:nil];
		}
		
		[op autorelease];

		id pp = [EXPExpression expression6:parser];
		if (pp==nil) {
			return nil;
		}

		[op setRight:pp];
		p = op;
	}
	
	if (unaryMinus) {
		EXPUnaryOp *unop = [[[EXPUnaryOp alloc] initWithLeft:p] autorelease];
		p = unop;
	}

	return [p autorelease];
}

+ (id)expression4:(EXPExpressionList *)parser
{
	id p = [EXPExpression expression5:parser];
	if (p==nil) {
		return nil;
	}

	while ([parser testSymbol:@"+"] || [parser testSymbol:@"-"]) {
		EXPBinOp *op;
		BOOL b = [[parser symbol] isEqualToString:@"+"];
		if (b) {
			op = [[EXPAddOp alloc] initWithLeft:p AndRight:nil];
		} else {
			op = [[EXPSubOp alloc] initWithLeft:p AndRight:nil];
		}
		
		[op autorelease];

		id pp = [EXPExpression expression5:parser];
		if (pp==nil) {
			return nil;
		}

		[op setRight:pp];
		p = op;
	}

	return [p autorelease];
}

+ (id)expression3:(EXPExpressionList *)parser
{
	BOOL unaryNot = [parser testSymbol:@"!"];

	id p = [EXPExpression expression4:parser];
	if (p==nil) {
		return nil;
	}
	
	NSString *opstr;
	while ([parser testSymbol:@"<"] || [parser testSymbol:@">"] || [parser testSymbol:@">="] || 
		   [parser testSymbol:@"<="] || [parser testSymbol:@"=="] || [parser testSymbol:@"!="]) {
		opstr = [[NSString alloc] initWithString:[parser symbol]];
		
		id pp = [EXPExpression expression4:parser];
		if (pp==nil) {
			return nil;
		}

		EXPBinOp *op;
		if ([opstr isEqualToString:@"<"]) {
			op = [[EXPLessThanOp alloc] initWithLeft:p AndRight:pp];
		} else if ([opstr isEqualToString:@">"]) {
			op = [[EXPGreaterThanOp alloc] initWithLeft:p AndRight:pp];
		} else if ([opstr isEqualToString:@">="]) {
			op = [[EXPGreaterThanOrEqualToOp alloc] initWithLeft:p AndRight:pp];
		} else if ([opstr isEqualToString:@"<="]) {
			op = [[EXPLessThanOrEqualToOp alloc] initWithLeft:p AndRight:pp];
		} else if ([opstr isEqualToString:@"=="]) {
			op = [[EXPEqualToOp alloc] initWithLeft:p AndRight:pp];
		} else if ([opstr isEqualToString:@"!="]) {
			op = [[EXPNotEqualToOp alloc] initWithLeft:p AndRight:pp];
		}
		[op autorelease];
		[opstr release];
		
		p = op;
	}

	if (unaryNot) {
		EXPUnaryNot *unop = [[[EXPUnaryNot alloc] initWithLeft:p] autorelease];
		p = unop;
	}

	return [p autorelease];
}

+ (id)expression2:(EXPExpressionList *)parser
{
	id p = [EXPExpression expression3:parser];
	if (p==nil) {
		return nil;
	}
	
	while ([parser testSymbol:@"and"]) {
		id pp = [EXPExpression expression3:parser];
		if (pp==nil) {
			return nil;
		}

		EXPBinOp *op = [[[EXPAndOp alloc] initWithLeft:p AndRight:pp] autorelease];
		p = op;
	}

	return [p autorelease];
}

+ (id)expression1:(EXPExpressionList *)parser
{
	id p = [EXPExpression expression2:parser];
	if (p==nil) {
		return nil;
	}
	
	while ([parser testSymbol:@"or"]) {
		id pp = [EXPExpression expression2:parser];
		if (pp==nil) {
			return nil;
		}

		EXPBinOp *op = [[[EXPOrOp alloc] initWithLeft:p AndRight:pp] autorelease];
		p = op;
	}
	
	return [p autorelease];
}

+ (id)expression:(EXPExpressionList *)parser
{
	id p = [EXPExpression expression1:parser];
	if (p==nil) {
		return nil;
	}
	
	if ([parser testSymbol:@"?"]) {
		id p1 = [EXPExpression expression1:parser];
		if (p1==nil) {
			return nil;
		}
		
		if (![parser testSymbol:@":"]) {
			return nil;
		}
		
		id p2 = [EXPExpression expression1:parser];
		if (p2==nil) {
			return nil;
		}
		
		EXPTernOp *op = [[[EXPTernOp alloc] initWithLeft:p andRight:p1 andThird:p2] autorelease];
		p = op;
	}

	return [p autorelease];
}

+ (int) numEXPExpressionsInited
{
	return _numEXPExpressionsInited;
}

+ (int) numEXPExpressionsDealloced
{
	return _numEXPExpressionsDealloced;
}

- (id) init
{
	[super init];
	_expressionId = _numEXPExpressionsInited++;
//	printf("Initialising EXPExpression %d\n", _expressionId);
//	if (_expressionId==20) {
//		printf("Ooooh...\n");
//	}
	return self;
}

- (double) result:(EXPSymbolTable *)symbolTable
{
	return 0.0;
}

/*- (BOOL) compile:(EXPSymbolTable *)symbolTable machine:(EXPMachine *)machine
{
	return NO;
} */

- (NSString *)description
{
	return @"Expression";
} 

- (void) dealloc
{
//	printf("Deallocating EXPExpression %d\n", _expressionId);
	_numEXPExpressionsDealloced++;
	[super dealloc];
}

@end
