Permalink
Browse files

% can now be used as a percent

It is currently mutually exclusive with mod. A compile-time option forces you to choose one over the other.  The % term must be the second argument to a binary operator.
  • Loading branch information...
1 parent 0aad716 commit 832ed113251c797b0a538f68137dffd2fbebd00d @davedelong committed Dec 16, 2011
@@ -16,7 +16,11 @@ typedef enum {
@class DDMathEvaluator, DDParser;
-@interface DDExpression : NSObject <NSCoding>
+@interface DDExpression : NSObject <NSCoding> {
+ DDExpression *_parentExpression;
+}
+
+@property (nonatomic, readonly) DDExpression *parentExpression;
+ (id) expressionFromString:(NSString *)expressionString error:(NSError **)error;
@@ -19,6 +19,8 @@
@implementation DDExpression
+@synthesize parentExpression=_parentExpression;
+
+ (id) expressionFromString:(NSString *)expressionString error:(NSError **)error {
DDParser *parser = [DDParser parserWithString:expressionString error:error];
return [parser parsedExpressionWithError:error];
@@ -105,4 +107,8 @@ - (void)encodeWithCoder:(NSCoder *)aCoder {
return;
}
+- (void)_setParentExpression:(DDExpression *)parent {
+ _parentExpression = parent;
+}
+
@end
@@ -43,6 +43,7 @@ extern NSString *const DDOperatorModulo;
extern NSString *const DDOperatorBitwiseNot;
extern NSString *const DDOperatorFactorial;
extern NSString *const DDOperatorDegree;
+extern NSString *const DDOperatorPercent;
extern NSString *const DDOperatorPower;
extern NSString *const DDOperatorParenthesisOpen;
extern NSString *const DDOperatorParenthesisClose;
@@ -31,6 +31,7 @@
NSString *const DDOperatorBitwiseNot = @"not";
NSString *const DDOperatorFactorial = @"factorial";
NSString *const DDOperatorDegree = @"dtor";
+NSString *const DDOperatorPercent = @"percent";
NSString *const DDOperatorPower = @"pow";
NSString *const DDOperatorParenthesisOpen = @"open_paren";
NSString *const DDOperatorParenthesisClose = @"close_paren";
@@ -7,7 +7,7 @@
//
#import <Foundation/Foundation.h>
-#import "DDExpression.h"
+#import "DDExpression_Internal.h"
@interface _DDFunctionExpression : DDExpression {
NSString * function;
@@ -14,6 +14,12 @@
#import "_DDVariableExpression.h"
#import "DDMathParserMacros.h"
+@interface DDExpression ()
+
+- (void)_setParentExpression:(DDExpression *)parent;
+
+@end
+
@implementation _DDFunctionExpression
- (id) initWithFunction:(NSString *)f arguments:(NSArray *)a error:(NSError **)error {
@@ -31,6 +37,9 @@ - (id) initWithFunction:(NSString *)f arguments:(NSArray *)a error:(NSError **)e
function = [f copy];
arguments = [a copy];
+ for (DDExpression *argument in arguments) {
+ [argument _setParentExpression:self];
+ }
}
return self;
}
@@ -43,6 +43,7 @@
+ (DDMathFunction) ceilFunction;
+ (DDMathFunction) absFunction;
+ (DDMathFunction) floorFunction;
++ (DDMathFunction) percentFunction;
+ (DDMathFunction) sinFunction;
+ (DDMathFunction) cosFunction;
@@ -11,6 +11,7 @@
#import "DDExpression.h"
#import "DDMathParserMacros.h"
#import "DDMathEvaluator.h"
+#import "_DDOperatorInfo.h"
#define REQUIRE_N_ARGS(__n) { \
if ([arguments count] != (__n)) { \
@@ -510,6 +511,58 @@ + (DDMathFunction) floorFunction {
return DD_AUTORELEASE([function copy]);
}
++ (DDMathFunction) percentFunction {
+ DDMathFunction function = ^ DDExpression* (NSArray *arguments, NSDictionary *variables, DDMathEvaluator *evaluator, NSError **error) {
+ REQUIRE_N_ARGS(1);
+
+ DDExpression *percentArgument = [arguments objectAtIndex:0];
+ DDExpression *percentExpression = [percentArgument parentExpression];
+ DDExpression *percentContext = [percentExpression parentExpression];
+
+ if (percentContext == nil || [percentExpression expressionType] != DDExpressionTypeFunction) {
+ if (error) {
+ *error = ERR(DDErrorCodeInvalidFormat, @"unable to determine context for percent");
+ }
+ return nil;
+ }
+
+ NSString *parentFunction = [percentContext function];
+ _DDOperatorInfo *operatorInfo = [[_DDOperatorInfo infosForOperatorFunction:parentFunction] lastObject];
+ if (operatorInfo == nil) {
+ if (error) {
+ *error = ERR(DDErrorCodeInvalidFormat, @"unable to determine context for percent");
+ }
+ return nil;
+ }
+
+ if ([operatorInfo arity] != DDOperatorArityBinary) {
+ if (error) {
+ *error = ERR(DDErrorCodeInvalidFormat, @"unable to determine context for percent");
+ }
+ return nil;
+ }
+
+ BOOL percentIsRightArgument = ([[percentContext arguments] objectAtIndex:1] == percentExpression);
+ if ([operatorInfo defaultAssociativity] == DDOperatorAssociativityLeft && !percentIsRightArgument) {
+ if (error) {
+ *error = ERR(DDErrorCodeInvalidFormat, @"unable to determine context for percent");
+ }
+ return nil;
+ }
+
+ DDExpression *baseExpression = [[percentContext arguments] objectAtIndex:0];
+ NSNumber *context = [baseExpression evaluateWithSubstitutions:variables evaluator:evaluator error:error];
+ NSNumber *percent = [percentArgument evaluateWithSubstitutions:variables evaluator:evaluator error:error];
+
+ RETURN_IF_NIL(context);
+ RETURN_IF_NIL(percent);
+
+ NSNumber *result = [NSNumber numberWithDouble:[context doubleValue] * ([percent doubleValue] / 100.0)];
+ return [DDExpression numberExpressionWithNumber:result];
+ };
+ return DD_AUTORELEASE([function copy]);
+}
+
+ (DDMathFunction) sinFunction {
DDMathFunction function = ^ DDExpression* (NSArray *arguments, NSDictionary *variables, DDMathEvaluator *evaluator, NSError **error) {
REQUIRE_N_ARGS(1);
@@ -8,6 +8,8 @@
#import "_DDOperatorInfo.h"
+#define PERCENT_AS_MOD 0
+
@implementation _DDOperatorInfo
@synthesize arity=_arity;
@@ -164,8 +166,10 @@ + (NSArray *)_buildOperators {
[operators addObject:[self infoForOperatorFunction:DDOperatorDivide token:@"\u00f7" arity:DDOperatorArityBinary precedence:precedence associativity:DDOperatorAssociativityLeft]];
precedence++;
+#if PERCENT_AS_MOD
[operators addObject:[self infoForOperatorFunction:DDOperatorModulo token:@"%" arity:DDOperatorArityBinary precedence:precedence associativity:DDOperatorAssociativityLeft]];
precedence++;
+#endif
[operators addObject:[self infoForOperatorFunction:DDOperatorBitwiseNot token:@"~" arity:DDOperatorArityUnary precedence:precedence associativity:DDOperatorAssociativityRight]];
precedence++;
@@ -183,6 +187,11 @@ + (NSArray *)_buildOperators {
[operators addObject:[self infoForOperatorFunction:DDOperatorDegree token:@"\u00ba" arity:DDOperatorArityUnary precedence:precedence associativity:DDOperatorAssociativityLeft]];
// \u00b0 is °
[operators addObject:[self infoForOperatorFunction:DDOperatorDegree token:@"\u00b0" arity:DDOperatorArityUnary precedence:precedence associativity:DDOperatorAssociativityLeft]];
+
+#if !PERCENT_AS_MOD
+ [operators addObject:[self infoForOperatorFunction:DDOperatorPercent token:@"%" arity:DDOperatorArityUnary precedence:precedence associativity:DDOperatorAssociativityLeft]];
+#endif
+
precedence++;
[operators addObject:[self infoForOperatorFunction:DDOperatorPower token:@"**" arity:DDOperatorArityBinary precedence:precedence associativity:DDOperatorAssociativityRight]];

0 comments on commit 832ed11

Please sign in to comment.