Archived
1

Cleaned Code by Removing Location Tracking for Errors

This commit is contained in:
Kim Wittenburg
2014-11-07 19:50:28 +01:00
parent 91e7dbe9f2
commit 139a75f816
59 changed files with 355 additions and 532 deletions

View File

@@ -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 = "<group>"; };
3B0F69A819028C6000817707 /* MPException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPException.m; sourceTree = "<group>"; };
3B0F69AB1902A82C00817707 /* MPExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPExpressionTests.m; path = ../MathPadTests/MPExpressionTests.m; sourceTree = "<group>"; };
3B3A4AAC19F71855001E9D54 /* MPRootFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootFunction.h; sourceTree = "<group>"; };
3B3A4AAD19F71855001E9D54 /* MPRootFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootFunction.m; sourceTree = "<group>"; };
3B3A4AB019F71A11001E9D54 /* MPRootFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootFunctionLayout.h; sourceTree = "<group>"; };
3B3A4AB119F71A11001E9D54 /* MPRootFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootFunctionLayout.m; sourceTree = "<group>"; };
3B528D0D199417740054DB5F /* MPLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLayout.h; sourceTree = "<group>"; };
3B528D0E199417E10054DB5F /* MPExpressionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionLayout.h; sourceTree = "<group>"; };
3B528D0F199417E10054DB5F /* MPExpressionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionLayout.m; sourceTree = "<group>"; };
3B528D11199417E90054DB5F /* MPFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunctionLayout.h; sourceTree = "<group>"; };
3B528D12199417E90054DB5F /* MPFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunctionLayout.m; sourceTree = "<group>"; };
3B52CECE19BE509C00CEDCFC /* MPParseError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPParseError.h; sourceTree = "<group>"; };
3B52CECF19BE509C00CEDCFC /* MPParseError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPParseError.m; sourceTree = "<group>"; };
3B52CEDA19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSRegularExpression+MPParsingAdditions.h"; sourceTree = "<group>"; };
3B52CEDB19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSRegularExpression+MPParsingAdditions.m"; sourceTree = "<group>"; };
3B591BB919C58D000061D86B /* MPMathRules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMathRules.h; sourceTree = "<group>"; };
@@ -453,6 +457,8 @@
3B5FF73A19DB2FF500C8348A /* MPPowerFunction.m */,
3B69B67A19E4915E0028E608 /* MPFractionFunction.h */,
3B69B67B19E4915E0028E608 /* MPFractionFunction.m */,
3B3A4AAC19F71855001E9D54 /* MPRootFunction.h */,
3B3A4AAD19F71855001E9D54 /* MPRootFunction.m */,
);
name = Functions;
sourceTree = "<group>";
@@ -488,6 +494,8 @@
3B69B66B19DB41B90028E608 /* MPPowerFunctionLayout.m */,
3B69B67E19E493630028E608 /* MPFractionFunctionLayout.h */,
3B69B67F19E493630028E608 /* MPFractionFunctionLayout.m */,
3B3A4AB019F71A11001E9D54 /* MPRootFunctionLayout.h */,
3B3A4AB119F71A11001E9D54 /* MPRootFunctionLayout.m */,
);
name = "Function Layouts";
sourceTree = "<group>";
@@ -556,8 +564,6 @@
3B78C85319C2DA5300516335 /* MPEvaluationContext.m */,
3B591BB919C58D000061D86B /* MPMathRules.h */,
3B591BBA19C58D000061D86B /* MPMathRules.m */,
3B52CECE19BE509C00CEDCFC /* MPParseError.h */,
3B52CECF19BE509C00CEDCFC /* MPParseError.m */,
);
name = Evaluation;
sourceTree = "<group>";
@@ -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 */,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 920 KiB

View File

@@ -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]] : @"";
}

View File

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

View File

@@ -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<MPExpressionElement>)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;

View File

@@ -8,8 +8,6 @@
@import Foundation;
#import "MPParseError.h"
@protocol MPExpressionElement <NSObject, NSCopying, NSCoding>
- (BOOL)isString;

View File

@@ -50,7 +50,6 @@
[current clearCacheInRange:rangePath.rangeAtLastIndex
replacementLength:replacementLength];
[self.expressionView invalidateIntrinsicContentSize];
self.expressionView.error = nil;
self.expressionView.needsDisplay = YES;
}

View File

@@ -13,16 +13,9 @@
@interface MPExpressionTree : NSObject <MPExpressionTreeElement>
@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

View File

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

View File

@@ -8,11 +8,7 @@
#import <Foundation/Foundation.h>
#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 <NSObject>
@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

View File

@@ -10,8 +10,6 @@
#import <Cocoa/Cocoa.h>
#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;

View File

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

View File

@@ -13,10 +13,8 @@
@interface MPFactor : NSObject <MPExpressionTreeElement>
@property (nonatomic) BOOL hasMultiplicationSymbol;
@property (nonatomic, strong) MPOperatorChain *operatorChain;
@property (nonatomic, strong) id<MPValue> value;
- (NSRange)multiplicationSymbolRange;
@property (readonly, nonatomic) BOOL hasMultiplicationSymbol;
@property (readonly, nonatomic, strong) MPOperatorChain *operatorChain;
@property (readonly, nonatomic, strong) id<MPValue> value;
@end

View File

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

View File

@@ -11,6 +11,6 @@
@interface MPFactorial : NSObject <MPValue>
@property (nonatomic, strong) id<MPValue> value;
@property (readonly, nonatomic, strong) id<MPValue> value;
@end

View File

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

View File

@@ -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];
}

View File

@@ -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);
}
}

View File

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

View File

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

View File

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

View File

@@ -7,13 +7,14 @@
//
#import <Cocoa/Cocoa.h>
#import "MPPowerFunction.h"
#import "MPFunction+MPValue.h"
#import "MPValueGroup.h"
@interface MPFunctionValue : NSObject <MPValue>
- (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

View File

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

View File

@@ -11,6 +11,6 @@
@interface MPNumber : NSObject <MPValue>
@property (nonatomic, strong) NSDecimalNumber *number;
@property (readonly, nonatomic, strong) NSDecimalNumber *number;
@end

View File

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

View File

@@ -11,7 +11,7 @@
@interface MPOperatorChain : NSObject <MPExpressionTreeElement>
@property (nonatomic) BOOL negating;
@property (nonatomic) NSUInteger numberOfOperators;
@property (readonly, nonatomic) BOOL negating;
@property (readonly, nonatomic) NSUInteger numberOfOperators;
@end

View File

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

View File

@@ -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];
}

View File

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

View File

@@ -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 <Foundation/Foundation.h>
@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

View File

@@ -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<at=(%ld, %ld) message=\"%@\">", self.errorRange.location, self.errorRange.length, self.localizedErrorMessage];
}
@end

View File

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

View File

@@ -12,12 +12,6 @@
@interface MPProduct : NSObject <MPExpressionTreeElement>
- (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

View File

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

16
MathPad/MPRootFunction.h Normal file
View File

@@ -0,0 +1,16 @@
//
// MPRootFunction.h
// MathPad
//
// Created by Kim Wittenburg on 22.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <MathKit/MathKit.h>
@interface MPRootFunction : MPFunction
@property (nonatomic, strong) MPExpression *exponentExpression;
@property (nonatomic, strong) MPExpression *radicantExpression;
@end

43
MathPad/MPRootFunction.m Normal file
View File

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

View File

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

View File

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

View File

@@ -8,6 +8,8 @@
#import <MathKit/MathKit.h>
#import "MPValueGroup.h"
@interface MPSuffixFunction : MPFunction
@property (nonatomic, strong) id<MPValue> baseValue;

View File

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

View File

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

View File

@@ -13,7 +13,7 @@
@interface MPSummand : NSObject <MPExpressionTreeElement>
@property (nonatomic, strong) MPOperatorChain *operatorChain;
@property (nonatomic, strong) MPProduct *product;
@property (readonly, nonatomic, strong) MPOperatorChain *operatorChain;
@property (readonly, nonatomic, strong) MPProduct *product;
@end

View File

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

View File

@@ -106,6 +106,7 @@
- (void)currentTokenConsumed
{
[self currentToken];
++_currentTokenIndex;
}

View File

@@ -11,6 +11,6 @@
@interface MPUnexpectedSymbolValue : NSObject <MPValue>
@property (nonatomic, copy) NSString *symbol;
@property (readonly, nonatomic, copy) NSString *symbol;
@end

View File

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

View File

@@ -16,13 +16,7 @@
@interface MPValueGroup : NSObject <MPValue>
@property (nonatomic, strong) NSArray *values;
- (void)appendValue:(id<MPValue>)value;
- (void)insertValue:(id<MPValue>)value
atIndex:(NSUInteger)index;
- (void)removeValue:(id<MPValue>)value;
- (void)removeValueAtIndex:(NSUInteger)index;
- (id<MPValue>)valueAtIndex:(NSUInteger)index;
@property (readonly, nonatomic, strong) NSArray *values;
@end

View File

@@ -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<MPValue>)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<MPValue> value in _values) {
[elements addObjectsFromArray:value.expressionElements];
}
return elements;
}
- (void)appendValue:(id<MPValue>)value
{
[_values addObject:value];
}
- (void)insertValue:(id<MPValue>)value
atIndex:(NSUInteger)index
{
[_values insertObject:value
atIndex:index];
}
- (void)removeValue:(id<MPValue>)value
{
[_values removeObject:value];
}
- (void)removeValueAtIndex:(NSUInteger)index
{
[_values removeObjectAtIndex:index];
}
- (id<MPValue>)valueAtIndex:(NSUInteger)index
{
return [_values objectAtIndex:index];
}
@end

View File

@@ -11,6 +11,6 @@
@interface MPVariable : NSObject <MPValue>
@property (nonatomic, strong) NSString *variableName;
@property (readonly, nonatomic, strong) NSString *variableName;
@end

View File

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