Invalid Numbers Are Now a Syntax Error
Syntax Errors Now Include a Range Syntax Errors Are Now Displayed in a Selectable List
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
#import "MPFactorialTerm.h"
|
#import "MPFactorialTerm.h"
|
||||||
|
|
||||||
#define success() state = 0
|
#define success() state = 0
|
||||||
#define fail() state = -1
|
#define fail() self.errorTokenIndex = self.currentTokenIndex; state = -1
|
||||||
|
|
||||||
@interface MPExpressionParser ()
|
@interface MPExpressionParser ()
|
||||||
|
|
||||||
@@ -85,13 +85,13 @@
|
|||||||
if (flag && hasVariableDefinition) {
|
if (flag && hasVariableDefinition) {
|
||||||
result.definedVariable = variableName;
|
result.definedVariable = variableName;
|
||||||
} else if (flag) {
|
} else if (flag) {
|
||||||
[self addErrorWithCode:3 localizedDescription:NSLocalizedString(@"Expected Variable Definition.", nil)];
|
[self addErrorWithCode:3 localizedDescription:NSLocalizedString(@"Expected Variable Definition.", nil) useRange:NO];
|
||||||
if (errors) {
|
if (errors) {
|
||||||
*errors = self.errors;
|
*errors = self.errors;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
} else if (hasVariableDefinition) {
|
} else if (hasVariableDefinition) {
|
||||||
[self addErrorWithCode:4 localizedDescription:NSLocalizedString(@"Unexpected Variable Definition.", nil)];
|
[self addErrorWithCode:4 localizedDescription:NSLocalizedString(@"Unexpected Variable Definition.", nil) useRange:NO];
|
||||||
if (errors) {
|
if (errors) {
|
||||||
*errors = self.errors;
|
*errors = self.errors;
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
[self skipWhitespaces];
|
[self skipWhitespaces];
|
||||||
if (self.currentTokenIndex >= self.tokens.count) {
|
if (self.currentTokenIndex >= self.tokens.count) {
|
||||||
[self addErrorWithCode:5 localizedDescription:NSLocalizedString(@"Empty Expression.", nil)];
|
[self addErrorWithCode:5 localizedDescription:NSLocalizedString(@"Empty Expression.", nil) useRange:NO];
|
||||||
if (errors) {
|
if (errors) {
|
||||||
*errors = self.errors;
|
*errors = self.errors;
|
||||||
}
|
}
|
||||||
@@ -173,6 +173,7 @@
|
|||||||
}
|
}
|
||||||
state = 6;
|
state = 6;
|
||||||
} else {
|
} else {
|
||||||
|
self.value = nil;
|
||||||
state = 4;
|
state = 4;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -191,7 +192,6 @@
|
|||||||
[self.valueGroup addObject:self.value];
|
[self.valueGroup addObject:self.value];
|
||||||
state = 5;
|
state = 5;
|
||||||
} else {
|
} else {
|
||||||
self.errorTokenIndex = self.currentTokenIndex;
|
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -376,10 +376,11 @@
|
|||||||
MPPowerTerm *term = [[MPPowerTerm alloc] initWithFunction:(MPFunction *)self.currentToken errors:&errors];
|
MPPowerTerm *term = [[MPPowerTerm alloc] initWithFunction:(MPFunction *)self.currentToken errors:&errors];
|
||||||
if (!term) {
|
if (!term) {
|
||||||
[self.errors addObjectsFromArray:errors];
|
[self.errors addObjectsFromArray:errors];
|
||||||
}
|
} else {
|
||||||
term.baseTerm = self.value;
|
term.baseTerm = self.value;
|
||||||
self.value = term;
|
self.value = term;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
[self nextToken];
|
[self nextToken];
|
||||||
} else {
|
} else {
|
||||||
checkMore = NO;
|
checkMore = NO;
|
||||||
@@ -389,15 +390,22 @@
|
|||||||
|
|
||||||
- (void)addErrorWithCode:(NSInteger)code
|
- (void)addErrorWithCode:(NSInteger)code
|
||||||
localizedDescription:(NSString *)description
|
localizedDescription:(NSString *)description
|
||||||
|
useRange:(BOOL)flag
|
||||||
{
|
{
|
||||||
|
NSRange errorRange;
|
||||||
|
if (flag) {
|
||||||
|
errorRange = [self.tokens[self.errorTokenIndex] range];
|
||||||
|
} else {
|
||||||
NSInteger errorIndex = [self.expression convertIndex:self.errorTokenIndex
|
NSInteger errorIndex = [self.expression convertIndex:self.errorTokenIndex
|
||||||
fromReferenceFrame:MPTokenReferenceFrame
|
fromReferenceFrame:MPTokenReferenceFrame
|
||||||
toReferenceFrame:MPSymbolReferenceFrame];
|
toReferenceFrame:MPSymbolReferenceFrame];
|
||||||
|
errorRange = NSMakeRange(errorIndex, 0);
|
||||||
|
}
|
||||||
[self.errors addObject:[NSError errorWithDomain:MPMathKitErrorDomain
|
[self.errors addObject:[NSError errorWithDomain:MPMathKitErrorDomain
|
||||||
code:code
|
code:code
|
||||||
userInfo:@{NSLocalizedDescriptionKey: description,
|
userInfo:@{NSLocalizedDescriptionKey: description,
|
||||||
MPPathToExpressionKey: self.expression.indexPath,
|
MPPathToExpressionKey: self.expression.indexPath,
|
||||||
MPErrorIndexKey: @(errorIndex)}]];
|
MPErrorRangeKey: [NSValue valueWithRange:errorRange]}]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)errorOccured
|
- (BOOL)errorOccured
|
||||||
@@ -405,13 +413,15 @@
|
|||||||
[self skipWhitespaces];
|
[self skipWhitespaces];
|
||||||
if (self.currentTokenIndex < self.tokens.count) {
|
if (self.currentTokenIndex < self.tokens.count) {
|
||||||
if (self.errorTokenIndex >= self.tokens.count) {
|
if (self.errorTokenIndex >= self.tokens.count) {
|
||||||
[self addErrorWithCode:0 localizedDescription:NSLocalizedString(@"Unexpected end. Expected Value.", nil)];
|
[self addErrorWithCode:0 localizedDescription:NSLocalizedString(@"Unexpected end. Expected Value", nil) useRange:NO];
|
||||||
} else {
|
} else {
|
||||||
id<MPToken> unexpectedToken = self.tokens[self.errorTokenIndex];
|
id<MPToken> unexpectedToken = self.tokens[self.errorTokenIndex];
|
||||||
if (unexpectedToken.tokenType == MPPowerToken) {
|
if (unexpectedToken.tokenType == MPPowerToken) {
|
||||||
[self addErrorWithCode:34 localizedDescription:NSLocalizedString(@"No base for Power", nil)];
|
[self addErrorWithCode:34 localizedDescription:NSLocalizedString(@"No base for Power", nil) useRange:NO];
|
||||||
|
} else if (unexpectedToken.tokenType == MPDeformedNumberToken) {
|
||||||
|
[self addErrorWithCode:42 localizedDescription:NSLocalizedString(@"Not a Number", nil) useRange:YES];
|
||||||
} else {
|
} else {
|
||||||
[self addErrorWithCode:1 localizedDescription:NSLocalizedString(@"Unexpected Symbol. Expected Value", nil)];
|
[self addErrorWithCode:1 localizedDescription:NSLocalizedString(@"Unexpected Symbol. Expected Value", nil) useRange:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,14 +49,15 @@
|
|||||||
NSString *regexStringFormat = @"\\A(?:"
|
NSString *regexStringFormat = @"\\A(?:"
|
||||||
@"([\\*∙⋅])|"
|
@"([\\*∙⋅])|"
|
||||||
@"([+-](?:\\s*[+-])*)|"
|
@"([+-](?:\\s*[+-])*)|"
|
||||||
@"((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))|"
|
@"((?:\\d+%@(?!\\d+))|(?:(?:\\d*%@){2,}\\d*)|%@)|" // Substitute with decimal separator 3 times
|
||||||
|
@"((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))|" // Substitute with decimal separator 2 times
|
||||||
@"(sin|cos|tan|asin|acos|atan)|"
|
@"(sin|cos|tan|asin|acos|atan)|"
|
||||||
@"([A-Za-z])|"
|
@"([A-Za-z])|"
|
||||||
@"(!)|"
|
@"(!)|"
|
||||||
@"(=)|"
|
@"(=)|"
|
||||||
@"(\\s+)"
|
@"(\\s+)"
|
||||||
@")";
|
@")";
|
||||||
NSString *regexString = [NSString stringWithFormat:regexStringFormat, decimalSeparator, decimalSeparator];
|
NSString *regexString = [NSString stringWithFormat:regexStringFormat, decimalSeparator, decimalSeparator, decimalSeparator, decimalSeparator, decimalSeparator];
|
||||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString
|
||||||
options:0
|
options:0
|
||||||
error:NULL];
|
error:NULL];
|
||||||
@@ -69,12 +70,13 @@
|
|||||||
if (match) {
|
if (match) {
|
||||||
NSRange multiplicationSymbolRange = [match rangeAtIndex:1];
|
NSRange multiplicationSymbolRange = [match rangeAtIndex:1];
|
||||||
NSRange operatorRange = [match rangeAtIndex:2];
|
NSRange operatorRange = [match rangeAtIndex:2];
|
||||||
NSRange numberRange = [match rangeAtIndex:3];
|
NSRange deformedNumberRange = [match rangeAtIndex:3];
|
||||||
NSRange elementaryFunctionRange = [match rangeAtIndex:4];
|
NSRange numberRange = [match rangeAtIndex:4];
|
||||||
NSRange variableRange = [match rangeAtIndex:5];
|
NSRange elementaryFunctionRange = [match rangeAtIndex:5];
|
||||||
NSRange factorialRange = [match rangeAtIndex:6];
|
NSRange variableRange = [match rangeAtIndex:6];
|
||||||
NSRange equalsRange = [match rangeAtIndex:7];
|
NSRange factorialRange = [match rangeAtIndex:7];
|
||||||
NSRange whitespaceRange = [match rangeAtIndex:8];
|
NSRange equalsRange = [match rangeAtIndex:8];
|
||||||
|
NSRange whitespaceRange = [match rangeAtIndex:9];
|
||||||
|
|
||||||
if (MPRangeExists(multiplicationSymbolRange)) {
|
if (MPRangeExists(multiplicationSymbolRange)) {
|
||||||
range = multiplicationSymbolRange;
|
range = multiplicationSymbolRange;
|
||||||
@@ -82,6 +84,9 @@
|
|||||||
} else if (MPRangeExists(operatorRange)) {
|
} else if (MPRangeExists(operatorRange)) {
|
||||||
range = operatorRange;
|
range = operatorRange;
|
||||||
tokenType = MPOperatorListToken;
|
tokenType = MPOperatorListToken;
|
||||||
|
} else if (MPRangeExists(deformedNumberRange)) {
|
||||||
|
range = deformedNumberRange;
|
||||||
|
tokenType = MPDeformedNumberToken;
|
||||||
} else if (MPRangeExists(numberRange)) {
|
} else if (MPRangeExists(numberRange)) {
|
||||||
range = numberRange;
|
range = numberRange;
|
||||||
tokenType = MPNumberToken;
|
tokenType = MPNumberToken;
|
||||||
|
|||||||
@@ -430,23 +430,25 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.syntaxErrorsPopUpButton.hidden = NO;
|
self.syntaxErrorsPopUpButton.hidden = NO;
|
||||||
[self.syntaxErrorsPopUpButton addItemWithTitle:@""];
|
NSString *title;
|
||||||
if (syntaxErrors.count == 1) {
|
if (syntaxErrors.count == 1) {
|
||||||
NSString *title = NSLocalizedString(@"1 Syntax Error", nil);
|
title = NSLocalizedString(@"1 Syntax Error", nil);
|
||||||
NSDictionary *attributes = @{NSForegroundColorAttributeName: [NSColor redColor],
|
|
||||||
NSFontAttributeName: [NSFont boldSystemFontOfSize:12.0]};
|
|
||||||
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
|
|
||||||
[self.syntaxErrorsPopUpButton itemAtIndex:0].attributedTitle = attributedTitle;
|
|
||||||
} else {
|
} else {
|
||||||
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%ld Syntax Errors", nil), syntaxErrors.count];
|
title = [NSString stringWithFormat:NSLocalizedString(@"%ld Syntax Errors", nil), syntaxErrors.count];
|
||||||
|
}
|
||||||
NSDictionary *attributes = @{NSForegroundColorAttributeName: [NSColor redColor],
|
NSDictionary *attributes = @{NSForegroundColorAttributeName: [NSColor redColor],
|
||||||
NSFontAttributeName: [NSFont boldSystemFontOfSize:12.0]};
|
NSFontAttributeName: [NSFont boldSystemFontOfSize:12.0]};
|
||||||
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
|
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
|
||||||
[self.syntaxErrorsPopUpButton itemAtIndex:0].attributedTitle = attributedTitle;
|
NSMenuItem *titleItem = [[NSMenuItem alloc] init];
|
||||||
}
|
titleItem.attributedTitle = attributedTitle;
|
||||||
|
[self.syntaxErrorsPopUpButton.menu addItem:titleItem];
|
||||||
|
|
||||||
NSUInteger index = 0;
|
NSUInteger index = 0;
|
||||||
for (NSError *error in syntaxErrors) {
|
for (NSError *error in syntaxErrors) {
|
||||||
[self.syntaxErrorsPopUpButton addItemWithTitle:error.localizedDescription];
|
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:error.localizedDescription
|
||||||
|
action:NULL
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[self.syntaxErrorsPopUpButton.menu addItem:item];
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,8 +540,9 @@
|
|||||||
{
|
{
|
||||||
NSError *error = self.syntaxErrors[sender.indexOfSelectedItem-1];
|
NSError *error = self.syntaxErrors[sender.indexOfSelectedItem-1];
|
||||||
NSIndexPath *pathToExpression = error.userInfo[MPPathToExpressionKey];
|
NSIndexPath *pathToExpression = error.userInfo[MPPathToExpressionKey];
|
||||||
pathToExpression = [pathToExpression indexPathByAddingIndex:[error.userInfo[MPErrorIndexKey] integerValue]];
|
NSRange errorRange = [error.userInfo[MPErrorRangeKey] rangeValue];
|
||||||
self.selection = MPMakeRangePath(pathToExpression, 0);
|
pathToExpression = [pathToExpression indexPathByAddingIndex:errorRange.location];
|
||||||
|
self.selection = MPMakeRangePath(pathToExpression, errorRange.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Actions
|
#pragma mark Actions
|
||||||
@@ -721,7 +724,7 @@
|
|||||||
fromReferenceFrame:MPSymbolReferenceFrame
|
fromReferenceFrame:MPSymbolReferenceFrame
|
||||||
toReferenceFrame:MPElementReferenceFrame];
|
toReferenceFrame:MPElementReferenceFrame];
|
||||||
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:functionElementIndex];
|
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:functionElementIndex];
|
||||||
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:1] indexPathByAddingIndex:0], 0);
|
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:0] indexPathByAddingIndex:0], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertNewline:(id)sender
|
- (void)insertNewline:(id)sender
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
FOUNDATION_EXPORT NSString *const MPMathKitErrorDomain;
|
FOUNDATION_EXPORT NSString *const MPMathKitErrorDomain;
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString *const MPPathToExpressionKey;
|
FOUNDATION_EXPORT NSString *const MPPathToExpressionKey;
|
||||||
FOUNDATION_EXPORT NSString *const MPErrorIndexKey;
|
FOUNDATION_EXPORT NSString *const MPErrorRangeKey;
|
||||||
|
|
||||||
|
|
||||||
@interface MPParsedExpression : NSObject
|
@interface MPParsedExpression : NSObject
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
NSString *const MPMathKitErrorDomain = @"MPMathKitErrorDomain";
|
NSString *const MPMathKitErrorDomain = @"MPMathKitErrorDomain";
|
||||||
NSString *const MPPathToExpressionKey = @"MPPathToExpressionKey";
|
NSString *const MPPathToExpressionKey = @"MPPathToExpressionKey";
|
||||||
NSString *const MPErrorIndexKey = @"MPErrorIndexKey";
|
NSString *const MPErrorRangeKey = @"MPErrorRangeKey";
|
||||||
|
|
||||||
@implementation MPParsedExpression
|
@implementation MPParsedExpression
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ typedef NS_ENUM(NSUInteger, MPTokenType) {
|
|||||||
MPOperatorListToken,
|
MPOperatorListToken,
|
||||||
MPElementaryFunctionToken,
|
MPElementaryFunctionToken,
|
||||||
MPNumberToken,
|
MPNumberToken,
|
||||||
|
MPDeformedNumberToken,
|
||||||
MPVariableToken,
|
MPVariableToken,
|
||||||
MPEqualsToken,
|
MPEqualsToken,
|
||||||
MPFactorialToken,
|
MPFactorialToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user