diff --git a/MathPad.xcodeproj/project.pbxproj b/MathPad.xcodeproj/project.pbxproj index 7a4e4ee..af7869b 100644 --- a/MathPad.xcodeproj/project.pbxproj +++ b/MathPad.xcodeproj/project.pbxproj @@ -7,9 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 3B3A4AAE19F71855001E9D54 /* MPRootFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B3A4AAC19F71855001E9D54 /* MPRootFunction.h */; }; + 3B3A4AAF19F71855001E9D54 /* MPRootFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A4AAD19F71855001E9D54 /* MPRootFunction.m */; }; + 3B3A4AB219F71A11001E9D54 /* MPRootFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B3A4AB019F71A11001E9D54 /* MPRootFunctionLayout.h */; }; + 3B3A4AB319F71A11001E9D54 /* MPRootFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A4AB119F71A11001E9D54 /* MPRootFunctionLayout.m */; }; 3B52CEC119BB9FA900CEDCFC /* MathKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B85830D19BB5E5500D76A8D /* MathKit.framework */; }; - 3B52CED019BE509C00CEDCFC /* MPParseError.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B52CECE19BE509C00CEDCFC /* MPParseError.h */; }; - 3B52CED119BE509C00CEDCFC /* MPParseError.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B52CECF19BE509C00CEDCFC /* MPParseError.m */; }; 3B52CEDC19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B52CEDA19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.h */; }; 3B52CEDD19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B52CEDB19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.m */; }; 3B591BBB19C58D000061D86B /* MPMathRules.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B591BB919C58D000061D86B /* MPMathRules.h */; }; @@ -163,13 +165,15 @@ 3B0F69A719028BC600817707 /* MPException.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPException.h; sourceTree = ""; }; 3B0F69A819028C6000817707 /* MPException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPException.m; sourceTree = ""; }; 3B0F69AB1902A82C00817707 /* MPExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPExpressionTests.m; path = ../MathPadTests/MPExpressionTests.m; sourceTree = ""; }; + 3B3A4AAC19F71855001E9D54 /* MPRootFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootFunction.h; sourceTree = ""; }; + 3B3A4AAD19F71855001E9D54 /* MPRootFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootFunction.m; sourceTree = ""; }; + 3B3A4AB019F71A11001E9D54 /* MPRootFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootFunctionLayout.h; sourceTree = ""; }; + 3B3A4AB119F71A11001E9D54 /* MPRootFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootFunctionLayout.m; sourceTree = ""; }; 3B528D0D199417740054DB5F /* MPLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLayout.h; sourceTree = ""; }; 3B528D0E199417E10054DB5F /* MPExpressionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionLayout.h; sourceTree = ""; }; 3B528D0F199417E10054DB5F /* MPExpressionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionLayout.m; sourceTree = ""; }; 3B528D11199417E90054DB5F /* MPFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunctionLayout.h; sourceTree = ""; }; 3B528D12199417E90054DB5F /* MPFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunctionLayout.m; sourceTree = ""; }; - 3B52CECE19BE509C00CEDCFC /* MPParseError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPParseError.h; sourceTree = ""; }; - 3B52CECF19BE509C00CEDCFC /* MPParseError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPParseError.m; sourceTree = ""; }; 3B52CEDA19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSRegularExpression+MPParsingAdditions.h"; sourceTree = ""; }; 3B52CEDB19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSRegularExpression+MPParsingAdditions.m"; sourceTree = ""; }; 3B591BB919C58D000061D86B /* MPMathRules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMathRules.h; sourceTree = ""; }; @@ -453,6 +457,8 @@ 3B5FF73A19DB2FF500C8348A /* MPPowerFunction.m */, 3B69B67A19E4915E0028E608 /* MPFractionFunction.h */, 3B69B67B19E4915E0028E608 /* MPFractionFunction.m */, + 3B3A4AAC19F71855001E9D54 /* MPRootFunction.h */, + 3B3A4AAD19F71855001E9D54 /* MPRootFunction.m */, ); name = Functions; sourceTree = ""; @@ -488,6 +494,8 @@ 3B69B66B19DB41B90028E608 /* MPPowerFunctionLayout.m */, 3B69B67E19E493630028E608 /* MPFractionFunctionLayout.h */, 3B69B67F19E493630028E608 /* MPFractionFunctionLayout.m */, + 3B3A4AB019F71A11001E9D54 /* MPRootFunctionLayout.h */, + 3B3A4AB119F71A11001E9D54 /* MPRootFunctionLayout.m */, ); name = "Function Layouts"; sourceTree = ""; @@ -556,8 +564,6 @@ 3B78C85319C2DA5300516335 /* MPEvaluationContext.m */, 3B591BB919C58D000061D86B /* MPMathRules.h */, 3B591BBA19C58D000061D86B /* MPMathRules.m */, - 3B52CECE19BE509C00CEDCFC /* MPParseError.h */, - 3B52CECF19BE509C00CEDCFC /* MPParseError.m */, ); name = Evaluation; sourceTree = ""; @@ -664,6 +670,7 @@ 3B69B67C19E4915E0028E608 /* MPFractionFunction.h in Headers */, 3B78C85419C2DA5300516335 /* MPEvaluationContext.h in Headers */, 3B85834419BB654D00D76A8D /* NSString+MPExpressionElement.h in Headers */, + 3B3A4AAE19F71855001E9D54 /* MPRootFunction.h in Headers */, 3B69B6B519E88E750028E608 /* MPUnexpectedSymbolValue.h in Headers */, 3B7172F219C9FC6700FEAA5B /* MPParenthesisFunctionLayout.h in Headers */, 3B52CEDC19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.h in Headers */, @@ -671,6 +678,7 @@ 3B69B6B119E8175F0028E608 /* MPFactor.h in Headers */, 3B69B66C19DB41B90028E608 /* MPPowerFunctionLayout.h in Headers */, 3B69B69719E6F0780028E608 /* MPValueGroup.h in Headers */, + 3B3A4AB219F71A11001E9D54 /* MPRootFunctionLayout.h in Headers */, 3B85834319BB653700D76A8D /* MPSumFunction.h in Headers */, 3B85834119BB651E00D76A8D /* MPRangePath.h in Headers */, 3B69B6C119E953590028E608 /* MPFactorial.h in Headers */, @@ -678,7 +686,6 @@ 3B69B69D19E6F2110028E608 /* MPNumber.h in Headers */, 3B85834519BB655200D76A8D /* NSIndexPath+MPAdditions.h in Headers */, 3B5FF73B19DB2FF500C8348A /* MPPowerFunction.h in Headers */, - 3B52CED019BE509C00CEDCFC /* MPParseError.h in Headers */, 3B7172EE19C9FA8E00FEAA5B /* MPParenthesisFunction.h in Headers */, 3B85834619BB655C00D76A8D /* MPExpressionView.h in Headers */, 3B85834719BB655F00D76A8D /* MPExpressionStorage.h in Headers */, @@ -893,6 +900,7 @@ 3B69B6C219E953590028E608 /* MPFactorial.m in Sources */, 3B69B69E19E6F2110028E608 /* MPNumber.m in Sources */, 3B7172F319C9FC6700FEAA5B /* MPParenthesisFunctionLayout.m in Sources */, + 3B3A4AB319F71A11001E9D54 /* MPRootFunctionLayout.m in Sources */, 3BBEA93A19BB79A700133766 /* MPSumFunction.m in Sources */, 3BBEA93E19BB79A700133766 /* NSIndexPath+MPAdditions.m in Sources */, 3B52CEDD19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.m in Sources */, @@ -901,10 +909,10 @@ 3B69B68E19E6EB0D0028E608 /* MPProduct.m in Sources */, 3B69B6B619E88E750028E608 /* MPUnexpectedSymbolValue.m in Sources */, 3BF59AFF19D80ECC00E54292 /* MPFunctionsViewController.m in Sources */, - 3B52CED119BE509C00CEDCFC /* MPParseError.m in Sources */, 3BB18AA619CDB3A900986DA0 /* MPTokenStream.m in Sources */, 3B69B66D19DB41B90028E608 /* MPPowerFunctionLayout.m in Sources */, 3BBEA93619BB79A700133766 /* MPFunction.m in Sources */, + 3B3A4AAF19F71855001E9D54 /* MPRootFunction.m in Sources */, 3BBEA93519BB79A700133766 /* MPExpression.m in Sources */, 3BBEA93B19BB79A700133766 /* MPRangePath.m in Sources */, 3B69B68A19E6E9280028E608 /* MPSummand.m in Sources */, diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128.png index a90c346..63aa798 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png index 50499e9..7463c50 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16.png index bd89585..8e6852c 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png index 589ddb7..f851f85 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256.png index 50499e9..7463c50 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png index 618b3fd..b64e771 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32.png index 589ddb7..f851f85 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png index 7d8e182..2aa5cef 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512.png index 618b3fd..b64e771 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512.png differ diff --git a/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png index 5d9487c..dae1c96 100644 Binary files a/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png and b/MathPad/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ diff --git a/MathPad/MPDocument.m b/MathPad/MPDocument.m index dea08b0..cc3fcd4 100644 --- a/MathPad/MPDocument.m +++ b/MathPad/MPDocument.m @@ -60,9 +60,13 @@ #pragma mark Actions - (IBAction)evaluateExpression:(id)sender { - MPParseError *error; + NSError *error; NSDecimalNumber *result = [self.expressionView.expressionStorage evaluateWithError:&error]; - self.expressionView.error = error; + if (error) { + self.expressionView.errorMessageTextField.stringValue = error.localizedDescription; + } else { + self.expressionView.errorMessageTextField.stringValue = @""; + } self.resultLabel.stringValue = result != nil ? [result descriptionWithLocale:[NSLocale currentLocale]] : @""; } diff --git a/MathPad/MPExpression.h b/MathPad/MPExpression.h index 9e934fe..d36ef1a 100644 --- a/MathPad/MPExpression.h +++ b/MathPad/MPExpression.h @@ -8,16 +8,34 @@ @import Foundation; #import "NSString+MPExpressionElement.h" -#import "MPExpressionTree.h" #import "MPToken.h" +FOUNDATION_EXPORT NSString *const MPMathKitErrorDomain; +FOUNDATION_EXPORT NSString *const MPExpressionPathErrorKey; + +NS_INLINE NSError * MPParseError(NSInteger errorCode, + NSString *errorDescription, + NSError *underlyingError) { + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; + if (errorDescription) { + userInfo[NSLocalizedDescriptionKey] = errorDescription; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + NSError *error = [NSError errorWithDomain:MPMathKitErrorDomain + code:errorCode + userInfo:userInfo.copy]; + return error; +} + typedef NS_ENUM(NSUInteger, MPReferenceFrame) { MPElementReferenceFrame, MPSymbolReferenceFrame, MPTokenReferenceFrame }; -@class MPExpression, MPFunction, MPRangePath, MPExpressionEvaluator, MPParseError; +@class MPExpression, MPFunction, MPRangePath, MPExpressionTree, MPExpressionEvaluator; @protocol MPExpressionElement; /*! @@ -78,8 +96,6 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) { */ - (instancetype)init; -- (instancetype)initWithExpressionTree:(MPExpressionTree *)expressionTree; - /*! @method initWithElement: @@ -359,7 +375,7 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) { be evaluated. In that case the @c error parameter is set to an appropriate value. */ -- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error; +- (NSDecimalNumber *)evaluateWithError:(NSError *__autoreleasing *)error; - (MPExpressionTree *)parse; diff --git a/MathPad/MPExpression.m b/MathPad/MPExpression.m index 7d1ae64..5848f9f 100644 --- a/MathPad/MPExpression.m +++ b/MathPad/MPExpression.m @@ -16,6 +16,11 @@ #import "MPExpressionTokenizer.h" #import "MPToken.h" +#import "MPExpressionTree.h" + + +NSString *const MPMathKitErrorDomain = @"MPMathKitErrorDomain"; +NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey"; @interface MPExpression () { @@ -54,11 +59,6 @@ return [self initWithElements:@[]]; } -- (instancetype)initWithExpressionTree:(MPExpressionTree *)expressionTree -{ - return [self initWithElements:expressionTree.expressionElements]; -} - - (instancetype)initWithElement:(id)element { return [self initWithElements:@[element]]; @@ -521,7 +521,7 @@ #pragma mark Evaluating Expressions -- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error +- (NSDecimalNumber *)evaluateWithError:(NSError *__autoreleasing *)error { MPExpressionTree *tree = [self parse]; return [tree validate:error] ? [tree evaluate] : nil; diff --git a/MathPad/MPExpressionElement.h b/MathPad/MPExpressionElement.h index 41f8332..0c5c1af 100644 --- a/MathPad/MPExpressionElement.h +++ b/MathPad/MPExpressionElement.h @@ -8,8 +8,6 @@ @import Foundation; -#import "MPParseError.h" - @protocol MPExpressionElement - (BOOL)isString; diff --git a/MathPad/MPExpressionStorage.m b/MathPad/MPExpressionStorage.m index 3eed689..4ac6403 100644 --- a/MathPad/MPExpressionStorage.m +++ b/MathPad/MPExpressionStorage.m @@ -50,7 +50,6 @@ [current clearCacheInRange:rangePath.rangeAtLastIndex replacementLength:replacementLength]; [self.expressionView invalidateIntrinsicContentSize]; - self.expressionView.error = nil; self.expressionView.needsDisplay = YES; } diff --git a/MathPad/MPExpressionTree.h b/MathPad/MPExpressionTree.h index 4690b01..9f011fa 100644 --- a/MathPad/MPExpressionTree.h +++ b/MathPad/MPExpressionTree.h @@ -13,16 +13,9 @@ @interface MPExpressionTree : NSObject @property (nonatomic, copy) NSString *definedVariable; - -- (NSArray *)summands; -- (void)appendSummand:(MPSummand *)summand; -- (void)insertSummand:(MPSummand *)summand - atIndex:(NSUInteger)index; -- (void)removeSummand:(MPSummand *)summand; -- (void)removeSummandAtIndex:(NSUInteger)index; -- (MPSummand *)summandAtIndex:(NSUInteger)index; +@property (readonly, nonatomic, strong) NSArray *summands; - (BOOL)validateExpectingVariableDefinition:(BOOL)flag - error:(MPParseError *__autoreleasing *)error; + error:(NSError *__autoreleasing *)error; @end diff --git a/MathPad/MPExpressionTree.m b/MathPad/MPExpressionTree.m index 61b01fd..fc458ac 100644 --- a/MathPad/MPExpressionTree.m +++ b/MathPad/MPExpressionTree.m @@ -9,9 +9,7 @@ #import "MPExpressionTree.h" @implementation MPExpressionTree { - NSRange _variableDefinitionRange; NSMutableArray *_summands; - NSRange _range; } - (id)init @@ -27,20 +25,14 @@ { self = [self init]; if (self) { - MPTokenStreamRecordCurrentLocation(tokenStream); - [tokenStream beginIgnoringWhitespaceTokens]; - _variableDefinitionRange = NSMakeRange(NSNotFound, 0); self.definedVariable = nil; if (tokenStream.currentToken.tokenType == MPVariableToken) { if (tokenStream.peekNextToken.tokenType == MPEqualsToken) { self.definedVariable = tokenStream.currentToken.stringValue; - NSRange variableRange = tokenStream.currentToken.range; [tokenStream currentTokenConsumed]; - NSRange equalsRange = tokenStream.currentToken.range; [tokenStream currentTokenConsumed]; - _variableDefinitionRange = NSUnionRange(variableRange, equalsRange); } } while ([tokenStream hasMoreTokens]) { @@ -48,43 +40,48 @@ } [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; - _range = MPTokenStreamRecordedRange(tokenStream); } return self; } -- (NSRange)range +- (NSArray *)summands { - return _range; + return _summands; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return [self validateExpectingVariableDefinition:NO error:error]; } - (BOOL)validateExpectingVariableDefinition:(BOOL)flag - error:(MPParseError *__autoreleasing *)error + error:(NSError *__autoreleasing *)error { if (flag) { if (!self.definedVariable) { if (error) { - *error = MPParseError(NSMakeRange(self.range.location, 0), @"Expected Variable Definition."); + *error = MPParseError(1, + NSLocalizedString(@"Expected Variable Definition.", @"Error message. This is displayed when an expected variable definition was not found."), + nil); } return NO; } } else { if (self.definedVariable) { if (error) { - *error = MPParseError(_variableDefinitionRange, @"Unexpected Variable Definition"); + *error = MPParseError(2, + NSLocalizedString(@"Unexpected Variable Definition.", @"Error message. This is displayed when no variable definition was expected but one was found."), + nil); } return NO; } } if (_summands.count == 0) { if (error) { - *error = MPParseError(self.range, @"Empty Expression."); + *error = MPParseError(3, + NSLocalizedString(@"Empty Expression.", @"Error message. This is displayed when the user tried to evaluate an empty expression."), + nil); } return NO; } @@ -111,48 +108,4 @@ } -- (NSArray *)expressionElements -{ - NSMutableArray *elements = [[NSMutableArray alloc] init]; - if (self.definedVariable) { - [elements addObject:[NSString stringWithFormat:@"%@=", self.definedVariable]]; - } - for (MPSummand *summand in _summands) { - [elements addObjectsFromArray:summand.expressionElements]; - } - return elements; -} - -- (NSArray *)summands -{ - return _summands; -} - -- (void)appendSummand:(MPSummand *)summand -{ - [_summands addObject:summand]; -} - -- (void)insertSummand:(MPSummand *)summand - atIndex:(NSUInteger)index -{ - [_summands insertObject:summand - atIndex:index]; -} - -- (void)removeSummand:(MPSummand *)summand -{ - [_summands removeObject:summand]; -} - -- (void)removeSummandAtIndex:(NSUInteger)index -{ - [_summands removeObjectAtIndex:index]; -} - -- (MPSummand *)summandAtIndex:(NSUInteger)index -{ - return [_summands objectAtIndex:index]; -} - @end diff --git a/MathPad/MPExpressionTreeElement.h b/MathPad/MPExpressionTreeElement.h index cf9e97e..8f8b73a 100644 --- a/MathPad/MPExpressionTreeElement.h +++ b/MathPad/MPExpressionTreeElement.h @@ -8,11 +8,7 @@ #import #import "MPTokenStream.h" -#import "MPParseError.h" -#import "MPTokenStream.h" - -#define MPTokenStreamRecordCurrentLocation(tokenStream) NSUInteger __tokenStreamStart = tokenStream.currentToken.range.location -#define MPTokenStreamRecordedRange(tokenStream) NSMakeRange(__tokenStreamStart, tokenStream.currentToken.range.location - __tokenStreamStart) +#import "MPExpression.h" @protocol MPExpressionTreeElement @required @@ -20,11 +16,7 @@ - (instancetype)init; - (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream; -- (NSRange)range; - -- (BOOL)validate:(MPParseError *__autoreleasing *)error; +- (BOOL)validate:(NSError *__autoreleasing *)error; - (NSDecimalNumber *)evaluate; -- (NSArray *)expressionElements; // Converts - @end diff --git a/MathPad/MPExpressionView.h b/MathPad/MPExpressionView.h index 73fec97..802ea1a 100644 --- a/MathPad/MPExpressionView.h +++ b/MathPad/MPExpressionView.h @@ -10,8 +10,6 @@ #import -#import "MPParseError.h" - @class MPExpressionView, MPExpressionStorage, MPExpressionLayout, MPRangePath; @interface MPExpressionView : NSView @@ -25,7 +23,8 @@ @property (readonly, nonatomic, strong) MPExpressionStorage *expressionStorage; @property (nonatomic, strong) MPRangePath *selection; -@property (nonatomic, strong) MPParseError *error; + +@property (nonatomic, strong) NSTextField *errorMessageTextField; @property (nonatomic, weak) id target; @property (nonatomic) SEL action; diff --git a/MathPad/MPExpressionView.m b/MathPad/MPExpressionView.m index 96d5f5d..3111f42 100644 --- a/MathPad/MPExpressionView.m +++ b/MathPad/MPExpressionView.m @@ -34,8 +34,6 @@ @property (nonatomic, strong) NSPopover *functionsPopover; @property (nonatomic, strong) MPFunctionsViewController *functionsViewController; -@property (nonatomic, strong) NSTextField *errorLabel; - @property (nonatomic, strong) NSTimer *caretTimer; @property (nonatomic) NSTimeInterval caretBlinkRate; @property (nonatomic) BOOL caretVisible; @@ -339,7 +337,7 @@ _expressionStorage = expressionStorage; [self initializeButtons]; - [self initializeErrorLabel]; + [self initializeErrorMessageTextField]; self.selection = [[MPRangePath alloc] initWithRange:NSMakeRange(0, 0)]; self.caretBlinkRate = 1.0; @@ -377,9 +375,9 @@ constant:0]]; } -- (void)initializeErrorLabel +- (void)initializeErrorMessageTextField { - NSTextField *errorLabel = self.errorLabel; + NSTextField *errorLabel = self.errorMessageTextField; [self addSubview:errorLabel]; NSDictionary *variableBindings = NSDictionaryOfVariableBindings(errorLabel); [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[errorLabel]" @@ -408,13 +406,6 @@ self.needsDisplay = YES; } -- (void)setError:(MPParseError *)error -{ - _error = error; - self.errorLabel.stringValue = error.localizedErrorMessage != nil ? error.localizedErrorMessage : @""; - self.needsDisplay = YES; -} - - (NSButton *)radiansDegreesButton { if (!_radiansDegreesButton) { @@ -457,9 +448,9 @@ return _functionsButton; } -- (NSTextField *)errorLabel +- (NSTextField *)errorMessageTextField { - if (!_errorLabel) { + if (!_errorMessageTextField) { NSTextField *label = [[NSTextField alloc] initWithFrame:NSZeroRect]; label.textColor = [NSColor redColor]; label.translatesAutoresizingMaskIntoConstraints = NO; @@ -467,9 +458,9 @@ label.drawsBackground = NO; label.editable = NO; label.selectable = NO; - _errorLabel = label; + _errorMessageTextField = label; } - return _errorLabel; + return _errorMessageTextField; } #pragma mark Actions @@ -922,25 +913,7 @@ [transform translateXBy:expressionOrigin.x yBy:expressionOrigin.y]; [transform concat]; - - // Draw the error -// if (self.error) { -// [[NSColor redColor] set]; -// NSRect rect = [self.expressionStorage.rootLayout boundingRectForRangePath:self.error.rangePath]; -// if (self.error.rangePath.length == 0) { -// NSBezierPath *bezierPath = [NSBezierPath bezierPath]; -// [bezierPath moveToPoint:rect.origin]; -// [bezierPath lineToPoint:NSMakePoint(rect.origin.x - 5, rect.origin.y - 5)]; -// [bezierPath moveToPoint:rect.origin]; -// [bezierPath lineToPoint:NSMakePoint(rect.origin.x + 5, rect.origin.y - 5)]; -// bezierPath.lineWidth = 2.0; -// [bezierPath stroke]; -// } else { -// NSRect underlineRect = NSMakeRect(rect.origin.x, rect.origin.y + 2, rect.size.width, 2); -// NSRectFill(underlineRect); -// } -// } - + // Draw the selection if (self.caretVisible || self.selection.length > 0) { if (self.selection.length == 0) { diff --git a/MathPad/MPFactor.h b/MathPad/MPFactor.h index 9d3e73a..a471bba 100644 --- a/MathPad/MPFactor.h +++ b/MathPad/MPFactor.h @@ -13,10 +13,8 @@ @interface MPFactor : NSObject -@property (nonatomic) BOOL hasMultiplicationSymbol; -@property (nonatomic, strong) MPOperatorChain *operatorChain; -@property (nonatomic, strong) id value; - -- (NSRange)multiplicationSymbolRange; +@property (readonly, nonatomic) BOOL hasMultiplicationSymbol; +@property (readonly, nonatomic, strong) MPOperatorChain *operatorChain; +@property (readonly, nonatomic, strong) id value; @end diff --git a/MathPad/MPFactor.m b/MathPad/MPFactor.m index 94d9503..a9c9cec 100644 --- a/MathPad/MPFactor.m +++ b/MathPad/MPFactor.m @@ -10,7 +10,7 @@ #import "MPMathRules.h" @implementation MPFactor { - NSRange _multiplicationSymbolRange; + BOOL _multiplicationSymbolPresent; } - (instancetype)init @@ -28,11 +28,9 @@ if (self) { [tokenStream beginIgnoringWhitespaceTokens]; MPToken *token = tokenStream.currentToken; - if (token.tokenType == MPMultiplicationSymbolToken) { - _multiplicationSymbolRange = token.range; + _multiplicationSymbolPresent = token.tokenType == MPMultiplicationSymbolToken; + if (_multiplicationSymbolPresent) { [tokenStream currentTokenConsumed]; - } else { - _multiplicationSymbolRange = NSMakeRange(NSNotFound, 0); } if (tokenStream.currentToken.tokenType == MPOperatorListToken) { _operatorChain = [[MPOperatorChain alloc] initWithTokenStream:tokenStream]; @@ -44,29 +42,18 @@ return self; } -- (NSRange)range -{ - if (_multiplicationSymbolRange.location == NSNotFound) { - return self.value.range; - } - return NSUnionRange(_multiplicationSymbolRange, self.value.range); -} - -- (NSRange)multiplicationSymbolRange -{ - return _multiplicationSymbolRange; -} - - (BOOL)hasMultiplicationSymbol { - return _multiplicationSymbolRange.location != NSNotFound; + return _multiplicationSymbolPresent; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (self.operatorChain.numberOfOperators > [[MPMathRules sharedRules] maximumOperatorChainLengthInMultiplication]) { if (error) { - *error = MPParseError(self.operatorChain.range, @"Too many operators in Multiplication"); + *error = MPParseError(7, + NSLocalizedString(@"Too many operators in Multiplication.", @"Error message. This is displayed when there are too many operators between a multiplication symbol and a value."), + nil); } return NO; } @@ -82,14 +69,4 @@ return value; } -- (NSArray *)expressionElements -{ - NSMutableArray *elements = [[NSMutableArray alloc] init]; - if (self.hasMultiplicationSymbol) { - [elements addObject:@"*"]; - } - [elements addObjectsFromArray:self.value.expressionElements]; - return elements; -} - @end diff --git a/MathPad/MPFactorial.h b/MathPad/MPFactorial.h index 457f49e..795ae6c 100644 --- a/MathPad/MPFactorial.h +++ b/MathPad/MPFactorial.h @@ -11,6 +11,6 @@ @interface MPFactorial : NSObject -@property (nonatomic, strong) id value; +@property (readonly, nonatomic, strong) id value; @end diff --git a/MathPad/MPFactorial.m b/MathPad/MPFactorial.m index 5fff083..c06f1ad 100644 --- a/MathPad/MPFactorial.m +++ b/MathPad/MPFactorial.m @@ -34,12 +34,7 @@ return self; } -- (NSRange)range -{ - return NSMakeRange(0, 0); -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return [self.value validate:error]; } @@ -50,9 +45,4 @@ return [[NSDecimalNumber alloc] initWithDouble:tgamma(value+1)]; } -- (NSArray *)expressionElements -{ - return @[@"!"]; -} - @end diff --git a/MathPad/MPFractionFunction.m b/MathPad/MPFractionFunction.m index f035cb7..2028e86 100644 --- a/MathPad/MPFractionFunction.m +++ b/MathPad/MPFractionFunction.m @@ -8,6 +8,8 @@ #import "MPFractionFunction.h" +#import "MPExpressionTree.h" + @implementation MPFractionFunction MPFunctionAccessorImplementation(NominatorExpression, _nominatorExpression) @@ -18,7 +20,7 @@ MPFunctionAccessorImplementation(DenominatorExpression, _denominatorExpression) return @[@"nominatorExpression", @"denominatorExpression"]; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return [[self.nominatorExpression parse] validate:error] && [[self.denominatorExpression parse] validate:error]; } diff --git a/MathPad/MPFractionFunctionLayout.m b/MathPad/MPFractionFunctionLayout.m index 270e9d9..169fa3f 100644 --- a/MathPad/MPFractionFunctionLayout.m +++ b/MathPad/MPFractionFunctionLayout.m @@ -40,15 +40,16 @@ - (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index { + NSRect bounds = self.bounds; if (index == 0) { NSRect nominatorBounds = [self childLayoutAtIndex:0].bounds; CGFloat y = MPFractionMiddle + kFractionFunctionLineWidth / 2 - nominatorBounds.origin.y; - return NSMakePoint(kFractionFunctionHorizontalInset, y); + return NSMakePoint((bounds.size.width - nominatorBounds.size.width) / 2, y); } else { NSRect denominatorBounds = [self childLayoutAtIndex:1].bounds; CGFloat y = MPFractionMiddle - kFractionFunctionLineWidth / 2; y -= denominatorBounds.size.height + denominatorBounds.origin.y; - return NSMakePoint(kFractionFunctionHorizontalInset, y); + return NSMakePoint((bounds.size.width - denominatorBounds.size.width) / 2, y); } } diff --git a/MathPad/MPFunction+MPValue.m b/MathPad/MPFunction+MPValue.m index 0192bac..09ba9d3 100644 --- a/MathPad/MPFunction+MPValue.m +++ b/MathPad/MPFunction+MPValue.m @@ -14,15 +14,13 @@ { [tokenStream beginIgnoringWhitespaceTokens]; if (tokenStream.currentToken.tokenType != MPGenericFunctionToken) { - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Function" userInfo:nil]; + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Expected Function" + userInfo:nil]; } + [tokenStream currentTokenConsumed]; [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; return [self init]; } -- (NSArray *)expressionElements -{ - return @[self]; -} - @end diff --git a/MathPad/MPFunction.h b/MathPad/MPFunction.h index 23a0685..dd29a18 100644 --- a/MathPad/MPFunction.h +++ b/MathPad/MPFunction.h @@ -8,7 +8,6 @@ @import Foundation; #import "MPExpressionElement.h" -#import "MPParseError.h" #define MPFunctionAccessorImplementation(Accessor, variableName) \ - (void)set##Accessor:(MPExpression *)value \ @@ -49,7 +48,7 @@ #pragma mark Evaluating Functions -- (BOOL)validate:(MPParseError *__autoreleasing *)error; // Override +- (BOOL)validate:(NSError *__autoreleasing *)error; // Override - (NSDecimalNumber *)evaluate; // Override #pragma mark Messages diff --git a/MathPad/MPFunctionLayout.m b/MathPad/MPFunctionLayout.m index 54a3e67..796dfb0 100644 --- a/MathPad/MPFunctionLayout.m +++ b/MathPad/MPFunctionLayout.m @@ -17,6 +17,8 @@ #import "MPPowerFunctionLayout.h" #import "MPFractionFunctionLayout.h" #import "MPFractionFunction.h" +#import "MPRootFunctionLayout.h" +#import "MPRootFunction.h" #import "NSIndexPath+MPAdditions.h" @@ -35,6 +37,8 @@ return [[MPPowerFunctionLayout alloc] initWithFunction:function parent:parent]; } else if (class == [MPFractionFunction class]) { return [[MPFractionFunctionLayout alloc] initWithFunction:function parent:parent]; + } else if (class == [MPRootFunction class]) { + return [[MPRootFunctionLayout alloc] initWithFunction:function parent:parent]; } return [[self alloc] initWithFunction:function parent:parent]; diff --git a/MathPad/MPFunctionValue.h b/MathPad/MPFunctionValue.h index 8bd73e7..fef3a9a 100644 --- a/MathPad/MPFunctionValue.h +++ b/MathPad/MPFunctionValue.h @@ -7,13 +7,14 @@ // #import +#import "MPPowerFunction.h" +#import "MPFunction+MPValue.h" #import "MPValueGroup.h" @interface MPFunctionValue : NSObject -- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream; // May return an MPFunctionValue or a powered function - -@property (nonatomic, copy) NSString *functionName; -@property (nonatomic, strong) MPValueGroup *valueGroup; +@property (readonly, nonatomic, copy) NSString *functionName; +@property (readonly, nonatomic, strong) MPPowerFunction *power; // May be nil +@property (readonly, nonatomic, strong) MPValueGroup *valueGroup; @end \ No newline at end of file diff --git a/MathPad/MPFunctionValue.m b/MathPad/MPFunctionValue.m index 0a628ad..5cc58e1 100644 --- a/MathPad/MPFunctionValue.m +++ b/MathPad/MPFunctionValue.m @@ -29,7 +29,7 @@ double defaultFunction(double value) {return value;}; switch (tokenStream.currentToken.tokenType) { case MPSinToken: [tokenStream currentTokenConsumed]; - self.functionName = @"sin"; + _functionName = @"sin"; return [self initWithTokenStream:tokenStream function:&sin takesArcValue:YES @@ -37,7 +37,7 @@ double defaultFunction(double value) {return value;}; case MPCosToken: [tokenStream currentTokenConsumed]; - self.functionName = @"cos"; + _functionName = @"cos"; return [self initWithTokenStream:tokenStream function:&cos takesArcValue:YES @@ -45,7 +45,7 @@ double defaultFunction(double value) {return value;}; case MPTanToken: [tokenStream currentTokenConsumed]; - self.functionName = @"tan"; + _functionName = @"tan"; return [self initWithTokenStream:tokenStream function:&tan takesArcValue:YES @@ -53,7 +53,7 @@ double defaultFunction(double value) {return value;}; case MPASinToken: [tokenStream currentTokenConsumed]; - self.functionName = @"asin"; + _functionName = @"asin"; return [self initWithTokenStream:tokenStream function:&asin takesArcValue:YES @@ -61,7 +61,7 @@ double defaultFunction(double value) {return value;}; case MPACosToken: [tokenStream currentTokenConsumed]; - self.functionName = @"acos"; + _functionName = @"acos"; return [self initWithTokenStream:tokenStream function:&acos takesArcValue:YES @@ -69,14 +69,16 @@ double defaultFunction(double value) {return value;}; case MPATanToken: [tokenStream currentTokenConsumed]; - self.functionName = @"atan"; + _functionName = @"atan"; return [self initWithTokenStream:tokenStream function:&atan takesArcValue:YES returnsArcValue:NO]; default: - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Function" userInfo:nil]; + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Expected Function" + userInfo:nil]; break; } return self; @@ -125,12 +127,7 @@ double defaultFunction(double value) {return value;}; } } -- (NSRange)range -{ - return NSMakeRange(0, 0); -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return [self.valueGroup validate:error]; } @@ -140,12 +137,4 @@ double defaultFunction(double value) {return value;}; return _function([self.valueGroup evaluate]); } -- (NSArray *)expressionElements -{ - NSMutableArray *elements = [[NSMutableArray alloc] init]; - [elements addObject:self.functionName]; - [elements addObjectsFromArray:self.valueGroup.expressionElements]; - return elements; -} - @end diff --git a/MathPad/MPNumber.h b/MathPad/MPNumber.h index d74f910..d7fbf08 100644 --- a/MathPad/MPNumber.h +++ b/MathPad/MPNumber.h @@ -11,6 +11,6 @@ @interface MPNumber : NSObject -@property (nonatomic, strong) NSDecimalNumber *number; +@property (readonly, nonatomic, strong) NSDecimalNumber *number; @end diff --git a/MathPad/MPNumber.m b/MathPad/MPNumber.m index ebb0f8c..53dffdb 100644 --- a/MathPad/MPNumber.m +++ b/MathPad/MPNumber.m @@ -8,9 +8,7 @@ #import "MPNumber.h" -@implementation MPNumber { - NSRange _range; -} +@implementation MPNumber - (instancetype)init { @@ -27,10 +25,11 @@ [tokenStream beginIgnoringWhitespaceTokens]; MPToken *token = tokenStream.currentToken; if (token.tokenType == MPNumberToken) { - self.number = [NSDecimalNumber decimalNumberWithString:token.stringValue locale:[NSLocale currentLocale]]; - _range = token.range; + _number = [NSDecimalNumber decimalNumberWithString:token.stringValue locale:[NSLocale currentLocale]]; } else { - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Number" userInfo:nil]; + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Expected Number" + userInfo:nil]; } [tokenStream currentTokenConsumed]; [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; @@ -38,12 +37,7 @@ return self; } -- (NSRange)range -{ - return _range; -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return YES; } @@ -53,9 +47,4 @@ return self.number; } -- (NSArray *)expressionElements -{ - return @[[self.number descriptionWithLocale:[NSLocale currentLocale]]]; -} - @end diff --git a/MathPad/MPOperatorChain.h b/MathPad/MPOperatorChain.h index d21ba16..d3ee31d 100644 --- a/MathPad/MPOperatorChain.h +++ b/MathPad/MPOperatorChain.h @@ -11,7 +11,7 @@ @interface MPOperatorChain : NSObject -@property (nonatomic) BOOL negating; -@property (nonatomic) NSUInteger numberOfOperators; +@property (readonly, nonatomic) BOOL negating; +@property (readonly, nonatomic) NSUInteger numberOfOperators; @end diff --git a/MathPad/MPOperatorChain.m b/MathPad/MPOperatorChain.m index 33c2439..69e89c4 100644 --- a/MathPad/MPOperatorChain.m +++ b/MathPad/MPOperatorChain.m @@ -8,9 +8,7 @@ #import "MPOperatorChain.h" -@implementation MPOperatorChain { - NSRange _range; -} +@implementation MPOperatorChain - (id)init { @@ -26,11 +24,12 @@ if (self) { [tokenStream beginIgnoringWhitespaceTokens]; MPToken *currentToken = tokenStream.currentToken; + if (currentToken.tokenType != MPOperatorListToken) { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Operators" userInfo:nil]; } + NSString *operatorString = currentToken.stringValue; - _range = currentToken.range; operatorString = [[operatorString componentsSeparatedByString:@" "] componentsJoinedByString:@""]; _negating = NO; _numberOfOperators = operatorString.length; @@ -39,18 +38,14 @@ _negating = !_negating; } } + [tokenStream currentTokenConsumed]; [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; } return self; } -- (NSRange)range -{ - return _range; -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return YES; } @@ -60,16 +55,4 @@ return self.negating ? [[NSDecimalNumber alloc] initWithInteger:-1] : [NSDecimalNumber one]; } -- (NSArray *)expressionElements -{ - NSMutableString *text = [[NSMutableString alloc] init]; - for (NSUInteger index = 1; index < self.numberOfOperators; index++) { - [text appendString:@"+"]; - } - if (self.negating) { - [text appendString:@"-"]; - } - return @[text.copy]; -} - @end diff --git a/MathPad/MPParenthesisFunction.m b/MathPad/MPParenthesisFunction.m index b08383b..149883b 100644 --- a/MathPad/MPParenthesisFunction.m +++ b/MathPad/MPParenthesisFunction.m @@ -9,6 +9,8 @@ #import "MPParenthesisFunction.h" +#import "MPExpressionTree.h" + @implementation MPParenthesisFunction MPFunctionAccessorImplementation(Expression, _expression) @@ -18,7 +20,7 @@ MPFunctionAccessorImplementation(Expression, _expression) return @[@"expression"]; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { return [[self.expression parse] validate:error]; } diff --git a/MathPad/MPParenthesisFunctionLayout.m b/MathPad/MPParenthesisFunctionLayout.m index 5c0816a..2b324eb 100644 --- a/MathPad/MPParenthesisFunctionLayout.m +++ b/MathPad/MPParenthesisFunctionLayout.m @@ -122,10 +122,7 @@ - (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index { - if (index == 0) { - return NSMakePoint(self.openingParens.bounds.size.width + MPParenthesisFunctionOpeningParensOffset, 0); - } - return NSZeroPoint; + return NSMakePoint(self.openingParens.bounds.size.width + MPParenthesisFunctionOpeningParensOffset, 0); } - (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point @@ -166,16 +163,19 @@ MPLayout *expressionLayout = [self childLayoutAtIndex:0]; NSBezierPath *closingParens = self.transformedClosingParens; - CGFloat x = 0; + CGFloat y = -openingParens.bounds.origin.y + expressionLayout.bounds.origin.y; + NSAffineTransform *transform = [NSAffineTransform transform]; + [transform translateXBy:0 + yBy:y]; + [openingParens transformUsingAffineTransform:transform]; [openingParens fill]; x += openingParens.bounds.size.width; x += MPParenthesisFunctionOpeningParensOffset; x += expressionLayout.bounds.size.width; x += MPParenthesisFunctionClosingParensOffset; - NSAffineTransform *transform = [NSAffineTransform transform]; [transform translateXBy:x yBy:0]; [closingParens transformUsingAffineTransform:transform]; diff --git a/MathPad/MPParseError.h b/MathPad/MPParseError.h deleted file mode 100644 index f01a328..0000000 --- a/MathPad/MPParseError.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// MPParseError.h -// MathPad -// -// Created by Kim Wittenburg on 08.09.14. -// Copyright (c) 2014 Kim Wittenburg. All rights reserved. -// - -// TODO: Rename to MPSyntaxError - -#import - -@class MPRangePath; - -#define MPParseError(range,key) [[MPParseError alloc] initWithErrorRange:range errorMessageKey:key] - -@interface MPParseError : NSObject - -- (instancetype)initWithErrorRange:(NSRange)errorRange - errorMessageKey:(NSString *)key; - -- (instancetype)initWithErrorRange:(NSRange)errorRange - localizederrorMessage:(NSString *)errorMessage; - -@property (nonatomic, strong) NSIndexPath *pathToExpression; - -@property (nonatomic) NSRange errorRange; -@property (nonatomic, copy) NSString *localizedErrorMessage; - -- (MPRangePath *)rangePath; - -@end diff --git a/MathPad/MPParseError.m b/MathPad/MPParseError.m deleted file mode 100644 index 5923309..0000000 --- a/MathPad/MPParseError.m +++ /dev/null @@ -1,49 +0,0 @@ -// -// MPParseError.m -// MathPad -// -// Created by Kim Wittenburg on 08.09.14. -// Copyright (c) 2014 Kim Wittenburg. All rights reserved. -// - -#import "MPParseError.h" - -#import "MPRangePath.h" -#import "NSIndexPath+MPAdditions.h" - -@implementation MPParseError - -- (instancetype)initWithErrorRange:(NSRange)errorRange errorMessageKey:(NSString *)key -{ - self = [super init]; - if (self) { - _errorRange = errorRange; - _localizedErrorMessage = NSLocalizedString(key, nil); - } - return self; -} - -- (instancetype)initWithErrorRange:(NSRange)errorRange localizederrorMessage:(NSString *)errorMessage -{ - self = [super init]; - if (self) { - _errorRange = errorRange; - _localizedErrorMessage = errorMessage; - } - return self; -} - -- (MPRangePath *)rangePath -{ - NSIndexPath *location = self.pathToExpression; - location = [location indexPathByAddingIndex:self.errorRange.location]; - MPRangePath *rangePath = [MPRangePath rangePathWithLocation:location length:self.errorRange.length]; - return rangePath; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"MPParseError", self.errorRange.location, self.errorRange.length, self.localizedErrorMessage]; -} - -@end diff --git a/MathPad/MPPowerFunction.m b/MathPad/MPPowerFunction.m index 1af59ac..0b4142c 100644 --- a/MathPad/MPPowerFunction.m +++ b/MathPad/MPPowerFunction.m @@ -9,6 +9,8 @@ #import "MPPowerFunction.h" #import "MPExpression.h" +#import "MPExpressionTree.h" + @implementation MPPowerFunction MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression) @@ -18,13 +20,13 @@ MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression) return @[@"exponentExpression"]; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (!self.baseValue) { if (error) { - *error = MPParseError(NSMakeRange([self.parent convertIndex:[self.parent indexOfElement:self] - fromReferenceFrame:MPElementReferenceFrame - toReferenceFrame:MPSymbolReferenceFrame], 0), @"No Base for Power"); + *error = MPParseError(11, + NSLocalizedString(@"No Base For Power.", @"Error message. This is displayed when a power does not have a base value."), + nil); } return NO; } diff --git a/MathPad/MPProduct.h b/MathPad/MPProduct.h index f6aa72c..b195d61 100644 --- a/MathPad/MPProduct.h +++ b/MathPad/MPProduct.h @@ -12,12 +12,6 @@ @interface MPProduct : NSObject -- (NSArray *)factors; -- (void)appendFactor:(MPFactor *)factor; -- (void)insertFactor:(MPFactor *)factor - atIndex:(NSUInteger)index; -- (void)removeFactor:(MPFactor *)factor; -- (void)removeFactorAtIndex:(NSUInteger)index; -- (MPFactor *)factorAtIndex:(NSUInteger)index; +@property (readonly, nonatomic, strong) NSArray *factors; @end diff --git a/MathPad/MPProduct.m b/MathPad/MPProduct.m index 62959ad..365024b 100644 --- a/MathPad/MPProduct.m +++ b/MathPad/MPProduct.m @@ -11,7 +11,6 @@ @implementation MPProduct { NSMutableArray *_factors; - NSRange _range; } - (id)init @@ -29,33 +28,35 @@ if (self) { [tokenStream beginIgnoringWhitespaceTokens]; - MPTokenStreamRecordCurrentLocation(tokenStream); while (tokenStream.currentToken.tokenType != MPOperatorListToken && tokenStream.currentToken.tokenType != MPEOFToken) { [_factors addObject:[[MPFactor alloc] initWithTokenStream:tokenStream]]; } - _range = MPTokenStreamRecordedRange(tokenStream); [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; } return self; } -- (NSRange)range +- (NSArray *)factors { - return _range; + return _factors; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (_factors.count == 0) { if (error) { - *error = MPParseError(_range, @"Expected Value"); + *error = MPParseError(5, + NSLocalizedString(@"Expected A Value.", @"Error message. Displayed when a value was expected in an expression but none was found."), + nil); } return NO; } MPFactor *factor = _factors[0]; if (factor.hasMultiplicationSymbol) { if (error) { - *error = MPParseError(factor.multiplicationSymbolRange, @"Unexpected Symbol."); + *error = MPParseError(6, + NSLocalizedString(@"Unexpected Symbol.", @"Error message. Displayed when or inappropriate symbol was encountered during parsing."), + nil); } return NO; } @@ -88,45 +89,4 @@ return value; } -- (NSArray *)expressionElements -{ - NSMutableArray *elements = [[NSMutableArray alloc] init]; - for (MPFactor *factor in _factors) { - [elements addObjectsFromArray:factor.expressionElements]; - } - return elements; -} - -- (NSArray *)factors -{ - return _factors; -} - -- (void)appendFactor:(MPFactor *)factor -{ - [_factors addObject:factor]; -} - -- (void)insertFactor:(MPFactor *)factor - atIndex:(NSUInteger)index -{ - [_factors insertObject:factor - atIndex:index]; -} - -- (void)removeFactor:(MPFactor *)factor -{ - [_factors removeObject:factor]; -} - -- (void)removeFactorAtIndex:(NSUInteger)index -{ - [_factors removeObjectAtIndex:index]; -} - -- (MPFactor *)factorAtIndex:(NSUInteger)index -{ - return [_factors objectAtIndex:index]; -} - @end diff --git a/MathPad/MPRootFunction.h b/MathPad/MPRootFunction.h new file mode 100644 index 0000000..30fac2c --- /dev/null +++ b/MathPad/MPRootFunction.h @@ -0,0 +1,16 @@ +// +// MPRootFunction.h +// MathPad +// +// Created by Kim Wittenburg on 22.10.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import + +@interface MPRootFunction : MPFunction + +@property (nonatomic, strong) MPExpression *exponentExpression; +@property (nonatomic, strong) MPExpression *radicantExpression; + +@end diff --git a/MathPad/MPRootFunction.m b/MathPad/MPRootFunction.m new file mode 100644 index 0000000..89924af --- /dev/null +++ b/MathPad/MPRootFunction.m @@ -0,0 +1,43 @@ +// +// MPRootFunction.m +// MathPad +// +// Created by Kim Wittenburg on 22.10.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPRootFunction.h" + +#import "MPExpressionTree.h" + +@implementation MPRootFunction + +MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression) +MPFunctionAccessorImplementation(RadicantExpression, _radicantExpression) + +- (NSArray *)childrenAccessors +{ + return @[@"exponentExpression", @"radicantExpression"]; +} + +- (BOOL)validate:(NSError *__autoreleasing *)error +{ + return [[self.exponentExpression parse] validate:error] && [[self.radicantExpression parse] validate:error]; +} + +- (NSDecimalNumber *)evaluate +{ + NSDecimalNumber *exponent = [[self.exponentExpression parse] evaluate]; + NSDecimalNumber *radicant = [[self.radicantExpression parse] evaluate]; + return [[NSDecimalNumber alloc] initWithDouble:pow(radicant.doubleValue, exponent.doubleValue)]; +} + +- (NSString *)description +{ + if (self.exponentExpression == nil) { + return [NSString stringWithFormat:@"√%@", self.radicantExpression.description]; + } + return [NSString stringWithFormat:@"pow(%@; %@)", self.radicantExpression.description, self.exponentExpression]; +} + +@end diff --git a/MathPad/MPRootFunctionLayout.h b/MathPad/MPRootFunctionLayout.h new file mode 100644 index 0000000..4f95328 --- /dev/null +++ b/MathPad/MPRootFunctionLayout.h @@ -0,0 +1,18 @@ +// +// MPRootFunctionLayout.h +// MathPad +// +// Created by Kim Wittenburg on 22.10.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPFunctionLayout.h" +#import "MPRootFunction.h" + +@interface MPRootFunctionLayout : MPFunctionLayout + +- (MPRootFunction *)rootFunction; + +@property (nonatomic, getter=isExponentImplicit) BOOL exponentImplicit; + +@end diff --git a/MathPad/MPRootFunctionLayout.m b/MathPad/MPRootFunctionLayout.m new file mode 100644 index 0000000..0bb20a9 --- /dev/null +++ b/MathPad/MPRootFunctionLayout.m @@ -0,0 +1,82 @@ +// +// MPRootFunctionLayout.m +// MathPad +// +// Created by Kim Wittenburg on 22.10.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPRootFunctionLayout.h" + +#define kRootFunctionSpaceBetweenRadicantAndExponent 5 + +@implementation MPRootFunctionLayout + +- (MPRootFunction *)rootFunction +{ + return (MPRootFunction *)self.function; +} + +- (NSUInteger)indexOfLeadingChild +{ + return 0; +} + +- (NSUInteger)indexOfTrailingChild +{ + return 1; +} + +- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index +{ + return index == 0 ? 1 : [super indexOfChildAfterChildAtIndex:index]; +} + +- (NSUInteger)indexOfChildBeforeChildAtIndex:(NSUInteger)index +{ + return index == 1 ? 0 : [super indexOfChildBeforeChildAtIndex:index]; +} + +- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index +{ + return 1; +} + +- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index +{ + return 0; +} + +- (NSIndexSet *)indexesOfRemainingChildren +{ + return [NSIndexSet indexSetWithIndex:1]; +} + +- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index +{ + NSRect exponentBounds = [self childLayoutAtIndex:0].bounds; + NSRect radicandBounds = [self childLayoutAtIndex:1].bounds; + if (index == 0) { + return NSMakePoint(0, (radicandBounds.size.height + radicandBounds.origin.y) / 2); + } else { + + return NSMakePoint(exponentBounds.size.width + kRootFunctionSpaceBetweenRadicantAndExponent, 0); + } +} + +- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index +{ + return index == 0; +} + +- (NSRect)generateBounds +{ + return NSZeroRect; +} + +- (void)draw +{ + +} + +@end diff --git a/MathPad/MPSuffixFunction.h b/MathPad/MPSuffixFunction.h index 58de168..2ae51e1 100644 --- a/MathPad/MPSuffixFunction.h +++ b/MathPad/MPSuffixFunction.h @@ -8,6 +8,8 @@ #import +#import "MPValueGroup.h" + @interface MPSuffixFunction : MPFunction @property (nonatomic, strong) id baseValue; diff --git a/MathPad/MPSumFunction.m b/MathPad/MPSumFunction.m index 97e3227..b504161 100644 --- a/MathPad/MPSumFunction.m +++ b/MathPad/MPSumFunction.m @@ -11,6 +11,8 @@ #import "MPEvaluationContext.h" +#import "MPExpressionTree.h" + @implementation MPSumFunction MPFunctionAccessorImplementation(StartExpression, _startExpression) @@ -24,7 +26,7 @@ MPFunctionAccessorImplementation(SumExpression, _sumExpression) #pragma mark Evaluating Functions -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { MPExpressionTree *startTree = [self.startExpression parse]; if (![startTree validateExpectingVariableDefinition:YES error:error]) { @@ -67,21 +69,6 @@ MPFunctionAccessorImplementation(SumExpression, _sumExpression) } #pragma mark Working With Functions -/* -- (BOOL)isEqualToFunction:(MPFunction *)aFunction -{ - if (![aFunction isKindOfClass:[MPSumFunction class]]) { - return NO; - } - MPSumFunction *sumFunction = (MPSumFunction *)aFunction; - if (![self.startExpression isEqualToExpression:sumFunction.startExpression]) { - return NO; - } - if (![self.targetExpression isEqualToExpression:sumFunction.targetExpression]) { - return NO; - } - return [self.sumExpression isEqualToExpression:sumFunction.sumExpression]; -}*/ - (NSString *)description { diff --git a/MathPad/MPSumFunctionLayout.m b/MathPad/MPSumFunctionLayout.m index 31ed1dc..c59fee6 100644 --- a/MathPad/MPSumFunctionLayout.m +++ b/MathPad/MPSumFunctionLayout.m @@ -129,13 +129,11 @@ bounds.size.width = MAX(bounds.size.width, targetExpressionBounds.size.width); bounds.size.height += targetExpressionBounds.size.height + kSumFunctionTargetExpressionOffset; - bounds.size.width += kSumFunctionSumExpressionOffset + sumExpressionBounds.size.width; - bounds.size.height = MAX(bounds.size.height, sumExpressionBounds.size.height); - bounds.size.width += kSumFunctionTrailingOffset; - - // The Bounds are a little bigger than the drawn function - bounds.size.height += 6; - bounds.origin.y -= 3; + bounds.size.width += kSumFunctionSumExpressionOffset + sumExpressionBounds.size.width + kSumFunctionTrailingOffset; + CGFloat yOffsetBottom = bounds.origin.y - sumExpressionBounds.origin.y; + CGFloat yOffsetTop = sumExpressionBounds.size.height - (yOffsetBottom + bounds.size.height); + bounds.size.height = MAX(yOffsetBottom, 0) + bounds.size.height + MAX(yOffsetTop, 0); + bounds.origin.y = MIN(sumExpressionBounds.origin.y, bounds.origin.y); return bounds; } diff --git a/MathPad/MPSummand.h b/MathPad/MPSummand.h index bd913f0..3088aa1 100644 --- a/MathPad/MPSummand.h +++ b/MathPad/MPSummand.h @@ -13,7 +13,7 @@ @interface MPSummand : NSObject -@property (nonatomic, strong) MPOperatorChain *operatorChain; -@property (nonatomic, strong) MPProduct *product; +@property (readonly, nonatomic, strong) MPOperatorChain *operatorChain; +@property (readonly, nonatomic, strong) MPProduct *product; @end diff --git a/MathPad/MPSummand.m b/MathPad/MPSummand.m index 5ccaf8e..152972b 100644 --- a/MathPad/MPSummand.m +++ b/MathPad/MPSummand.m @@ -33,16 +33,13 @@ return self; } -- (NSRange)range -{ - return NSUnionRange(self.operatorChain.range, self.product.range); -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (self.operatorChain.numberOfOperators > [MPMathRules sharedRules].maximumOperatorChainLength) { if (error) { - *error = MPParseError(self.operatorChain.range, @"Too many operators."); + *error = MPParseError(4, + NSLocalizedString(@"Too many operators.", @"Error message. This is displayed when there are too many subsequent operators in an expression."), + nil); } return NO; } @@ -58,14 +55,4 @@ return value; } --(NSArray *)expressionElements -{ - NSMutableArray *elements = [[NSMutableArray alloc] init]; - if (self.operatorChain) { - [elements addObjectsFromArray:self.operatorChain.expressionElements]; - } - [elements addObjectsFromArray:self.product.expressionElements]; - return @[self.operatorChain.expressionElements,]; -} - @end diff --git a/MathPad/MPTokenStream.m b/MathPad/MPTokenStream.m index cc22572..af71ff0 100644 --- a/MathPad/MPTokenStream.m +++ b/MathPad/MPTokenStream.m @@ -106,6 +106,7 @@ - (void)currentTokenConsumed { + [self currentToken]; ++_currentTokenIndex; } diff --git a/MathPad/MPUnexpectedSymbolValue.h b/MathPad/MPUnexpectedSymbolValue.h index a714eef..ee54543 100644 --- a/MathPad/MPUnexpectedSymbolValue.h +++ b/MathPad/MPUnexpectedSymbolValue.h @@ -11,6 +11,6 @@ @interface MPUnexpectedSymbolValue : NSObject -@property (nonatomic, copy) NSString *symbol; +@property (readonly, nonatomic, copy) NSString *symbol; @end diff --git a/MathPad/MPUnexpectedSymbolValue.m b/MathPad/MPUnexpectedSymbolValue.m index 562cd46..ccd8dd3 100644 --- a/MathPad/MPUnexpectedSymbolValue.m +++ b/MathPad/MPUnexpectedSymbolValue.m @@ -8,9 +8,7 @@ #import "MPUnexpectedSymbolValue.h" -@implementation MPUnexpectedSymbolValue { - NSRange _range; -} +@implementation MPUnexpectedSymbolValue - (instancetype)init { @@ -25,7 +23,6 @@ self = [self init]; if (self) { [tokenStream beginIgnoringWhitespaceTokens]; - _range = tokenStream.currentToken.range; _symbol = tokenStream.currentToken.stringValue; [tokenStream currentTokenConsumed]; [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; @@ -33,15 +30,12 @@ return self; } -- (NSRange)range -{ - return _range; -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (error) { - *error = MPParseError(self.range, @"Unknown Symbol."); + *error = MPParseError(10, + NSLocalizedString(@"Unknown Symbol.", @"Error message. Displayed when an unknown symbol was encountered during parsing."), + nil); } return NO; } diff --git a/MathPad/MPValueGroup.h b/MathPad/MPValueGroup.h index e77b4f6..840bc33 100644 --- a/MathPad/MPValueGroup.h +++ b/MathPad/MPValueGroup.h @@ -16,13 +16,7 @@ @interface MPValueGroup : NSObject -@property (nonatomic, strong) NSArray *values; -- (void)appendValue:(id)value; -- (void)insertValue:(id)value - atIndex:(NSUInteger)index; -- (void)removeValue:(id)value; -- (void)removeValueAtIndex:(NSUInteger)index; -- (id)valueAtIndex:(NSUInteger)index; +@property (readonly, nonatomic, strong) NSArray *values; @end diff --git a/MathPad/MPValueGroup.m b/MathPad/MPValueGroup.m index a0301b9..d3fc944 100644 --- a/MathPad/MPValueGroup.m +++ b/MathPad/MPValueGroup.m @@ -17,7 +17,6 @@ @implementation MPValueGroup { NSMutableArray *_values; - NSRange _range; } - (id)init @@ -34,7 +33,7 @@ self = [self init]; if (self) { [tokenStream beginIgnoringWhitespaceTokens]; - MPTokenStreamRecordCurrentLocation(tokenStream); // This will also skip leading whitespaces + [tokenStream currentToken]; // This will skip leading whitespaces [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; [tokenStream beginAcceptingWhitespaceTokens]; @@ -57,6 +56,9 @@ case MPGenericFunctionToken: { currentValue = (id)tokenStream.currentToken; + if ([currentValue isKindOfClass:[MPSuffixFunction class]]) { + ((MPSuffixFunction *)currentValue).baseValue = nil; + } [tokenStream currentTokenConsumed]; } break; @@ -85,24 +87,19 @@ [_values addObject:[tokenStream consumeSuffixesForValue:currentValue]]; } } - - _range = MPTokenStreamRecordedRange(tokenStream); [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; } return self; } -- (NSRange)range -{ - return _range; -} - -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (_values.count == 0) { if (error) { - *error = MPParseError(self.range, @"Expected Value"); + *error = MPParseError(8, + NSLocalizedString(@"Expected Value.", @"Error message. This is displayed when a value was expected but none was found."), + nil); } return NO; } @@ -131,42 +128,6 @@ return result; } -- (NSArray *)expressionElements -{ - NSMutableArray *elements = [[NSMutableArray alloc] init]; - for (id value in _values) { - [elements addObjectsFromArray:value.expressionElements]; - } - return elements; -} - -- (void)appendValue:(id)value -{ - [_values addObject:value]; -} - -- (void)insertValue:(id)value - atIndex:(NSUInteger)index -{ - [_values insertObject:value - atIndex:index]; -} - -- (void)removeValue:(id)value -{ - [_values removeObject:value]; -} - -- (void)removeValueAtIndex:(NSUInteger)index -{ - [_values removeObjectAtIndex:index]; -} - -- (id)valueAtIndex:(NSUInteger)index -{ - return [_values objectAtIndex:index]; -} - @end diff --git a/MathPad/MPVariable.h b/MathPad/MPVariable.h index f85e1d2..8d0bba4 100644 --- a/MathPad/MPVariable.h +++ b/MathPad/MPVariable.h @@ -11,6 +11,6 @@ @interface MPVariable : NSObject -@property (nonatomic, strong) NSString *variableName; +@property (readonly, nonatomic, strong) NSString *variableName; @end diff --git a/MathPad/MPVariable.m b/MathPad/MPVariable.m index 415597c..eb7ebfd 100644 --- a/MathPad/MPVariable.m +++ b/MathPad/MPVariable.m @@ -28,7 +28,7 @@ [tokenStream beginIgnoringWhitespaceTokens]; MPToken *token = tokenStream.currentToken; if (token.tokenType == MPVariableToken) { - self.variableName = token.stringValue; + _variableName = token.stringValue; _range = token.range; } else { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Variable" userInfo:nil]; @@ -44,11 +44,13 @@ return _range; } -- (BOOL)validate:(MPParseError *__autoreleasing *)error +- (BOOL)validate:(NSError *__autoreleasing *)error { if (![[MPEvaluationContext sharedContext] isVariableDefined:self.variableName]) { if (error) { - *error = MPParseError(self.range, @"Undefined Variable"); + *error = MPParseError(9, + NSLocalizedString(@"Undefined Variable.", @"Error message. This is displayed when an expression contains an undefined variable."), + nil); } return NO; } @@ -60,9 +62,4 @@ return [[MPEvaluationContext sharedContext] valueForVariable:self.variableName]; } -- (NSArray *)expressionElements -{ - return @[self.variableName]; -} - @end