diff --git a/DDMathParser/DDMathEvaluator.m b/DDMathParser/DDMathEvaluator.m index 5dbc6d3..1644a29 100644 --- a/DDMathParser/DDMathEvaluator.m +++ b/DDMathParser/DDMathEvaluator.m @@ -271,6 +271,7 @@ + (NSSet *) _standardFunctions { //logical functions @"l_and", @"l_or", + @"l_not", nil]; }); return standardFunctions; diff --git a/DDMathParser/DDMathStringTokenizer.m b/DDMathParser/DDMathStringTokenizer.m index 9e49b88..5a4aae3 100644 --- a/DDMathParser/DDMathStringTokenizer.m +++ b/DDMathParser/DDMathStringTokenizer.m @@ -92,12 +92,12 @@ - (id)initWithString:(NSString *)expressionString error:(NSError **)error { return nil; } } + + [self _processToken:nil withError:error]; if (error && *error) { DD_RELEASE(self); self = nil; - } else { - [self _processToken:nil withError:nil]; } } @@ -119,10 +119,7 @@ - (void)dealloc { - (BOOL)_processToken:(DDMathStringToken *)token withError:(NSError **)error { //figure out if "-" and "+" are unary or binary - BOOL shouldContinue = [self _processUnknownOperatorToken:token withError:error]; - if (!shouldContinue) { - return NO; - } + (void)[self _processUnknownOperatorToken:token withError:error]; if ([token operatorType] == DDOperatorUnaryPlus) { // the unary + operator is a no-op operator. It does nothing, so we'll throw it out @@ -140,8 +137,8 @@ - (BOOL)_processToken:(DDMathStringToken *)token withError:(NSError **)error { } - (BOOL)_processUnknownOperatorToken:(DDMathStringToken *)token withError:(NSError **)error { + DDMathStringToken *previousToken = [_tokens lastObject]; if ([token tokenType] == DDTokenTypeOperator && [token operatorType] == DDOperatorInvalid) { - DDMathStringToken *previousToken = [_tokens lastObject]; DDOperator resolvedOperator = DDOperatorInvalid; BOOL shouldBeUnary = NO; @@ -168,6 +165,14 @@ - (BOOL)_processUnknownOperatorToken:(DDMathStringToken *)token withError:(NSErr } } + if ([[token token] isEqual:@"!"]) { + if (previousToken == nil) { + resolvedOperator = DDOperatorLogicalNot; + } else if ([previousToken tokenType] == DDTokenTypeOperator && [previousToken operatorType] != DDOperatorParenthesisClose) { + resolvedOperator = DDOperatorLogicalNot; + } + } + [token resolveToOperator:resolvedOperator]; if ([token operatorType] == DDOperatorInvalid) { @@ -177,6 +182,14 @@ - (BOOL)_processUnknownOperatorToken:(DDMathStringToken *)token withError:(NSErr return NO; } } + + if (token == nil && [[previousToken token] isEqual:@"!"]) { + [previousToken resolveToOperator:DDOperatorFactorial]; + if (error != nil) { + *error = nil; + } + } + return YES; } diff --git a/DDMathParser/DDParser.m b/DDMathParser/DDParser.m index 9bd634b..468dfd7 100644 --- a/DDMathParser/DDParser.m +++ b/DDMathParser/DDParser.m @@ -145,6 +145,8 @@ - (DDOperatorAssociativity) associativityForOperator:(DDOperator)operatorType { // factorial is always left associative case DDOperatorFactorial: return DDOperatorAssociativityLeft; + // logical not is always right associative + case DDOperatorLogicalNot: return DDOperatorAssociativityRight; default: return DDOperatorAssociativityLeft; } diff --git a/DDMathParser/DDParserTypes.h b/DDMathParser/DDParserTypes.h index cd1d9f6..050fc1d 100644 --- a/DDMathParser/DDParserTypes.h +++ b/DDMathParser/DDParserTypes.h @@ -25,6 +25,7 @@ typedef enum { DDOperatorLogicalOr, DDOperatorLogicalAnd, + DDOperatorLogicalNot, DDOperatorBitwiseOr, DDOperatorBitwiseXor, diff --git a/DDMathParser/NSString+DDMathParsing.m b/DDMathParser/NSString+DDMathParsing.m index 7ee3018..a6d0538 100644 --- a/DDMathParser/NSString+DDMathParsing.m +++ b/DDMathParser/NSString+DDMathParsing.m @@ -18,9 +18,8 @@ - (NSNumber *) numberByEvaluatingString { - (NSNumber *) numberByEvaluatingStringWithSubstitutions:(NSDictionary *)substitutions { NSError *error = nil; NSNumber *returnValue = [self numberByEvaluatingStringWithSubstitutions:substitutions error:&error]; - if (error != nil) { + if (returnValue == nil) { NSLog(@"error: %@", error); - return nil; } return returnValue; } diff --git a/DDMathParser/_DDFunctionUtilities.h b/DDMathParser/_DDFunctionUtilities.h index 4f932ac..d8d086a 100644 --- a/DDMathParser/_DDFunctionUtilities.h +++ b/DDMathParser/_DDFunctionUtilities.h @@ -98,5 +98,6 @@ + (DDMathFunction) l_andFunction; + (DDMathFunction) l_orFunction; ++ (DDMathFunction) l_notFunction; @end diff --git a/DDMathParser/_DDFunctionUtilities.m b/DDMathParser/_DDFunctionUtilities.m index a020e32..8927d9b 100644 --- a/DDMathParser/_DDFunctionUtilities.m +++ b/DDMathParser/_DDFunctionUtilities.m @@ -1097,4 +1097,16 @@ + (DDMathFunction) l_orFunction { return DD_AUTORELEASE([function copy]); } ++ (DDMathFunction) l_notFunction { + DDMathFunction function = ^ DDExpression* (NSArray *arguments, NSDictionary *variables, DDMathEvaluator *evaluator, NSError **error) { +#pragma unused(variables, evaluator) + REQUIRE_N_ARGS(1); + NSNumber *n = [[arguments objectAtIndex:0] evaluateWithSubstitutions:variables evaluator:evaluator error:error]; + NSNumber *result = [NSNumber numberWithBool:![n boolValue]]; + return [DDExpression numberExpressionWithNumber:result]; + + }; + return DD_AUTORELEASE([function copy]); +} + @end diff --git a/DDMathParser/_DDOperatorInfo.m b/DDMathParser/_DDOperatorInfo.m index 179e954..7d95f15 100644 --- a/DDMathParser/_DDOperatorInfo.m +++ b/DDMathParser/_DDOperatorInfo.m @@ -50,6 +50,9 @@ + (NSArray *)_buildOperators { [operators addObject:[self infoForOperator:DDOperatorLogicalAnd arity:DDOperatorArityBinary precedence:precedence token:@"&&" function:@"l_and"]]; precedence++; + [operators addObject:[self infoForOperator:DDOperatorLogicalNot arity:DDOperatorArityUnary precedence:precedence token:@"!" function:@"l_not"]]; + precedence++; + [operators addObject:[self infoForOperator:DDOperatorBitwiseOr arity:DDOperatorArityBinary precedence:precedence token:@"|" function:@"or"]]; precedence++;