Cleaned Code by Removing Location Tracking for Errors
@@ -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 */,
|
||||
|
||||
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 920 KiB |
@@ -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]] : @"";
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
@import Foundation;
|
||||
|
||||
#import "MPParseError.h"
|
||||
|
||||
@protocol MPExpressionElement <NSObject, NSCopying, NSCoding>
|
||||
|
||||
- (BOOL)isString;
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
[current clearCacheInRange:rangePath.rangeAtLastIndex
|
||||
replacementLength:replacementLength];
|
||||
[self.expressionView invalidateIntrinsicContentSize];
|
||||
self.expressionView.error = nil;
|
||||
self.expressionView.needsDisplay = YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -923,24 +914,6 @@
|
||||
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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
@interface MPFactorial : NSObject <MPValue>
|
||||
|
||||
@property (nonatomic, strong) id<MPValue> value;
|
||||
@property (readonly, nonatomic, strong) id<MPValue> value;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
@interface MPNumber : NSObject <MPValue>
|
||||
|
||||
@property (nonatomic, strong) NSDecimalNumber *number;
|
||||
@property (readonly, nonatomic, strong) NSDecimalNumber *number;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -122,10 +122,7 @@
|
||||
|
||||
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
|
||||
{
|
||||
if (index == 0) {
|
||||
return NSMakePoint(self.openingParens.bounds.size.width + MPParenthesisFunctionOpeningParensOffset, 0);
|
||||
}
|
||||
return NSZeroPoint;
|
||||
}
|
||||
|
||||
- (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];
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
18
MathPad/MPRootFunctionLayout.h
Normal 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
|
||||
82
MathPad/MPRootFunctionLayout.m
Normal 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
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#import <MathKit/MathKit.h>
|
||||
|
||||
#import "MPValueGroup.h"
|
||||
|
||||
@interface MPSuffixFunction : MPFunction
|
||||
|
||||
@property (nonatomic, strong) id<MPValue> baseValue;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
|
||||
- (void)currentTokenConsumed
|
||||
{
|
||||
[self currentToken];
|
||||
++_currentTokenIndex;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
@interface MPUnexpectedSymbolValue : NSObject <MPValue>
|
||||
|
||||
@property (nonatomic, copy) NSString *symbol;
|
||||
@property (readonly, nonatomic, copy) NSString *symbol;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -86,23 +88,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
_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
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
@interface MPVariable : NSObject <MPValue>
|
||||
|
||||
@property (nonatomic, strong) NSString *variableName;
|
||||
@property (readonly, nonatomic, strong) NSString *variableName;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
|
||||