Redesign of the Evaluation System
This commit is contained in:
@@ -25,13 +25,13 @@
|
||||
|
||||
- (NSArray *)parseElement:(NSString *)string
|
||||
previousProduct:(MPParsedProduct *)previousProduct
|
||||
nextFactor:(MPParsedFactor *)nextFactor
|
||||
nextFactor:(id<MPParsedFactor>)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<MPParsedFactor>)nextFactor
|
||||
error:(out MPParseError *__autoreleasing *)error;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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<MPParsedFactor>)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<MPParsedFactor>)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;
|
||||
MPParsedNumber *number = [self parseNumber];
|
||||
|
||||
|
||||
NSDecimalNumber *operatorMultiplicator;
|
||||
NSUInteger operatorCount = [self countOperatorsInRange:operatorsRange
|
||||
multiplicator:&operatorMultiplicator];
|
||||
|
||||
if (!hasNumber) {
|
||||
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]) {
|
||||
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);
|
||||
return [match rangeAtIndex:1];
|
||||
matchRange = [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);
|
||||
return [match rangeAtIndex:1];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)numberInRange:(NSRange)range
|
||||
{
|
||||
NSString *numberString = [self.input substringWithRange:range];
|
||||
return [NSDecimalNumber decimalNumberWithString:numberString];
|
||||
matchRange = [match rangeAtIndex:1];
|
||||
}
|
||||
return [[MPParsedNumber alloc] initWithRange:matchRange
|
||||
inString:self.input];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
23
MathPad/MPEvaluationContext.h
Normal file
23
MathPad/MPEvaluationContext.h
Normal 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
|
||||
63
MathPad/MPEvaluationContext.m
Normal file
63
MathPad/MPEvaluationContext.m
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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<MPExpressionElement> element = [self.expression elementAtIndex:elementIndex];
|
||||
|
||||
if ([element isString]) {
|
||||
MPParsedFactor *nextFactor = nil;
|
||||
id<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];
|
||||
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;
|
||||
}
|
||||
|
||||
14
MathPad/MPFunction+MPParsedFactor.h
Normal file
14
MathPad/MPFunction+MPParsedFactor.h
Normal 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
|
||||
30
MathPad/MPFunction+MPParsedFactor.m
Normal file
30
MathPad/MPFunction+MPParsedFactor.m
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
}
|
||||
|
||||
#pragma mark Evaluating Functions
|
||||
- (NSDecimalNumber *)evaluate:(MPParseError *__autoreleasing *)error
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
return [NSDecimalNumber zero];
|
||||
}
|
||||
|
||||
@@ -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 <Foundation/Foundation.h>
|
||||
#import "MPParseError.h"
|
||||
|
||||
@interface MPParsedFactor : NSObject
|
||||
@protocol MPParsedFactor <NSObject>
|
||||
|
||||
+ (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
|
||||
|
||||
16
MathPad/MPParsedNumber.h
Normal file
16
MathPad/MPParsedNumber.h
Normal 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
42
MathPad/MPParsedNumber.m
Normal 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
|
||||
17
MathPad/MPParsedOperator.h
Normal file
17
MathPad/MPParsedOperator.h
Normal 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
|
||||
54
MathPad/MPParsedOperator.m
Normal file
54
MathPad/MPParsedOperator.m
Normal 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
|
||||
@@ -11,10 +11,12 @@
|
||||
|
||||
@interface MPParsedProduct : NSObject
|
||||
|
||||
- (instancetype)init; // designated initializer
|
||||
- (instancetype)initWithFactor:(id<MPParsedFactor>)factor; // designated initializer.
|
||||
|
||||
@property (readonly, nonatomic, strong) NSArray *factors;
|
||||
- (void)addFactor:(id<MPParsedFactor>)factor;
|
||||
|
||||
- (void)addFactor:(MPParsedFactor *)factor;
|
||||
|
||||
- (NSDecimalNumber *)value;
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,24 +21,37 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFactor:(id<MPParsedFactor>)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<MPParsedFactor>)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<MPParsedFactor> factor in _factors) {
|
||||
NSDecimalNumber *factorValue = [factor evaluateWithError:error];
|
||||
if (!factorValue) {
|
||||
return nil;
|
||||
}
|
||||
value = [value decimalNumberByMultiplyingBy:factorValue];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
16
MathPad/MPParsedVariable.h
Normal file
16
MathPad/MPParsedVariable.h
Normal 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
|
||||
47
MathPad/MPParsedVariable.m
Normal file
47
MathPad/MPParsedVariable.m
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user