// // MPExpressionEvaluator.m // MathPad // // Created by Kim Wittenburg on 31.08.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPExpressionEvaluator.h" #import "MPExpression.h" @interface MPExpressionEvaluator () @property (readwrite, nonatomic, strong) NSString *definedVariable; @end @implementation MPExpressionEvaluator { NSMutableDictionary *_variableBindings; MPElementParser *parser; } - (id)initWithExpression:(MPExpression *)expression { self = [super init]; if (self) { _expression = expression; _variableBindings = [[NSMutableDictionary alloc] init]; parser = [[MPElementParser alloc] init]; } return self; } #pragma mark Evaluating Expressions - (NSDictionary *)variableBindings { return [_variableBindings copy]; } - (void)bindValue:(NSDecimalNumber *)value toVariableName:(NSString *)name { [_variableBindings setObject:value forKey:name]; } - (void)unbindVariableName:(NSString *)name { [_variableBindings removeObjectForKey:name]; } - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error { return [self evaluateVariableDefinition:NO error:error]; } - (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"); } return nil; } // Expression of just one element if (self.expression.numberOfElements == 1) { id 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; // Process the first element id 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 element = [self.expression elementAtIndex:index]; if ([element isString]) { MPParsedElement *parseResult = [parser parseElement:(NSString *)element error:error]; if (parseResult) { if (parseResult.definedVariable) { if (error) { *error = MPParseError(index, @"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 = [element evaluate:error]; if (result) { currentSummand = [currentSummand decimalNumberByMultiplyingBy:result]; } else { return nil; } } } // Process the last element id 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]; return value; } @end