From b50c44457820e63de584048c1442a0353bd4270c Mon Sep 17 00:00:00 2001 From: Kim Wittenburg Date: Sat, 13 Sep 2014 23:16:44 +0200 Subject: [PATCH] Redesign of the Evaluation System --- MathPad/MPElementParser.h | 4 +- MathPad/MPElementParser.m | 135 ++++++++++++---------------- MathPad/MPEvaluationContext.h | 23 +++++ MathPad/MPEvaluationContext.m | 63 +++++++++++++ MathPad/MPExpressionEvaluator.h | 6 -- MathPad/MPExpressionEvaluator.m | 40 +++------ MathPad/MPFunction+MPParsedFactor.h | 14 +++ MathPad/MPFunction+MPParsedFactor.m | 30 +++++++ MathPad/MPFunction.h | 2 +- MathPad/MPFunction.m | 2 +- MathPad/MPParsedFactor.h | 16 ++-- MathPad/MPParsedNumber.h | 16 ++++ MathPad/MPParsedNumber.m | 42 +++++++++ MathPad/MPParsedOperator.h | 17 ++++ MathPad/MPParsedOperator.m | 54 +++++++++++ MathPad/MPParsedProduct.h | 8 +- MathPad/MPParsedProduct.m | 21 ++++- MathPad/MPParsedVariable.h | 16 ++++ MathPad/MPParsedVariable.m | 47 ++++++++++ MathPad/MPSumFunction.m | 10 ++- 20 files changed, 431 insertions(+), 135 deletions(-) create mode 100644 MathPad/MPEvaluationContext.h create mode 100644 MathPad/MPEvaluationContext.m create mode 100644 MathPad/MPFunction+MPParsedFactor.h create mode 100644 MathPad/MPFunction+MPParsedFactor.m create mode 100644 MathPad/MPParsedNumber.h create mode 100644 MathPad/MPParsedNumber.m create mode 100644 MathPad/MPParsedOperator.h create mode 100644 MathPad/MPParsedOperator.m create mode 100644 MathPad/MPParsedVariable.h create mode 100644 MathPad/MPParsedVariable.m diff --git a/MathPad/MPElementParser.h b/MathPad/MPElementParser.h index 8493765..b8999a1 100644 --- a/MathPad/MPElementParser.h +++ b/MathPad/MPElementParser.h @@ -25,13 +25,13 @@ - (NSArray *)parseElement:(NSString *)string previousProduct:(MPParsedProduct *)previousProduct - nextFactor:(MPParsedFactor *)nextFactor + nextFactor:(id)nextFactor definesVariable:(BOOL)flag definedVariable:(NSString *__autoreleasing *)variableName error:(out MPParseError *__autoreleasing *)error; - (NSArray *)parseElement:(NSString *)string previousProduct:(MPParsedProduct *)previousProduct - nextFactor:(MPParsedFactor *)nextFactor + nextFactor:(id)nextFactor error:(out MPParseError *__autoreleasing *)error; @end diff --git a/MathPad/MPElementParser.m b/MathPad/MPElementParser.m index 83a329d..8faca88 100644 --- a/MathPad/MPElementParser.m +++ b/MathPad/MPElementParser.m @@ -9,6 +9,11 @@ #import "MPElementParser.h" #import "NSRegularExpression+MPParsingAdditions.h" +#import "MPParsedFactor.h" +#import "MPParsedNumber.h" +#import "MPParsedVariable.h" +#import "MPParsedOperator.h" + #define MPMultiplicationSymbol @"*" @interface MPElementParser () @@ -24,11 +29,8 @@ - (NSRange)parseWhitespaces; - (NSRange)parseMultiplicationSymbol; -- (NSRange)parseOperators; -- (NSUInteger)countOperatorsInRange:(NSRange)range - multiplicator:(out NSDecimalNumber *__autoreleasing *)multiplicator; -- (NSRange)parseNumber; -- (NSDecimalNumber *)numberInRange:(NSRange)range; +- (MPParsedOperator *)parseOperators; +- (MPParsedNumber *)parseNumber; @end @@ -84,7 +86,7 @@ static BOOL useUserDefaults; - (NSArray *)parseElement:(NSString *)string previousProduct:(MPParsedProduct *)previousProduct - nextFactor:(MPParsedFactor *)nextFactor + nextFactor:(id)nextFactor error:(out MPParseError *__autoreleasing *)error { return [self parseElement:string @@ -97,7 +99,7 @@ static BOOL useUserDefaults; - (NSArray *)parseElement:(NSString *)string previousProduct:(MPParsedProduct *)previousProduct - nextFactor:(MPParsedFactor *)nextFactor + nextFactor:(id)nextFactor definesVariable:(BOOL)flag definedVariable:(NSString *__autoreleasing *)variableName error:(out MPParseError *__autoreleasing *)error @@ -123,90 +125,86 @@ static BOOL useUserDefaults; NSMutableArray *products = [[NSMutableArray alloc] init]; MPParsedProduct *currentProduct = previousProduct; - while (![self isAtEnd]) { + while (YES) { [self parseWhitespaces]; NSRange multiplicationSymbolRange = [self parseMultiplicationSymbol]; BOOL hasMultiplicationSymbol = multiplicationSymbolRange.location != NSNotFound; - NSRange operatorsRange = [self parseOperators]; - BOOL hasOperators = operatorsRange.location != NSNotFound; + MPParsedOperator *operators = [self parseOperators]; // NSRange functionRange = ... // BOOL hasFunction = functionRange.location != NSNotFound; - - NSRange numberRange = [self parseNumber]; - BOOL hasNumber = numberRange.location != NSNotFound; - - - NSDecimalNumber *operatorMultiplicator; - NSUInteger operatorCount = [self countOperatorsInRange:operatorsRange - multiplicator:&operatorMultiplicator]; - if (!hasNumber) { + MPParsedNumber *number = [self parseNumber]; + + + if (!number.exists) { if ([self isAtEnd] && nextFactor != nil) { if (hasMultiplicationSymbol) { - if (operatorCount > self.maximumOperatorChainLengthInFunction) { - self.error = MPParseError(operatorsRange, @"Too many operators in multiplication."); + if (operators.numberOfOperators > self.maximumOperatorChainLengthInFunction) { + self.error = MPParseError(operators.range, @"Too many operators in multiplication."); return nil; } - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:operatorMultiplicator]]; - } else if (hasOperators) { - if (operatorCount > self.maximumOperatorChainLength) { - self.error = MPParseError(operatorsRange, @"Too many operators."); + [currentProduct addFactor:operators]; + } else if (operators.exists) { + if (operators.numberOfOperators > self.maximumOperatorChainLength) { + self.error = MPParseError(operators.range, @"Too many operators."); return nil; } [products addObject:currentProduct]; currentProduct = [[MPParsedProduct alloc] init]; - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:[[NSDecimalNumber alloc] initWithUnsignedInteger:operatorCount]]]; + [currentProduct addFactor:operators]; } else if (self.allowsImplicitMultiplications) { + NSLog(@"Here I am"); if (!currentProduct) { currentProduct = [[MPParsedProduct alloc] init]; } } else { + NSLog(@"ERR"); self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Implicit Multiplication not allowed."); return nil; } break; } else if ([self isAtEnd]) { - self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Unexpected End. Expected Number."); - return nil; + if (hasMultiplicationSymbol || operators.exists) { + self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Unexpected End. Expected Number."); + return nil; + } } else { self.error = MPParseError(NSMakeRange(self.parsePosition, 1), @"Unexpected Symbol. Expected Number."); return nil; } + break; } else { - NSDecimalNumber *number = [self numberInRange:numberRange]; - NSDecimalNumber *value = [operatorMultiplicator decimalNumberByMultiplyingBy:number]; - if (hasMultiplicationSymbol) { if (currentProduct) { - if (operatorCount > self.maximumOperatorChainLengthInMultiplication) { - self.error = MPParseError(operatorsRange, @"Too many operators in multiplication."); + if (operators.numberOfOperators > self.maximumOperatorChainLengthInMultiplication) { + self.error = MPParseError(operators.range, @"Too many operators in multiplication."); return nil; } - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; + [currentProduct addFactor:operators]; + [currentProduct addFactor:number]; } else { self.error = MPParseError(multiplicationSymbolRange, @"Unexpected Symbol. Expected Number."); return nil; } - } else if (hasOperators) { - if (operatorCount > self.maximumOperatorChainLength) { - self.error = MPParseError(operatorsRange, @"Too many operators."); + } else if (operators.exists) { + if (operators.numberOfOperators > self.maximumOperatorChainLength) { + self.error = MPParseError(operators.range, @"Too many operators."); return nil; } if (currentProduct) { [products addObject:currentProduct]; } - currentProduct = [[MPParsedProduct alloc] init]; - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; + currentProduct = [[MPParsedProduct alloc] initWithFactor:operators]; + [currentProduct addFactor:number]; } else if (!currentProduct) { - currentProduct = [[MPParsedProduct alloc] init]; - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; + currentProduct = [[MPParsedProduct alloc] initWithFactor:number]; } else if (self.allowsImplicitMultiplications) { - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; + [currentProduct addFactor:number]; } else { - self.error = MPParseError(NSMakeRange(numberRange.location, 0), @"Implicit Multiplication not allowed."); + self.error = MPParseError(NSMakeRange(number.range.location, 0), @"Implicit Multiplication not allowed."); return nil; } } @@ -276,7 +274,7 @@ static NSRegularExpression *multiplicationSymbolRegex; } static NSRegularExpression *operatorsRegex; -- (NSRange)parseOperators +- (MPParsedOperator *)parseOperators { if (!operatorsRegex) { operatorsRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([+-](?:\\s*[+-])*)\\s*" @@ -285,33 +283,18 @@ static NSRegularExpression *operatorsRegex; } NSTextCheckingResult *match = [operatorsRegex firstMatchInString:self.input fromIndex:self.parsePosition]; - if (match == nil) { - return NSMakeRange(NSNotFound, 0); + NSRange matchRange; + if (!match) { + matchRange = NSMakeRange(NSNotFound, 0); + } else { + self.parsePosition = NSMaxRange(match.range); + matchRange = [match rangeAtIndex:1]; } - self.parsePosition = NSMaxRange(match.range); - return [match rangeAtIndex:1]; + return [[MPParsedOperator alloc] initWithRange:matchRange + inString:self.input]; } -- (NSUInteger)countOperatorsInRange:(NSRange)range - multiplicator:(out NSDecimalNumber *__autoreleasing *)outMultiplicator -{ - if (range.location == NSNotFound) { - *outMultiplicator = [NSDecimalNumber one]; - return 0; - } - NSString *operatorsString = [self.input substringWithRange:range]; - NSString *operators = [[operatorsString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""]; - NSInteger multiplicator = 1; - for (NSUInteger characterIndex; characterIndex < operators.length; characterIndex++) { - if ([[operators substringWithRange:NSMakeRange(characterIndex, 1)] isEqualToString:@"-"]) { - multiplicator *= -1; - } - } - *outMultiplicator = [[NSDecimalNumber alloc] initWithInteger:multiplicator]; - return operators.length; -} - -- (NSRange)parseNumber +- (MPParsedNumber *)parseNumber { NSString *decimalSeparatorRegexString = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]]; NSString *numberRegexFormat = [NSString stringWithFormat:@"\\A\\s*((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))\\s*", decimalSeparatorRegexString, decimalSeparatorRegexString]; @@ -320,17 +303,15 @@ static NSRegularExpression *operatorsRegex; error:NULL]; NSTextCheckingResult *match = [numberRegex firstMatchInString:self.input fromIndex:self.parsePosition]; + NSRange matchRange; if (!match) { - return NSMakeRange(NSNotFound, 0); + matchRange = NSMakeRange(NSNotFound, 0); + } else { + self.parsePosition = NSMaxRange(match.range); + matchRange = [match rangeAtIndex:1]; } - self.parsePosition = NSMaxRange(match.range); - return [match rangeAtIndex:1]; -} - -- (NSDecimalNumber *)numberInRange:(NSRange)range -{ - NSString *numberString = [self.input substringWithRange:range]; - return [NSDecimalNumber decimalNumberWithString:numberString]; + return [[MPParsedNumber alloc] initWithRange:matchRange + inString:self.input]; } @end diff --git a/MathPad/MPEvaluationContext.h b/MathPad/MPEvaluationContext.h new file mode 100644 index 0000000..1452d77 --- /dev/null +++ b/MathPad/MPEvaluationContext.h @@ -0,0 +1,23 @@ +// +// MPEvaluationContext.h +// MathPad +// +// Created by Kim Wittenburg on 12.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import + +@interface MPEvaluationContext : NSObject + ++ (MPEvaluationContext *)sharedContext; + +- (void)push; +- (void)pop; + +- (void)bindValue:(NSDecimalNumber *)value toName:(NSString *)variableName; +- (void)unbindVariableName:(NSString *)variableName; + +- (NSDecimalNumber *)valueForVariableName:(NSString *)variableName; + +@end diff --git a/MathPad/MPEvaluationContext.m b/MathPad/MPEvaluationContext.m new file mode 100644 index 0000000..280282c --- /dev/null +++ b/MathPad/MPEvaluationContext.m @@ -0,0 +1,63 @@ +// +// MPEvaluationContext.m +// MathPad +// +// Created by Kim Wittenburg on 12.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPEvaluationContext.h" + +@interface MPEvaluationContext () +@property (nonatomic, strong) NSMutableArray *stack; +@end + +@implementation MPEvaluationContext + +static MPEvaluationContext *sharedContext; ++ (MPEvaluationContext *)sharedContext +{ + if (!sharedContext) { + sharedContext = [[MPEvaluationContext alloc] init]; + } + return sharedContext; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _stack = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)push +{ + [self.stack addObject:[[NSMutableDictionary alloc] init]]; +} + +- (void)pop +{ + [self.stack removeLastObject]; +} + +- (void)bindValue:(NSDecimalNumber *)value toName:(NSString *)variableName +{ + NSMutableDictionary *currentBindings = self.stack.lastObject; + currentBindings[variableName] = value; +} + +- (void)unbindVariableName:(NSString *)variableName +{ + NSMutableDictionary *currentBindings = self.stack.lastObject; + [currentBindings removeObjectForKey:variableName]; +} + +- (NSDecimalNumber *)valueForVariableName:(NSString *)variableName +{ + NSMutableDictionary *currentBindings = self.stack.lastObject; + return currentBindings[variableName]; +} + +@end diff --git a/MathPad/MPExpressionEvaluator.h b/MathPad/MPExpressionEvaluator.h index 56a894d..f901c1c 100644 --- a/MathPad/MPExpressionEvaluator.h +++ b/MathPad/MPExpressionEvaluator.h @@ -16,15 +16,9 @@ // Do not instanciate yourself, use evaluator property of MPExpression instead - (instancetype)initWithExpression:(MPExpression *)expression; - @property (readonly, nonatomic, weak) MPExpression *expression; #pragma mark Evaluating Expressions -@property (readonly, nonatomic, strong) NSDictionary *variableBindings; - -- (void)bindValue:(NSDecimalNumber *)value toVariableName:(NSString *)name; -- (void)unbindVariableName:(NSString *)name; - @property (readonly, nonatomic, strong) NSString *definedVariable; - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error; diff --git a/MathPad/MPExpressionEvaluator.m b/MathPad/MPExpressionEvaluator.m index accc3ae..7bc464d 100644 --- a/MathPad/MPExpressionEvaluator.m +++ b/MathPad/MPExpressionEvaluator.m @@ -9,6 +9,8 @@ #import "MPExpressionEvaluator.h" #import "MPExpression.h" #import "MPFunction.h" +#import "MPParsedFactor.h" +#import "MPFunction+MPParsedFactor.h" @interface MPExpressionEvaluator () @property (readwrite, nonatomic, strong) NSString *definedVariable; @@ -16,7 +18,6 @@ @end @implementation MPExpressionEvaluator { - NSMutableDictionary *_variableBindings; MPElementParser *parser; } - (id)initWithExpression:(MPExpression *)expression @@ -24,29 +25,12 @@ 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]; @@ -68,14 +52,10 @@ id element = [self.expression elementAtIndex:elementIndex]; if ([element isString]) { - MPParsedFactor *nextFactor = nil; + id 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]; + nextFactor = nextFunction; } NSArray *newProducts; @@ -105,14 +85,10 @@ elementIndex++; } else { - NSDecimalNumber *functionValue = [(MPFunction *)element evaluate:error]; - if (!functionValue) { - return nil; - } if (!currentProduct) { currentProduct = [[MPParsedProduct alloc] init]; } - [currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:functionValue]]; + [currentProduct addFactor:(MPFunction *)element]; } } @@ -120,7 +96,11 @@ NSDecimalNumber *value = [NSDecimalNumber zero]; for (MPParsedProduct *product in products) { - value = [value decimalNumberByAdding:product.value]; + NSDecimalNumber *productValue = [product evaluateWithError:error]; + if (!productValue) { + return nil; + } + value = [value decimalNumberByAdding:productValue]; } return value; } diff --git a/MathPad/MPFunction+MPParsedFactor.h b/MathPad/MPFunction+MPParsedFactor.h new file mode 100644 index 0000000..a1a7469 --- /dev/null +++ b/MathPad/MPFunction+MPParsedFactor.h @@ -0,0 +1,14 @@ +// +// MPFunction+MPParsedFactor.h +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import +#import "MPParsedFactor.h" + +@interface MPFunction (MPParsedFactor) + +@end diff --git a/MathPad/MPFunction+MPParsedFactor.m b/MathPad/MPFunction+MPParsedFactor.m new file mode 100644 index 0000000..fc963e3 --- /dev/null +++ b/MathPad/MPFunction+MPParsedFactor.m @@ -0,0 +1,30 @@ +// +// MPFunction+MPParsedFactor.m +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPFunction+MPParsedFactor.h" + +@implementation MPFunction (MPParsedFactor) + +- (instancetype)initWithRange:(NSRange)range + inString:(NSString *)string +{ + return [self init]; +} + +- (BOOL)exists +{ + return YES; +} + +- (NSRange)range +{ + NSUInteger selfIndex = [self.parent indexOfElement:self]; + return NSMakeRange([self.parent locationOfElementAtIndex:selfIndex], 1); +} + +@end diff --git a/MathPad/MPFunction.h b/MathPad/MPFunction.h index 1acffbb..1cbbc2b 100644 --- a/MathPad/MPFunction.h +++ b/MathPad/MPFunction.h @@ -38,7 +38,7 @@ - (id)elementAtIndexPath:(NSIndexPath *)indexPath; #pragma mark Evaluating Functions -- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error; +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error; #pragma mark Messages - (void)didChangeElementsInRangePath:(MPRangePath *)rangePath diff --git a/MathPad/MPFunction.m b/MathPad/MPFunction.m index 9ba535a..0ae055e 100644 --- a/MathPad/MPFunction.m +++ b/MathPad/MPFunction.m @@ -82,7 +82,7 @@ } #pragma mark Evaluating Functions -- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error { return [NSDecimalNumber zero]; } diff --git a/MathPad/MPParsedFactor.h b/MathPad/MPParsedFactor.h index 280e4b3..46e6999 100644 --- a/MathPad/MPParsedFactor.h +++ b/MathPad/MPParsedFactor.h @@ -2,21 +2,19 @@ // MPParsedFactor.h // MathPad // -// Created by Kim Wittenburg on 10.09.14. +// Created by Kim Wittenburg on 13.09.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import +#import "MPParseError.h" -@interface MPParsedFactor : NSObject +@protocol MPParsedFactor -+ (MPParsedFactor *)factorWithDecimalNumber:(NSDecimalNumber *)number; -+ (MPParsedFactor *)sinFactorWithFactor:(MPParsedFactor *)factor; -+ (MPParsedFactor *)cosFactorWithFactor:(MPParsedFactor *)factor; -+ (MPParsedFactor *)tanFactorWithFactor:(MPParsedFactor *)factor; +- (instancetype)initWithRange:(NSRange)range inString:(NSString *)string; -- (instancetype)initWithDecimalNumber:(NSDecimalNumber *)number; - -- (NSDecimalNumber *)value; +- (NSRange)range; +- (BOOL)exists; +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error; @end diff --git a/MathPad/MPParsedNumber.h b/MathPad/MPParsedNumber.h new file mode 100644 index 0000000..7bf9368 --- /dev/null +++ b/MathPad/MPParsedNumber.h @@ -0,0 +1,16 @@ +// +// MPParsedNumber.h +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import +#import "MPParsedFactor.h" + +@interface MPParsedNumber : NSObject + +- (NSDecimalNumber *)number; + +@end diff --git a/MathPad/MPParsedNumber.m b/MathPad/MPParsedNumber.m new file mode 100644 index 0000000..f0be1e7 --- /dev/null +++ b/MathPad/MPParsedNumber.m @@ -0,0 +1,42 @@ +// +// MPParsedNumber.m +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPParsedNumber.h" + +@interface MPParsedNumber () +@property (nonatomic) NSRange range; +@property (nonatomic, strong) NSDecimalNumber *number; +@end + +@implementation MPParsedNumber + +- (instancetype)initWithRange:(NSRange)range + inString:(NSString *)string +{ + self = [super init]; + if (self) { + _range = range; + if (range.location != NSNotFound) { + NSString *stringValue = [string substringWithRange:range]; + _number = [NSDecimalNumber decimalNumberWithString:stringValue]; + } + } + return self; +} + +- (BOOL)exists +{ + return self.range.location != NSNotFound; +} + +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error +{ + return self.number; +} + +@end diff --git a/MathPad/MPParsedOperator.h b/MathPad/MPParsedOperator.h new file mode 100644 index 0000000..040b159 --- /dev/null +++ b/MathPad/MPParsedOperator.h @@ -0,0 +1,17 @@ +// +// MPParsedOperator.h +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import +#import "MPParsedFactor.h" + +@interface MPParsedOperator : NSObject + +- (NSUInteger)numberOfOperators; +- (NSDecimalNumber *)multiplicator; + +@end diff --git a/MathPad/MPParsedOperator.m b/MathPad/MPParsedOperator.m new file mode 100644 index 0000000..aacdee1 --- /dev/null +++ b/MathPad/MPParsedOperator.m @@ -0,0 +1,54 @@ +// +// MPParsedOperator.m +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPParsedOperator.h" + +@interface MPParsedOperator () +@property (nonatomic) NSRange range; +@property (nonatomic) NSUInteger numberOfOperators; +@property (nonatomic, strong) NSDecimalNumber *multiplicator; +@end + +@implementation MPParsedOperator + +- (instancetype)initWithRange:(NSRange)range + inString:(NSString *)string +{ + self = [super init]; + if (self) { + _range = range; + if (range.location == NSNotFound) { + _multiplicator = [NSDecimalNumber one]; + _numberOfOperators = 0; + } else { + NSString *stringValue = [string substringWithRange:range]; + NSString *operators = [[stringValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""]; + NSInteger multiplicator = 1; + for (NSUInteger characterIndex = 0; characterIndex < operators.length; characterIndex++) { + if ([[operators substringWithRange:NSMakeRange(characterIndex, 1)] isEqualToString:@"-"]) { + multiplicator *= -1; + } + } + _multiplicator = [[NSDecimalNumber alloc] initWithInteger:multiplicator]; + _numberOfOperators = operators.length; + } + } + return self; +} + +- (BOOL)exists +{ + return self.range.location != NSNotFound; +} + +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error +{ + return self.multiplicator; +} + +@end diff --git a/MathPad/MPParsedProduct.h b/MathPad/MPParsedProduct.h index e9cb974..19dbcdc 100644 --- a/MathPad/MPParsedProduct.h +++ b/MathPad/MPParsedProduct.h @@ -11,10 +11,12 @@ @interface MPParsedProduct : NSObject +- (instancetype)init; // designated initializer +- (instancetype)initWithFactor:(id)factor; // designated initializer. + @property (readonly, nonatomic, strong) NSArray *factors; +- (void)addFactor:(id)factor; -- (void)addFactor:(MPParsedFactor *)factor; - -- (NSDecimalNumber *)value; +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error; @end diff --git a/MathPad/MPParsedProduct.m b/MathPad/MPParsedProduct.m index 738fc91..c12e654 100644 --- a/MathPad/MPParsedProduct.m +++ b/MathPad/MPParsedProduct.m @@ -21,24 +21,37 @@ return self; } +- (instancetype)initWithFactor:(id)factor +{ + self = [super init]; + if (self) { + _factors = [[NSMutableArray alloc] initWithObjects:factor, nil]; + } + return self; +} + - (NSArray *)factors { return _factors; } -- (void)addFactor:(MPParsedFactor *)factor +- (void)addFactor:(id)factor { [_factors addObject:factor]; } -- (NSDecimalNumber *)value +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error { if (_factors.count == 0) { return [NSDecimalNumber zero]; } NSDecimalNumber *value = [NSDecimalNumber one]; - for (MPParsedFactor *factor in _factors) { - value = [value decimalNumberByMultiplyingBy:factor.value]; + for (id factor in _factors) { + NSDecimalNumber *factorValue = [factor evaluateWithError:error]; + if (!factorValue) { + return nil; + } + value = [value decimalNumberByMultiplyingBy:factorValue]; } return value; } diff --git a/MathPad/MPParsedVariable.h b/MathPad/MPParsedVariable.h new file mode 100644 index 0000000..6b1ff7f --- /dev/null +++ b/MathPad/MPParsedVariable.h @@ -0,0 +1,16 @@ +// +// MPParsedVariable.h +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import +#import "MPParsedFactor.h" + +@interface MPParsedVariable : NSObject + +- (NSString *)variableName; + +@end diff --git a/MathPad/MPParsedVariable.m b/MathPad/MPParsedVariable.m new file mode 100644 index 0000000..7dce021 --- /dev/null +++ b/MathPad/MPParsedVariable.m @@ -0,0 +1,47 @@ +// +// MPParsedVariable.m +// MathPad +// +// Created by Kim Wittenburg on 13.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPParsedVariable.h" +#import "MPEvaluationContext.h" + +@interface MPParsedVariable () +@property (nonatomic) NSRange range; +@property (nonatomic, strong) NSString *variableName; +@end + +@implementation MPParsedVariable + +- (instancetype)initWithRange:(NSRange)range + inString:(NSString *)string +{ + self = [super init]; + if (self) { + _range = range; + if (range.location != NSNotFound) { + _variableName = [string substringWithRange:range]; + } + } + return self; +} + +- (BOOL)exists +{ + return self.range.location != NSNotFound; +} + +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error +{ + NSDecimalNumber *value = [[MPEvaluationContext sharedContext] valueForVariableName:self.variableName]; + if (!value) { + *error = MPParseError(self.range, @"Undefined Variable."); + return nil; + } + return value; +} + +@end diff --git a/MathPad/MPSumFunction.m b/MathPad/MPSumFunction.m index 93af0e6..8c2c9e1 100644 --- a/MathPad/MPSumFunction.m +++ b/MathPad/MPSumFunction.m @@ -10,6 +10,7 @@ #import "MPExpression.h" #import "MPExpressionEvaluator.h" +#import "MPEvaluationContext.h" @implementation MPSumFunction @@ -99,7 +100,7 @@ } #pragma mark Evaluating Functions -- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error +- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error { MPExpressionEvaluator *startEvaluator = self.startExpression.evaluator; NSDecimalNumber *start = [startEvaluator evaluateVariableDefinition:YES error:error]; @@ -111,10 +112,12 @@ return nil; } + [[MPEvaluationContext sharedContext] push]; + MPExpressionEvaluator *sumEvaluator = self.sumExpression.evaluator; NSDecimalNumber *value = [NSDecimalNumber zero]; for (NSDecimalNumber *iterator = start; [iterator compare:target] <= 0; iterator = [iterator decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:1]]) { - [sumEvaluator bindValue:iterator toVariableName:startEvaluator.definedVariable]; + [[MPEvaluationContext sharedContext] bindValue:iterator toName:startEvaluator.definedVariable]; NSDecimalNumber *summand = [sumEvaluator evaluateWithError:error]; if (summand) { value = [value decimalNumberByAdding:summand]; @@ -122,6 +125,9 @@ return nil; } } + + [[MPEvaluationContext sharedContext] pop]; + return value; }