diff --git a/MathPad/MPElementParser.h b/MathPad/MPElementParser.h index b8999a1..4fec301 100644 --- a/MathPad/MPElementParser.h +++ b/MathPad/MPElementParser.h @@ -14,15 +14,6 @@ @interface MPElementParser : NSObject -+ (BOOL)isUsingDefaultValuesFromUserDefaults; -+ (void)setUsingDefaultValuesFromUserDefaults:(BOOL)flag; - -@property (nonatomic) BOOL allowsImplicitMultiplications; // wether 2 3 is equal to 6 or error -// Default value uses the key "..." in NSUserDefaults or ... if the key does not exist. -@property (nonatomic) NSUInteger maximumOperatorChainLength; // +--++-5 -> Chain length: 6, 2 default (sign of number and operator) (0 is invalid?) -@property (nonatomic) NSUInteger maximumOperatorChainLengthInMultiplication; // Default: 1, 0 means actually 0 -@property (nonatomic) NSUInteger maximumOperatorChainLengthInFunction; // For sin, cos, tan. Default: 1 - - (NSArray *)parseElement:(NSString *)string previousProduct:(MPParsedProduct *)previousProduct nextFactor:(id)nextFactor diff --git a/MathPad/MPElementParser.m b/MathPad/MPElementParser.m index 8faca88..14edfec 100644 --- a/MathPad/MPElementParser.m +++ b/MathPad/MPElementParser.m @@ -8,6 +8,7 @@ #import "MPElementParser.h" #import "NSRegularExpression+MPParsingAdditions.h" +#import "MPMathRules.h" #import "MPParsedFactor.h" #import "MPParsedNumber.h" @@ -21,6 +22,11 @@ @property (nonatomic) NSString *input; @property (nonatomic) NSUInteger parsePosition; +- (BOOL)allowsImplicitMultiplication; +- (BOOL)maximumOperatorChainLength; +- (BOOL)maximumOperatorChainLengthInMultiplication; +- (BOOL)maximumOperatorChainLengthInFunction; + - (void)setError:(MPParseError *)error; - (BOOL)isAtEnd; @@ -30,7 +36,9 @@ - (NSRange)parseWhitespaces; - (NSRange)parseMultiplicationSymbol; - (MPParsedOperator *)parseOperators; +- (id)parseValue; - (MPParsedNumber *)parseNumber; +- (MPParsedVariable *)parseVariable; @end @@ -38,36 +46,25 @@ MPParseError *__autoreleasing *outError; } -static BOOL useUserDefaults; - -#pragma mark Creation Methods - -+ (void)initialize +#pragma mark Helpers +- (BOOL)allowsImplicitMultiplication { - useUserDefaults = YES; + return [MPMathRules sharedRules].allowsImplicitMultiplication; } -- (instancetype)init +- (BOOL)maximumOperatorChainLength { - self = [super init]; - if (self) { - self.allowsImplicitMultiplications = NO; - self.maximumOperatorChainLength = 2; - self.maximumOperatorChainLengthInMultiplication = 1; - } - return self; + return [MPMathRules sharedRules].maximumOperatorChainLength; } -#pragma mark Properties - -+ (BOOL)isUsingDefaultValuesFromUserDefaults +- (BOOL)maximumOperatorChainLengthInFunction { - return useUserDefaults; + return [MPMathRules sharedRules].maximumOperatorChainLengthInFunction; } -+ (void)setUsingDefaultValuesFromUserDefaults:(BOOL)flag +- (BOOL)maximumOperatorChainLengthInMultiplication { - useUserDefaults = flag; + return [MPMathRules sharedRules].maximumOperatorChainLengthInMultiplication; } #pragma mark Parsing Methods @@ -136,10 +133,10 @@ static BOOL useUserDefaults; // NSRange functionRange = ... // BOOL hasFunction = functionRange.location != NSNotFound; - MPParsedNumber *number = [self parseNumber]; + id value = [self parseValue]; - if (!number.exists) { + if (!value.exists) { if ([self isAtEnd] && nextFactor != nil) { if (hasMultiplicationSymbol) { if (operators.numberOfOperators > self.maximumOperatorChainLengthInFunction) { @@ -155,13 +152,11 @@ static BOOL useUserDefaults; [products addObject:currentProduct]; currentProduct = [[MPParsedProduct alloc] init]; [currentProduct addFactor:operators]; - } else if (self.allowsImplicitMultiplications) { - NSLog(@"Here I am"); + } else if (self.allowsImplicitMultiplication) { if (!currentProduct) { currentProduct = [[MPParsedProduct alloc] init]; } } else { - NSLog(@"ERR"); self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Implicit Multiplication not allowed."); return nil; } @@ -184,7 +179,7 @@ static BOOL useUserDefaults; return nil; } [currentProduct addFactor:operators]; - [currentProduct addFactor:number]; + [currentProduct addFactor:value]; } else { self.error = MPParseError(multiplicationSymbolRange, @"Unexpected Symbol. Expected Number."); return nil; @@ -198,13 +193,13 @@ static BOOL useUserDefaults; [products addObject:currentProduct]; } currentProduct = [[MPParsedProduct alloc] initWithFactor:operators]; - [currentProduct addFactor:number]; + [currentProduct addFactor:value]; } else if (!currentProduct) { - currentProduct = [[MPParsedProduct alloc] initWithFactor:number]; - } else if (self.allowsImplicitMultiplications) { - [currentProduct addFactor:number]; + currentProduct = [[MPParsedProduct alloc] initWithFactor:value]; + } else if (self.allowsImplicitMultiplication) { + [currentProduct addFactor:value]; } else { - self.error = MPParseError(NSMakeRange(number.range.location, 0), @"Implicit Multiplication not allowed."); + self.error = MPParseError(NSMakeRange(value.range.location, 0), @"Implicit Multiplication not allowed."); return nil; } } @@ -294,6 +289,18 @@ static NSRegularExpression *operatorsRegex; inString:self.input]; } +- (id)parseValue +{ + MPParsedNumber *parsedNumber = [self parseNumber]; + if (!parsedNumber.exists) { + MPParsedVariable *parsedVariable = [self parseVariable]; + if (parsedVariable.exists) { + return parsedVariable; + } + } + return parsedNumber; +} + - (MPParsedNumber *)parseNumber { NSString *decimalSeparatorRegexString = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]]; @@ -314,4 +321,25 @@ static NSRegularExpression *operatorsRegex; inString:self.input]; } +static NSRegularExpression *variableRegex; +- (MPParsedVariable *)parseVariable +{ + if (!variableRegex) { + variableRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([A-Za-z])\\s*" + options:0 + error:NULL]; + } + NSTextCheckingResult *match = [variableRegex firstMatchInString:self.input + fromIndex:self.parsePosition]; + NSRange matchRange; + if (!match) { + matchRange = NSMakeRange(NSNotFound, 0); + } else { + self.parsePosition = NSMaxRange(match.range); + matchRange = [match rangeAtIndex:1]; + } + return [[MPParsedVariable alloc] initWithRange:matchRange + inString:self.input]; +} + @end diff --git a/MathPad/MPEvaluationContext.m b/MathPad/MPEvaluationContext.m index 280282c..6e6d0e1 100644 --- a/MathPad/MPEvaluationContext.m +++ b/MathPad/MPEvaluationContext.m @@ -25,6 +25,9 @@ static MPEvaluationContext *sharedContext; - (instancetype)init { + if (sharedContext) { + return sharedContext; + } self = [super init]; if (self) { _stack = [[NSMutableArray alloc] init]; diff --git a/MathPad/MPExpressionEvaluator.m b/MathPad/MPExpressionEvaluator.m index 7bc464d..7d07ced 100644 --- a/MathPad/MPExpressionEvaluator.m +++ b/MathPad/MPExpressionEvaluator.m @@ -11,6 +11,7 @@ #import "MPFunction.h" #import "MPParsedFactor.h" #import "MPFunction+MPParsedFactor.h" +#import "MPMathRules.h" @interface MPExpressionEvaluator () @property (readwrite, nonatomic, strong) NSString *definedVariable; @@ -87,8 +88,12 @@ } else { if (!currentProduct) { currentProduct = [[MPParsedProduct alloc] init]; + } else if ([MPMathRules sharedRules].allowsImplicitMultiplication) { + [currentProduct addFactor:(MPFunction *)element]; + } else { + *error = MPParseError(NSMakeRange(((MPFunction *)element).range.location, 0), @"Implicit Multiplication not allowed"); + return nil; } - [currentProduct addFactor:(MPFunction *)element]; } } diff --git a/MathPad/MPMathRules.h b/MathPad/MPMathRules.h new file mode 100644 index 0000000..14e9302 --- /dev/null +++ b/MathPad/MPMathRules.h @@ -0,0 +1,28 @@ +// +// MPMathRules.h +// MathPad +// +// Created by Kim Wittenburg on 14.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import + +FOUNDATION_EXPORT NSString *MPMathRulesAllowsImplicitMultiplicationKey; +FOUNDATION_EXPORT NSString *MPMathRulesMaximumOperatorChainLengthKey; +FOUNDATION_EXPORT NSString *MPMathRulesMaximumOperatorChainLengthInMultiplicationKey; +FOUNDATION_EXPORT NSString *MPMathRulesMaximumOperatorChainLengthInFunctionKey; + +@interface MPMathRules : NSObject + ++ (MPMathRules *)sharedRules; + +@property (nonatomic, getter = isUsingUserDefaultValues) BOOL usingUserDefaultValues; + +@property (nonatomic) BOOL allowsImplicitMultiplication; // wether 2 3 is equal to 6 or error +// Default value uses the key "..." in NSUserDefaults or ... if the key does not exist. +@property (nonatomic) NSUInteger maximumOperatorChainLength; // +--++-5 -> Chain length: 6, 2 default (sign of number and operator) (0 is invalid?) +@property (nonatomic) NSUInteger maximumOperatorChainLengthInMultiplication; // Default: 1, 0 means actually 0 +@property (nonatomic) NSUInteger maximumOperatorChainLengthInFunction; // For sin, cos, tan. Default: 1 + +@end diff --git a/MathPad/MPMathRules.m b/MathPad/MPMathRules.m new file mode 100644 index 0000000..324506b --- /dev/null +++ b/MathPad/MPMathRules.m @@ -0,0 +1,95 @@ +// +// MPMathRules.m +// MathPad +// +// Created by Kim Wittenburg on 14.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPMathRules.h" + +NSString *MPMathRulesAllowsImplicitMultiplicationKey = @"MPMathRulesAllowsImplicitMultiplicationKey"; +NSString *MPMathRulesMaximumOperatorChainLengthKey = @"MPMathRulesMaximumOperatorChainLengthKey"; +NSString *MPMathRulesMaximumOperatorChainLengthInMultiplicationKey = @"MPMathRulesMaximumOperatorChainLengthInMultiplicationKey"; +NSString *MPMathRulesMaximumOperatorChainLengthInFunctionKey = @"MPMathRulesMaximumOperatorChainLengthInFunctionKey"; + +@implementation MPMathRules + +static MPMathRules *sharedRules; + ++ (MPMathRules *)sharedRules +{ + if (!sharedRules) { + sharedRules = [[MPMathRules alloc] init]; + } + return sharedRules; +} + +- (instancetype)init +{ + if (sharedRules) { + return sharedRules; + } + self = [super init]; + if (self) { + _usingUserDefaultValues = YES; + NSNumber *userDefaultsAllowImplicitMultiplication = [[NSUserDefaults standardUserDefaults] objectForKey:MPMathRulesAllowsImplicitMultiplicationKey]; + NSNumber *userDefaultsMaximumOperatorChainLength = [[NSUserDefaults standardUserDefaults] objectForKey:MPMathRulesMaximumOperatorChainLengthKey]; + NSNumber *userDefaultsMaximumOperatorChainLengthInMultiplication = [[NSUserDefaults standardUserDefaults] objectForKey:MPMathRulesMaximumOperatorChainLengthInMultiplicationKey]; + NSNumber *userDefaultsMaximumOperatorChainLengthInFunction = [[NSUserDefaults standardUserDefaults] objectForKey:MPMathRulesMaximumOperatorChainLengthInFunctionKey]; + + _allowsImplicitMultiplication = userDefaultsAllowImplicitMultiplication != nil ? userDefaultsAllowImplicitMultiplication.boolValue : NO; + _maximumOperatorChainLength = userDefaultsMaximumOperatorChainLength != nil ? userDefaultsMaximumOperatorChainLength.unsignedIntegerValue : 2; + _maximumOperatorChainLengthInMultiplication = userDefaultsMaximumOperatorChainLengthInMultiplication != nil ? userDefaultsMaximumOperatorChainLengthInMultiplication.unsignedIntegerValue : 1; + _maximumOperatorChainLengthInFunction = userDefaultsMaximumOperatorChainLengthInFunction != nil ? userDefaultsMaximumOperatorChainLengthInFunction.unsignedIntegerValue : 1; + } + return self; +} + +- (void)setUsingUserDefaultValues:(BOOL)usingUserDefaultValues +{ + _usingUserDefaultValues = usingUserDefaultValues; + // Save the current values + self.allowsImplicitMultiplication = self.allowsImplicitMultiplication; + self.maximumOperatorChainLength = self.maximumOperatorChainLength; + self.maximumOperatorChainLengthInMultiplication = self.maximumOperatorChainLengthInMultiplication; + self.maximumOperatorChainLengthInFunction = self.maximumOperatorChainLengthInFunction; +} + +- (void)setAllowsImplicitMultiplication:(BOOL)allowsImplicitMultiplication +{ + _allowsImplicitMultiplication = allowsImplicitMultiplication; + if (self.isUsingUserDefaultValues) { + [[NSUserDefaults standardUserDefaults] setBool:allowsImplicitMultiplication + forKey:MPMathRulesAllowsImplicitMultiplicationKey]; + } +} + +- (void)setMaximumOperatorChainLength:(NSUInteger)maximumOperatorChainLength +{ + _maximumOperatorChainLength = maximumOperatorChainLength; + if (self.isUsingUserDefaultValues) { + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedInteger:maximumOperatorChainLength] + forKey:MPMathRulesMaximumOperatorChainLengthKey]; + } +} + +- (void)setMaximumOperatorChainLengthInMultiplication:(NSUInteger)maximumOperatorChainLengthInMultiplication +{ + _maximumOperatorChainLengthInMultiplication = maximumOperatorChainLengthInMultiplication; + if (self.isUsingUserDefaultValues) { + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedInteger:maximumOperatorChainLengthInMultiplication] + forKey:MPMathRulesMaximumOperatorChainLengthInMultiplicationKey]; + } +} + +- (void)setMaximumOperatorChainLengthInFunction:(NSUInteger)maximumOperatorChainLengthInFunction +{ + _maximumOperatorChainLengthInFunction = maximumOperatorChainLengthInFunction; + if (self.isUsingUserDefaultValues) { + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedInteger:maximumOperatorChainLengthInFunction] + forKey:MPMathRulesMaximumOperatorChainLengthInFunctionKey]; + } +} + +@end