Slight refactor, plus cleanup
This commit is contained in:
parent
348c26aa7d
commit
4a633ff82f
@ -99,28 +99,56 @@ NSComparisonResult compareEvaluatedExpressionsByAttemptBonus(SA_DiceExpression *
|
||||
#pragma mark - Properties
|
||||
/************************/
|
||||
|
||||
// The expression’s type (operation, roll command, simple value, etc.).
|
||||
@property SA_DiceExpressionTermType type;
|
||||
|
||||
@property NSUInteger errorBitMask;
|
||||
/*==============================================================================
|
||||
The following four sets of properties pertain to expressions of specific types.
|
||||
*/
|
||||
|
||||
// Expressions of type SA_DiceExpressionTerm_OPERATION.
|
||||
@property SA_DiceExpressionOperator operator;
|
||||
@property (nonatomic, strong) SA_DiceExpression *leftOperand;
|
||||
@property (nonatomic, strong) SA_DiceExpression *rightOperand;
|
||||
|
||||
// Expressions of type SA_DiceExpressionTerm_ROLL_COMMAND.
|
||||
@property SA_DiceExpressionRollCommand rollCommand;
|
||||
@property (nonatomic, strong) SA_DiceExpression *dieCount;
|
||||
@property (nonatomic, strong) SA_DiceExpression *dieSize;
|
||||
@property SA_DiceExpressionDieType dieType;
|
||||
|
||||
// Expressions of type SA_DiceExpressionTerm_ROLL_MODIFIER.
|
||||
@property SA_DiceExpressionRollModifier rollModifier;
|
||||
|
||||
// Expressions of type SA_DiceExpressionTerm_VALUE.
|
||||
@property (nonatomic, strong) NSNumber *value;
|
||||
|
||||
/*===================================================
|
||||
The following properties pertain to all expressions.
|
||||
*/
|
||||
|
||||
@property SA_DiceExpressionError errorBitMask;
|
||||
|
||||
@property (copy, nonatomic) NSString *inputString;
|
||||
@property (copy, nonatomic) NSAttributedString *attributedInputString;
|
||||
|
||||
/*=========================================================================
|
||||
The following properties pertain to evaluated expressions only.
|
||||
(They have a nil value for expressions which have not yet been evaluated.)
|
||||
*/
|
||||
|
||||
// Evaluated expressions (of any type).
|
||||
@property (nonatomic, strong) NSNumber *result;
|
||||
|
||||
// Evaluated expressions of type SA_DiceExpressionTerm_ROLL_COMMAND.
|
||||
@property (nonatomic, strong) NSArray <NSNumber *> *rolls;
|
||||
|
||||
/****************************/
|
||||
#pragma mark - Public methods
|
||||
/****************************/
|
||||
|
||||
+(instancetype) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
|
||||
toExpression:(SA_DiceExpression *)rightHandExpression
|
||||
withOperator:(SA_DiceExpressionOperator)operator;
|
||||
|
||||
@end
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
#import "SA_DiceExpression.h"
|
||||
|
||||
#import "SA_DiceFormatter.h"
|
||||
|
||||
/*********************/
|
||||
#pragma mark Functions
|
||||
/*********************/
|
||||
@ -74,11 +76,19 @@ NSString *NSStringFromSA_DiceExpressionError(SA_DiceExpressionError error) {
|
||||
@(SA_DiceExpressionError_INTEGER_UNDERFLOW_MULTIPLICATION) : @"SA_DB_ERROR_INTEGER_UNDERFLOW_MULTIPLICATION",
|
||||
@(SA_DiceExpressionError_KEEP_COUNT_EXCEEDS_ROLL_COUNT) : @"SA_DB_ERROR_KEEP_COUNT_EXCEEDS_ROLL_COUNT",
|
||||
@(SA_DiceExpressionError_KEEP_COUNT_NEGATIVE) : @"SA_DB_ERROR_KEEP_COUNT_NEGATIVE"
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
return SA_DiceExpressionErrorStringValues[@(error)];
|
||||
__block NSMutableArray *errorStrings = [NSMutableArray array];
|
||||
[SA_DiceExpressionErrorStringValues enumerateKeysAndObjectsUsingBlock:^(NSNumber *errorKey,
|
||||
NSString *errorString,
|
||||
BOOL *stop) {
|
||||
if (errorKey.unsignedIntegerValue & error)
|
||||
[errorStrings addObject:errorString];
|
||||
}];
|
||||
return [errorStrings componentsJoinedByString:@","];
|
||||
|
||||
// return SA_DiceExpressionErrorStringValues[@(error)];
|
||||
}
|
||||
|
||||
NSComparisonResult compareEvaluatedExpressionsByResult(SA_DiceExpression *expression1,
|
||||
@ -109,6 +119,65 @@ NSComparisonResult compareEvaluatedExpressionsByAttemptBonus(SA_DiceExpression *
|
||||
|
||||
@implementation SA_DiceExpression
|
||||
|
||||
+(SA_DiceExpression *) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
|
||||
toExpression:(SA_DiceExpression *)rightHandExpression
|
||||
withOperator:(SA_DiceExpressionOperator)operator {
|
||||
SA_DiceExpression *expression = [SA_DiceExpression new];
|
||||
|
||||
// First, we check that the operands and operator are not nil. If they are,
|
||||
// then the expression is invalid...
|
||||
if ( leftHandExpression == nil
|
||||
|| rightHandExpression == nil
|
||||
|| operator == SA_DiceExpressionOperator_NONE
|
||||
) {
|
||||
expression.type = SA_DiceExpressionTerm_NONE;
|
||||
expression.errorBitMask |= SA_DiceExpressionError_INVALID_EXPRESSION;
|
||||
return expression;
|
||||
}
|
||||
|
||||
// If the operands and operator are present, then the expression is an
|
||||
// operation expression...
|
||||
expression.type = SA_DiceExpressionTerm_OPERATION;
|
||||
|
||||
// ... but does it have a valid operator?
|
||||
if ( operator == SA_DiceExpressionOperator_MINUS
|
||||
|| operator == SA_DiceExpressionOperator_PLUS
|
||||
|| operator == SA_DiceExpressionOperator_TIMES
|
||||
) {
|
||||
expression.operator = operator;
|
||||
} else {
|
||||
expression.errorBitMask |= SA_DiceExpressionError_UNKNOWN_OPERATOR;
|
||||
return expression;
|
||||
}
|
||||
|
||||
// The operator is valid. Set the operands...
|
||||
expression.leftOperand = leftHandExpression;
|
||||
expression.rightOperand = rightHandExpression;
|
||||
|
||||
// And inherit any errors that they may have.
|
||||
expression.errorBitMask |= expression.leftOperand.errorBitMask;
|
||||
expression.errorBitMask |= expression.rightOperand.errorBitMask;
|
||||
|
||||
// Since this top-level expression was NOT generated by parsing an input
|
||||
// string, for completeness and consistency, we have to generate a fake
|
||||
// input string ourselves! We do this by wrapping each operand in
|
||||
// parentheses and putting the canonical representation of the operator
|
||||
// between them.
|
||||
// TODO: Shouldn't the canonical representation of an operator
|
||||
// possibly vary by formatter behavior...?
|
||||
// But on the other hand, how does a parser know what formatter behavior
|
||||
// is in use...?
|
||||
// TODO: Parentheses aren't even supported by the legacy parser!
|
||||
// This is total nonsense!
|
||||
expression.inputString = [NSString stringWithFormat:@"(%@)%@(%@)",
|
||||
expression.leftOperand.inputString,
|
||||
[SA_DiceFormatter canonicalRepresentationForOperator:expression.operator],
|
||||
expression.rightOperand.inputString];
|
||||
|
||||
// The joining is complete. (Power overwhelming.)
|
||||
return expression;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
#pragma mark - NSCopying methods
|
||||
/*******************************/
|
||||
|
||||
@ -96,6 +96,8 @@
|
||||
|
||||
NOTE 2: Legacy mode does not support whitespace within roll strings.
|
||||
|
||||
TODO: Document exploding dice, Fudge dice, and ‘k’ and ‘l’ operators.
|
||||
|
||||
=====================
|
||||
==== MODERN mode ====
|
||||
=====================
|
||||
@ -152,8 +154,4 @@ typedef NS_ENUM(NSUInteger, SA_DiceParserBehavior) {
|
||||
|
||||
-(SA_DiceExpression *) expressionForString:(NSString *)dieRollString;
|
||||
|
||||
-(SA_DiceExpression *) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
|
||||
toExpression:(SA_DiceExpression *)rightHandExpression
|
||||
withOperator:(SA_DiceExpressionOperator)operator;
|
||||
|
||||
@end
|
||||
|
||||
@ -68,6 +68,7 @@ static NSDictionary *_validCharactersDict;
|
||||
return _defaultParserBehavior;
|
||||
}
|
||||
|
||||
// TODO: Should this be on a per-mode, and therefore per-instance, basis?
|
||||
+(NSDictionary *) validCharactersDict {
|
||||
if (_validCharactersDict == nil) {
|
||||
[SA_DiceParser loadValidCharactersDict];
|
||||
@ -85,13 +86,15 @@ static NSDictionary *_validCharactersDict;
|
||||
}
|
||||
|
||||
-(instancetype) initWithBehavior:(SA_DiceParserBehavior)parserBehavior {
|
||||
if (self = [super init]) {
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
self.parserBehavior = parserBehavior;
|
||||
|
||||
if (_validCharactersDict == nil) {
|
||||
[SA_DiceParser loadValidCharactersDict];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -115,57 +118,6 @@ static NSDictionary *_validCharactersDict;
|
||||
}
|
||||
}
|
||||
|
||||
-(SA_DiceExpression *) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
|
||||
toExpression:(SA_DiceExpression *)rightHandExpression
|
||||
withOperator:(SA_DiceExpressionOperator)operator {
|
||||
SA_DiceExpression *expression = [SA_DiceExpression new];
|
||||
|
||||
// First, we check that the operands and operator are not nil. If they are,
|
||||
// then the expression is invalid...
|
||||
if (leftHandExpression == nil ||
|
||||
rightHandExpression == nil ||
|
||||
operator == SA_DiceExpressionOperator_NONE) {
|
||||
expression.type = SA_DiceExpressionTerm_NONE;
|
||||
expression.errorBitMask |= SA_DiceExpressionError_INVALID_EXPRESSION;
|
||||
return expression;
|
||||
}
|
||||
|
||||
// If the operands and operator are present, then the expression is an
|
||||
// operation expression...
|
||||
expression.type = SA_DiceExpressionTerm_OPERATION;
|
||||
|
||||
// ... but does it have a valid operator?
|
||||
if (operator == SA_DiceExpressionOperator_MINUS ||
|
||||
operator == SA_DiceExpressionOperator_PLUS ||
|
||||
operator == SA_DiceExpressionOperator_TIMES) {
|
||||
expression.operator = operator;
|
||||
} else {
|
||||
expression.errorBitMask |= SA_DiceExpressionError_UNKNOWN_OPERATOR;
|
||||
return expression;
|
||||
}
|
||||
|
||||
// The operator is valid. Set the operands...
|
||||
expression.leftOperand = leftHandExpression;
|
||||
expression.rightOperand = rightHandExpression;
|
||||
|
||||
// And inherit any errors that they may have.
|
||||
expression.errorBitMask |= expression.leftOperand.errorBitMask;
|
||||
expression.errorBitMask |= expression.rightOperand.errorBitMask;
|
||||
|
||||
// Since this top-level expression was NOT generated by parsing an input
|
||||
// string, for completeness and consistency, we have to generate a fake
|
||||
// input string ourselves! We do this by wrapping each operand in
|
||||
// parentheses and putting the canonical representation of the operator
|
||||
// between them.
|
||||
expression.inputString = [NSString stringWithFormat:@"(%@)%@(%@)",
|
||||
expression.leftOperand.inputString,
|
||||
[SA_DiceFormatter canonicalRepresentationForOperator:expression.operator],
|
||||
expression.rightOperand.inputString];
|
||||
|
||||
// The joining is complete. (Power overwhelming.)
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
#pragma mark - “Legacy” behavior implementation
|
||||
/**********************************************/
|
||||
@ -234,10 +186,9 @@ static NSDictionary *_validCharactersDict;
|
||||
// expression type fall through to the remaining cases (roll command
|
||||
// or simple value).
|
||||
// In the latter case, we register an error and return.
|
||||
if (dieRollString.length == lastOperatorRange.length ||
|
||||
![[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_MINUS] containsCharactersInString:operator]) {
|
||||
if ( dieRollString.length == lastOperatorRange.length
|
||||
|| ([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_MINUS] containsCharactersInString:operator] == NO)) {
|
||||
SA_DiceExpression *expression = [SA_DiceExpression new];
|
||||
|
||||
expression.type = SA_DiceExpressionTerm_OPERATION;
|
||||
expression.inputString = dieRollString;
|
||||
expression.errorBitMask |= SA_DiceExpressionError_INVALID_EXPRESSION;
|
||||
@ -351,8 +302,6 @@ static NSDictionary *_validCharactersDict;
|
||||
// These roll one or more dice of a given sort, and determine the sum of
|
||||
// their rolled values. (In the “exploding dice” version, each die can
|
||||
// explode, of course.)
|
||||
// In the future, support for other, more complex roll commands might be
|
||||
// added, such as “roll several and return the highest”.
|
||||
if ([[SA_DiceParser validCharactersForRollCommandDelimiter:SA_DiceExpressionRollCommand_SUM]
|
||||
containsString:[dieRollString substringWithRange:delimiterRange]])
|
||||
expression.rollCommand = SA_DiceExpressionRollCommand_SUM;
|
||||
@ -453,6 +402,7 @@ static NSDictionary *_validCharactersDict;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should this be on a per-mode, and therefore per-instance, basis?
|
||||
+(NSString *) allValidCharacters {
|
||||
return [ @[ [SA_DiceParser validNumeralCharacters],
|
||||
[SA_DiceParser allValidRollCommandDelimiterCharacters],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user