Archived
1

Redesign of the Evaluation System

This commit is contained in:
Kim Wittenburg
2014-09-13 23:16:44 +02:00
parent a3e1cc6df4
commit b50c444578
20 changed files with 431 additions and 135 deletions

View File

@@ -25,13 +25,13 @@
- (NSArray *)parseElement:(NSString *)string - (NSArray *)parseElement:(NSString *)string
previousProduct:(MPParsedProduct *)previousProduct previousProduct:(MPParsedProduct *)previousProduct
nextFactor:(MPParsedFactor *)nextFactor nextFactor:(id<MPParsedFactor>)nextFactor
definesVariable:(BOOL)flag definesVariable:(BOOL)flag
definedVariable:(NSString *__autoreleasing *)variableName definedVariable:(NSString *__autoreleasing *)variableName
error:(out MPParseError *__autoreleasing *)error; error:(out MPParseError *__autoreleasing *)error;
- (NSArray *)parseElement:(NSString *)string - (NSArray *)parseElement:(NSString *)string
previousProduct:(MPParsedProduct *)previousProduct previousProduct:(MPParsedProduct *)previousProduct
nextFactor:(MPParsedFactor *)nextFactor nextFactor:(id<MPParsedFactor>)nextFactor
error:(out MPParseError *__autoreleasing *)error; error:(out MPParseError *__autoreleasing *)error;
@end @end

View File

@@ -9,6 +9,11 @@
#import "MPElementParser.h" #import "MPElementParser.h"
#import "NSRegularExpression+MPParsingAdditions.h" #import "NSRegularExpression+MPParsingAdditions.h"
#import "MPParsedFactor.h"
#import "MPParsedNumber.h"
#import "MPParsedVariable.h"
#import "MPParsedOperator.h"
#define MPMultiplicationSymbol @"*" #define MPMultiplicationSymbol @"*"
@interface MPElementParser () @interface MPElementParser ()
@@ -24,11 +29,8 @@
- (NSRange)parseWhitespaces; - (NSRange)parseWhitespaces;
- (NSRange)parseMultiplicationSymbol; - (NSRange)parseMultiplicationSymbol;
- (NSRange)parseOperators; - (MPParsedOperator *)parseOperators;
- (NSUInteger)countOperatorsInRange:(NSRange)range - (MPParsedNumber *)parseNumber;
multiplicator:(out NSDecimalNumber *__autoreleasing *)multiplicator;
- (NSRange)parseNumber;
- (NSDecimalNumber *)numberInRange:(NSRange)range;
@end @end
@@ -84,7 +86,7 @@ static BOOL useUserDefaults;
- (NSArray *)parseElement:(NSString *)string - (NSArray *)parseElement:(NSString *)string
previousProduct:(MPParsedProduct *)previousProduct previousProduct:(MPParsedProduct *)previousProduct
nextFactor:(MPParsedFactor *)nextFactor nextFactor:(id<MPParsedFactor>)nextFactor
error:(out MPParseError *__autoreleasing *)error error:(out MPParseError *__autoreleasing *)error
{ {
return [self parseElement:string return [self parseElement:string
@@ -97,7 +99,7 @@ static BOOL useUserDefaults;
- (NSArray *)parseElement:(NSString *)string - (NSArray *)parseElement:(NSString *)string
previousProduct:(MPParsedProduct *)previousProduct previousProduct:(MPParsedProduct *)previousProduct
nextFactor:(MPParsedFactor *)nextFactor nextFactor:(id<MPParsedFactor>)nextFactor
definesVariable:(BOOL)flag definesVariable:(BOOL)flag
definedVariable:(NSString *__autoreleasing *)variableName definedVariable:(NSString *__autoreleasing *)variableName
error:(out MPParseError *__autoreleasing *)error error:(out MPParseError *__autoreleasing *)error
@@ -123,90 +125,86 @@ static BOOL useUserDefaults;
NSMutableArray *products = [[NSMutableArray alloc] init]; NSMutableArray *products = [[NSMutableArray alloc] init];
MPParsedProduct *currentProduct = previousProduct; MPParsedProduct *currentProduct = previousProduct;
while (![self isAtEnd]) { while (YES) {
[self parseWhitespaces]; [self parseWhitespaces];
NSRange multiplicationSymbolRange = [self parseMultiplicationSymbol]; NSRange multiplicationSymbolRange = [self parseMultiplicationSymbol];
BOOL hasMultiplicationSymbol = multiplicationSymbolRange.location != NSNotFound; BOOL hasMultiplicationSymbol = multiplicationSymbolRange.location != NSNotFound;
NSRange operatorsRange = [self parseOperators]; MPParsedOperator *operators = [self parseOperators];
BOOL hasOperators = operatorsRange.location != NSNotFound;
// NSRange functionRange = ... // NSRange functionRange = ...
// BOOL hasFunction = functionRange.location != NSNotFound; // 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 ([self isAtEnd] && nextFactor != nil) {
if (hasMultiplicationSymbol) { if (hasMultiplicationSymbol) {
if (operatorCount > self.maximumOperatorChainLengthInFunction) { if (operators.numberOfOperators > self.maximumOperatorChainLengthInFunction) {
self.error = MPParseError(operatorsRange, @"Too many operators in multiplication."); self.error = MPParseError(operators.range, @"Too many operators in multiplication.");
return nil; return nil;
} }
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:operatorMultiplicator]]; [currentProduct addFactor:operators];
} else if (hasOperators) { } else if (operators.exists) {
if (operatorCount > self.maximumOperatorChainLength) { if (operators.numberOfOperators > self.maximumOperatorChainLength) {
self.error = MPParseError(operatorsRange, @"Too many operators."); self.error = MPParseError(operators.range, @"Too many operators.");
return nil; return nil;
} }
[products addObject:currentProduct]; [products addObject:currentProduct];
currentProduct = [[MPParsedProduct alloc] init]; currentProduct = [[MPParsedProduct alloc] init];
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:[[NSDecimalNumber alloc] initWithUnsignedInteger:operatorCount]]]; [currentProduct addFactor:operators];
} else if (self.allowsImplicitMultiplications) { } else if (self.allowsImplicitMultiplications) {
NSLog(@"Here I am");
if (!currentProduct) { if (!currentProduct) {
currentProduct = [[MPParsedProduct alloc] init]; currentProduct = [[MPParsedProduct alloc] init];
} }
} else { } else {
NSLog(@"ERR");
self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Implicit Multiplication not allowed."); self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Implicit Multiplication not allowed.");
return nil; return nil;
} }
break; break;
} else if ([self isAtEnd]) { } else if ([self isAtEnd]) {
self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Unexpected End. Expected Number."); if (hasMultiplicationSymbol || operators.exists) {
return nil; self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Unexpected End. Expected Number.");
return nil;
}
} else { } else {
self.error = MPParseError(NSMakeRange(self.parsePosition, 1), @"Unexpected Symbol. Expected Number."); self.error = MPParseError(NSMakeRange(self.parsePosition, 1), @"Unexpected Symbol. Expected Number.");
return nil; return nil;
} }
break;
} else { } else {
NSDecimalNumber *number = [self numberInRange:numberRange];
NSDecimalNumber *value = [operatorMultiplicator decimalNumberByMultiplyingBy:number];
if (hasMultiplicationSymbol) { if (hasMultiplicationSymbol) {
if (currentProduct) { if (currentProduct) {
if (operatorCount > self.maximumOperatorChainLengthInMultiplication) { if (operators.numberOfOperators > self.maximumOperatorChainLengthInMultiplication) {
self.error = MPParseError(operatorsRange, @"Too many operators in multiplication."); self.error = MPParseError(operators.range, @"Too many operators in multiplication.");
return nil; return nil;
} }
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; [currentProduct addFactor:operators];
[currentProduct addFactor:number];
} else { } else {
self.error = MPParseError(multiplicationSymbolRange, @"Unexpected Symbol. Expected Number."); self.error = MPParseError(multiplicationSymbolRange, @"Unexpected Symbol. Expected Number.");
return nil; return nil;
} }
} else if (hasOperators) { } else if (operators.exists) {
if (operatorCount > self.maximumOperatorChainLength) { if (operators.numberOfOperators > self.maximumOperatorChainLength) {
self.error = MPParseError(operatorsRange, @"Too many operators."); self.error = MPParseError(operators.range, @"Too many operators.");
return nil; return nil;
} }
if (currentProduct) { if (currentProduct) {
[products addObject:currentProduct]; [products addObject:currentProduct];
} }
currentProduct = [[MPParsedProduct alloc] init]; currentProduct = [[MPParsedProduct alloc] initWithFactor:operators];
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; [currentProduct addFactor:number];
} else if (!currentProduct) { } else if (!currentProduct) {
currentProduct = [[MPParsedProduct alloc] init]; currentProduct = [[MPParsedProduct alloc] initWithFactor:number];
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]];
} else if (self.allowsImplicitMultiplications) { } else if (self.allowsImplicitMultiplications) {
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:value]]; [currentProduct addFactor:number];
} else { } 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; return nil;
} }
} }
@@ -276,7 +274,7 @@ static NSRegularExpression *multiplicationSymbolRegex;
} }
static NSRegularExpression *operatorsRegex; static NSRegularExpression *operatorsRegex;
- (NSRange)parseOperators - (MPParsedOperator *)parseOperators
{ {
if (!operatorsRegex) { if (!operatorsRegex) {
operatorsRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([+-](?:\\s*[+-])*)\\s*" operatorsRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([+-](?:\\s*[+-])*)\\s*"
@@ -285,33 +283,18 @@ static NSRegularExpression *operatorsRegex;
} }
NSTextCheckingResult *match = [operatorsRegex firstMatchInString:self.input NSTextCheckingResult *match = [operatorsRegex firstMatchInString:self.input
fromIndex:self.parsePosition]; fromIndex:self.parsePosition];
if (match == nil) { NSRange matchRange;
return NSMakeRange(NSNotFound, 0); if (!match) {
matchRange = NSMakeRange(NSNotFound, 0);
} else {
self.parsePosition = NSMaxRange(match.range);
matchRange = [match rangeAtIndex:1];
} }
self.parsePosition = NSMaxRange(match.range); return [[MPParsedOperator alloc] initWithRange:matchRange
return [match rangeAtIndex:1]; inString:self.input];
} }
- (NSUInteger)countOperatorsInRange:(NSRange)range - (MPParsedNumber *)parseNumber
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
{ {
NSString *decimalSeparatorRegexString = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]]; NSString *decimalSeparatorRegexString = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
NSString *numberRegexFormat = [NSString stringWithFormat:@"\\A\\s*((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))\\s*", decimalSeparatorRegexString, decimalSeparatorRegexString]; NSString *numberRegexFormat = [NSString stringWithFormat:@"\\A\\s*((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))\\s*", decimalSeparatorRegexString, decimalSeparatorRegexString];
@@ -320,17 +303,15 @@ static NSRegularExpression *operatorsRegex;
error:NULL]; error:NULL];
NSTextCheckingResult *match = [numberRegex firstMatchInString:self.input NSTextCheckingResult *match = [numberRegex firstMatchInString:self.input
fromIndex:self.parsePosition]; fromIndex:self.parsePosition];
NSRange matchRange;
if (!match) { 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 [[MPParsedNumber alloc] initWithRange:matchRange
return [match rangeAtIndex:1]; inString:self.input];
}
- (NSDecimalNumber *)numberInRange:(NSRange)range
{
NSString *numberString = [self.input substringWithRange:range];
return [NSDecimalNumber decimalNumberWithString:numberString];
} }
@end @end

View File

@@ -0,0 +1,23 @@
//
// MPEvaluationContext.h
// MathPad
//
// Created by Kim Wittenburg on 12.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
@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

View File

@@ -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

View File

@@ -16,15 +16,9 @@
// Do not instanciate yourself, use evaluator property of MPExpression instead // Do not instanciate yourself, use evaluator property of MPExpression instead
- (instancetype)initWithExpression:(MPExpression *)expression; - (instancetype)initWithExpression:(MPExpression *)expression;
@property (readonly, nonatomic, weak) MPExpression *expression; @property (readonly, nonatomic, weak) MPExpression *expression;
#pragma mark Evaluating Expressions #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; @property (readonly, nonatomic, strong) NSString *definedVariable;
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error; - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;

View File

@@ -9,6 +9,8 @@
#import "MPExpressionEvaluator.h" #import "MPExpressionEvaluator.h"
#import "MPExpression.h" #import "MPExpression.h"
#import "MPFunction.h" #import "MPFunction.h"
#import "MPParsedFactor.h"
#import "MPFunction+MPParsedFactor.h"
@interface MPExpressionEvaluator () @interface MPExpressionEvaluator ()
@property (readwrite, nonatomic, strong) NSString *definedVariable; @property (readwrite, nonatomic, strong) NSString *definedVariable;
@@ -16,7 +18,6 @@
@end @end
@implementation MPExpressionEvaluator { @implementation MPExpressionEvaluator {
NSMutableDictionary *_variableBindings;
MPElementParser *parser; MPElementParser *parser;
} }
- (id)initWithExpression:(MPExpression *)expression - (id)initWithExpression:(MPExpression *)expression
@@ -24,29 +25,12 @@
self = [super init]; self = [super init];
if (self) { if (self) {
_expression = expression; _expression = expression;
_variableBindings = [[NSMutableDictionary alloc] init];
parser = [[MPElementParser alloc] init]; parser = [[MPElementParser alloc] init];
} }
return self; return self;
} }
#pragma mark Evaluating Expressions #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 - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
{ {
return [self evaluateVariableDefinition:NO error:error]; return [self evaluateVariableDefinition:NO error:error];
@@ -68,14 +52,10 @@
id<MPExpressionElement> element = [self.expression elementAtIndex:elementIndex]; id<MPExpressionElement> element = [self.expression elementAtIndex:elementIndex];
if ([element isString]) { if ([element isString]) {
MPParsedFactor *nextFactor = nil; id<MPParsedFactor> nextFactor = nil;
if (elementIndex < self.expression.numberOfElements - 1) { if (elementIndex < self.expression.numberOfElements - 1) {
MPFunction *nextFunction = (MPFunction *)[self.expression elementAtIndex:elementIndex+1]; MPFunction *nextFunction = (MPFunction *)[self.expression elementAtIndex:elementIndex+1];
NSDecimalNumber *functionValue = [nextFunction evaluate:error]; nextFactor = nextFunction;
if (!functionValue) {
return nil;
}
nextFactor = [MPParsedFactor factorWithDecimalNumber:functionValue];
} }
NSArray *newProducts; NSArray *newProducts;
@@ -105,14 +85,10 @@
elementIndex++; elementIndex++;
} else { } else {
NSDecimalNumber *functionValue = [(MPFunction *)element evaluate:error];
if (!functionValue) {
return nil;
}
if (!currentProduct) { if (!currentProduct) {
currentProduct = [[MPParsedProduct alloc] init]; currentProduct = [[MPParsedProduct alloc] init];
} }
[currentProduct addFactor:[MPParsedFactor factorWithDecimalNumber:functionValue]]; [currentProduct addFactor:(MPFunction *)element];
} }
} }
@@ -120,7 +96,11 @@
NSDecimalNumber *value = [NSDecimalNumber zero]; NSDecimalNumber *value = [NSDecimalNumber zero];
for (MPParsedProduct *product in products) { 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; return value;
} }

View File

@@ -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 <MathKit/MathKit.h>
#import "MPParsedFactor.h"
@interface MPFunction (MPParsedFactor) <MPParsedFactor>
@end

View File

@@ -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

View File

@@ -38,7 +38,7 @@
- (id)elementAtIndexPath:(NSIndexPath *)indexPath; - (id)elementAtIndexPath:(NSIndexPath *)indexPath;
#pragma mark Evaluating Functions #pragma mark Evaluating Functions
- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error; - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
#pragma mark Messages #pragma mark Messages
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath - (void)didChangeElementsInRangePath:(MPRangePath *)rangePath

View File

@@ -82,7 +82,7 @@
} }
#pragma mark Evaluating Functions #pragma mark Evaluating Functions
- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
{ {
return [NSDecimalNumber zero]; return [NSDecimalNumber zero];
} }

View File

@@ -2,21 +2,19 @@
// MPParsedFactor.h // MPParsedFactor.h
// MathPad // 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. // Copyright (c) 2014 Kim Wittenburg. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "MPParseError.h"
@interface MPParsedFactor : NSObject @protocol MPParsedFactor <NSObject>
+ (MPParsedFactor *)factorWithDecimalNumber:(NSDecimalNumber *)number; - (instancetype)initWithRange:(NSRange)range inString:(NSString *)string;
+ (MPParsedFactor *)sinFactorWithFactor:(MPParsedFactor *)factor;
+ (MPParsedFactor *)cosFactorWithFactor:(MPParsedFactor *)factor;
+ (MPParsedFactor *)tanFactorWithFactor:(MPParsedFactor *)factor;
- (instancetype)initWithDecimalNumber:(NSDecimalNumber *)number; - (NSRange)range;
- (BOOL)exists;
- (NSDecimalNumber *)value; - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
@end @end

16
MathPad/MPParsedNumber.h Normal file
View File

@@ -0,0 +1,16 @@
//
// MPParsedNumber.h
// MathPad
//
// Created by Kim Wittenburg on 13.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPParsedFactor.h"
@interface MPParsedNumber : NSObject <MPParsedFactor>
- (NSDecimalNumber *)number;
@end

42
MathPad/MPParsedNumber.m Normal file
View File

@@ -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

View File

@@ -0,0 +1,17 @@
//
// MPParsedOperator.h
// MathPad
//
// Created by Kim Wittenburg on 13.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPParsedFactor.h"
@interface MPParsedOperator : NSObject <MPParsedFactor>
- (NSUInteger)numberOfOperators;
- (NSDecimalNumber *)multiplicator;
@end

View File

@@ -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

View File

@@ -11,10 +11,12 @@
@interface MPParsedProduct : NSObject @interface MPParsedProduct : NSObject
- (instancetype)init; // designated initializer
- (instancetype)initWithFactor:(id<MPParsedFactor>)factor; // designated initializer.
@property (readonly, nonatomic, strong) NSArray *factors; @property (readonly, nonatomic, strong) NSArray *factors;
- (void)addFactor:(id<MPParsedFactor>)factor;
- (void)addFactor:(MPParsedFactor *)factor; - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
- (NSDecimalNumber *)value;
@end @end

View File

@@ -21,24 +21,37 @@
return self; return self;
} }
- (instancetype)initWithFactor:(id<MPParsedFactor>)factor
{
self = [super init];
if (self) {
_factors = [[NSMutableArray alloc] initWithObjects:factor, nil];
}
return self;
}
- (NSArray *)factors - (NSArray *)factors
{ {
return _factors; return _factors;
} }
- (void)addFactor:(MPParsedFactor *)factor - (void)addFactor:(id<MPParsedFactor>)factor
{ {
[_factors addObject:factor]; [_factors addObject:factor];
} }
- (NSDecimalNumber *)value - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
{ {
if (_factors.count == 0) { if (_factors.count == 0) {
return [NSDecimalNumber zero]; return [NSDecimalNumber zero];
} }
NSDecimalNumber *value = [NSDecimalNumber one]; NSDecimalNumber *value = [NSDecimalNumber one];
for (MPParsedFactor *factor in _factors) { for (id<MPParsedFactor> factor in _factors) {
value = [value decimalNumberByMultiplyingBy:factor.value]; NSDecimalNumber *factorValue = [factor evaluateWithError:error];
if (!factorValue) {
return nil;
}
value = [value decimalNumberByMultiplyingBy:factorValue];
} }
return value; return value;
} }

View File

@@ -0,0 +1,16 @@
//
// MPParsedVariable.h
// MathPad
//
// Created by Kim Wittenburg on 13.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPParsedFactor.h"
@interface MPParsedVariable : NSObject <MPParsedFactor>
- (NSString *)variableName;
@end

View File

@@ -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

View File

@@ -10,6 +10,7 @@
#import "MPExpression.h" #import "MPExpression.h"
#import "MPExpressionEvaluator.h" #import "MPExpressionEvaluator.h"
#import "MPEvaluationContext.h"
@implementation MPSumFunction @implementation MPSumFunction
@@ -99,7 +100,7 @@
} }
#pragma mark Evaluating Functions #pragma mark Evaluating Functions
- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error - (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
{ {
MPExpressionEvaluator *startEvaluator = self.startExpression.evaluator; MPExpressionEvaluator *startEvaluator = self.startExpression.evaluator;
NSDecimalNumber *start = [startEvaluator evaluateVariableDefinition:YES error:error]; NSDecimalNumber *start = [startEvaluator evaluateVariableDefinition:YES error:error];
@@ -111,10 +112,12 @@
return nil; return nil;
} }
[[MPEvaluationContext sharedContext] push];
MPExpressionEvaluator *sumEvaluator = self.sumExpression.evaluator; MPExpressionEvaluator *sumEvaluator = self.sumExpression.evaluator;
NSDecimalNumber *value = [NSDecimalNumber zero]; NSDecimalNumber *value = [NSDecimalNumber zero];
for (NSDecimalNumber *iterator = start; [iterator compare:target] <= 0; iterator = [iterator decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:1]]) { 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]; NSDecimalNumber *summand = [sumEvaluator evaluateWithError:error];
if (summand) { if (summand) {
value = [value decimalNumberByAdding:summand]; value = [value decimalNumberByAdding:summand];
@@ -122,6 +125,9 @@
return nil; return nil;
} }
} }
[[MPEvaluationContext sharedContext] pop];
return value; return value;
} }