Archived
1

Implemented Expression Evaluation/Parsing with Proper Error Handling

This commit is contained in:
Kim Wittenburg
2014-09-11 22:17:29 +02:00
parent f791213127
commit 245468a559
16 changed files with 670 additions and 330 deletions

View File

@@ -8,9 +8,11 @@
#import "MPExpressionEvaluator.h"
#import "MPExpression.h"
#import "MPFunction.h"
@interface MPExpressionEvaluator ()
@property (readwrite, nonatomic, strong) NSString *definedVariable;
@end
@implementation MPExpressionEvaluator {
@@ -52,146 +54,74 @@
- (NSDecimalNumber *)evaluateVariableDefinition:(BOOL)flag error:(MPParseError *__autoreleasing *)error
{
#warning Implement Cache
// Empty Expression
if (self.expression.numberOfElements == 0) {
if (error) {
*error = MPParseError(0, @"Empty Expression");
}
*error = MPParseError(NSMakeRange(0, 0), @"Expected Expression");
return nil;
}
// Expression of just one element
if (self.expression.numberOfElements == 1) {
id<MPExpressionElement> singleElement = [self.expression elementAtIndex:0];
if ([singleElement isString]) {
MPParsedElement *parseResult = [parser parseElement:(NSString *)singleElement
error:error];
if ([parseResult isValidStandaloneElement:error]) {
if (flag && parseResult.definedVariable) {
self.definedVariable = parseResult.definedVariable;
} else if (flag) {
if (error) {
*error = MPParseError(0, @"Expected Variable Definition");
}
return nil;
} else if (parseResult.definedVariable) {
if (error) {
*error = MPParseError(0, @"Unexpected Variable Definition");
}
return nil;
}
return parseResult.standaloneValue;
} else {
return nil;
}
} else {
return [singleElement evaluate:error];
}
}
// Expression with any number of elements
NSDecimalNumber *value = [NSDecimalNumber zero];
NSDecimalNumber *currentSummand = nil;
NSMutableArray *products = [[NSMutableArray alloc] init];
MPParsedProduct *currentProduct = nil;
// Process the first element
id<MPExpressionElement> firstElement = [self.expression elementAtIndex:0];
if ([firstElement isString]) {
MPParsedElement *parseResult = [parser parseElement:(NSString *)firstElement
error:error];
if (parseResult && [parseResult isValidElementAtBeginning:error]) {
if (flag && parseResult.definedVariable) {
self.definedVariable = parseResult.definedVariable;
} else if (flag) {
if (error) {
*error = MPParseError(0, @"Expected Variable Definition");
}
return nil;
} else if (parseResult.definedVariable) {
if (error) {
*error = MPParseError(0, @"Unexpected Variable Definition");
}
return nil;
}
if ([parseResult isFactor]) {
currentSummand = parseResult.value;
} else {
value = [parseResult valueAtBeginning];
currentSummand = parseResult.suffixMultiplicator;
}
}
} else {
currentSummand = [firstElement evaluate:error];
}
if (!currentSummand) {
return nil;
}
// Process the elements between the first and last element
for (NSUInteger index = 1; index < self.expression.numberOfElements-1; index++) {
id<MPExpressionElement> element = [self.expression elementAtIndex:index];
for (NSUInteger elementIndex = 0; elementIndex < self.expression.numberOfElements; elementIndex++) {
id<MPExpressionElement> element = [self.expression elementAtIndex:elementIndex];
if ([element isString]) {
MPParsedElement *parseResult = [parser parseElement:(NSString *)element
error:error];
if (parseResult) {
if (parseResult.definedVariable) {
if (error) {
*error = MPParseError(index, @"Unexpected Variable Definition");
}
MPParsedFactor *nextFactor = nil;
if (elementIndex < self.expression.numberOfElements - 1) {
MPFunction *nextFunction = (MPFunction *)[self.expression elementAtIndex:elementIndex+1];
NSDecimalNumber *functionValue = [nextFunction evaluate:error];
if (!functionValue) {
return nil;
}
if ([parseResult isFactor]) {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:parseResult.value];
} else {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:parseResult.prefixMultiplicator];
value = [[value decimalNumberByAdding:currentSummand] decimalNumberByAdding:parseResult.value];
currentSummand = parseResult.suffixMultiplicator;
}
nextFactor = [MPParsedFactor factorWithDecimalNumber:functionValue];
}
NSArray *newProducts;
if (elementIndex == 0 && flag) {
NSString *definedVariable;
newProducts = [parser parseElement:(NSString *)element
previousProduct:currentProduct
nextFactor:nextFactor
definesVariable:YES
definedVariable:&definedVariable
error:error];
self.definedVariable = definedVariable;
} else {
newProducts = [parser parseElement:(NSString *)element
previousProduct:currentProduct
nextFactor:nextFactor
error:error];
}
if (!newProducts) {
return nil;
}
for (NSUInteger productIndex = 0; productIndex < newProducts.count-1; productIndex++) {
[products addObject:newProducts[productIndex]];
}
currentProduct = newProducts.lastObject;
elementIndex++;
} else {
NSDecimalNumber *result = [element evaluate:error];
if (result) {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:result];
} else {
NSDecimalNumber *functionValue = [(MPFunction *)element evaluate:error];
if (!functionValue) {
return nil;
}
if (!currentProduct) {
currentProduct = [[MPParsedProduct alloc] init];
}
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:functionValue]];
}
}
// Process the last element
id<MPExpressionElement> lastElement = [self.expression elementAtIndex:self.expression.numberOfElements-1];
if ([lastElement isString]) {
MPParsedElement *parseResult = [parser parseElement:(NSString *)lastElement
error:error];
if (parseResult && [parseResult isValidElementAtEnd:error]) {
if (parseResult.definedVariable) {
if (error) {
*error = MPParseError(0, @"Unexpected Variable Definition");
}
return nil;
}
if ([parseResult isFactor]) {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:parseResult.value];
} else {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:parseResult.prefixMultiplicator];
value = [[value decimalNumberByAdding:currentSummand] decimalNumberByAdding:parseResult.value];
currentSummand = parseResult.suffixMultiplicator;
}
} else {
return nil;
}
} else {
NSDecimalNumber *result = [lastElement evaluate:error];
if (result) {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:result];
} else {
return nil;
}
}
value = [value decimalNumberByAdding:currentSummand];
[products addObject:currentProduct];
NSDecimalNumber *value = [NSDecimalNumber zero];
for (MPParsedProduct *product in products) {
value = [value decimalNumberByAdding:product.value];
}
return value;
}