Archived
1

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:
Kim Wittenburg
2014-11-29 00:19:52 +01:00
parent 4bc2fdead1
commit b6973dc24a
6 changed files with 62 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -65,6 +65,7 @@ typedef NS_ENUM(NSUInteger, MPTokenType) {
MPOperatorListToken, MPOperatorListToken,
MPElementaryFunctionToken, MPElementaryFunctionToken,
MPNumberToken, MPNumberToken,
MPDeformedNumberToken,
MPVariableToken, MPVariableToken,
MPEqualsToken, MPEqualsToken,
MPFactorialToken, MPFactorialToken,