// // 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" #import "MPFunction.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 { // Empty Expression if (self.expression.numberOfElements == 0) { *error = MPParseError(NSMakeRange(0, 0), @"Expected Expression"); return nil; } NSMutableArray *products = [[NSMutableArray alloc] init]; MPParsedProduct *currentProduct = nil; for (NSUInteger elementIndex = 0; elementIndex < self.expression.numberOfElements; elementIndex++) { id element = [self.expression elementAtIndex:elementIndex]; if ([element isString]) { 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; } 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 *functionValue = [(MPFunction *)element evaluate:error]; if (!functionValue) { return nil; } if (!currentProduct) { currentProduct = [[MPParsedProduct alloc] init]; } [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:functionValue]]; } } [products addObject:currentProduct]; NSDecimalNumber *value = [NSDecimalNumber zero]; for (MPParsedProduct *product in products) { value = [value decimalNumberByAdding:product.value]; } return value; } @end