浏览代码

Slight refactor, plus cleanup

master
achmizs 4 年前
父节点
当前提交
4a633ff82f
共有 4 个文件被更改,包括 116 次插入71 次删除
  1. 29
    1
      SA_DiceExpression.h
  2. 71
    2
      SA_DiceExpression.m
  3. 2
    4
      SA_DiceParser.h
  4. 14
    64
      SA_DiceParser.m

+ 29
- 1
SA_DiceExpression.h 查看文件

#pragma mark - Properties #pragma mark - Properties
/************************/ /************************/


// The expression’s type (operation, roll command, simple value, etc.).
@property SA_DiceExpressionTermType type; @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 SA_DiceExpressionOperator operator;
@property (nonatomic, strong) SA_DiceExpression *leftOperand; @property (nonatomic, strong) SA_DiceExpression *leftOperand;
@property (nonatomic, strong) SA_DiceExpression *rightOperand; @property (nonatomic, strong) SA_DiceExpression *rightOperand;


// Expressions of type SA_DiceExpressionTerm_ROLL_COMMAND.
@property SA_DiceExpressionRollCommand rollCommand; @property SA_DiceExpressionRollCommand rollCommand;
@property (nonatomic, strong) SA_DiceExpression *dieCount; @property (nonatomic, strong) SA_DiceExpression *dieCount;
@property (nonatomic, strong) SA_DiceExpression *dieSize; @property (nonatomic, strong) SA_DiceExpression *dieSize;
@property SA_DiceExpressionDieType dieType; @property SA_DiceExpressionDieType dieType;


// Expressions of type SA_DiceExpressionTerm_ROLL_MODIFIER.
@property SA_DiceExpressionRollModifier rollModifier; @property SA_DiceExpressionRollModifier rollModifier;


// Expressions of type SA_DiceExpressionTerm_VALUE.
@property (nonatomic, strong) NSNumber *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) NSString *inputString;
@property (copy, nonatomic) NSAttributedString *attributedInputString; @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; @property (nonatomic, strong) NSNumber *result;


// Evaluated expressions of type SA_DiceExpressionTerm_ROLL_COMMAND.
@property (nonatomic, strong) NSArray <NSNumber *> *rolls; @property (nonatomic, strong) NSArray <NSNumber *> *rolls;


/****************************/
#pragma mark - Public methods
/****************************/

+(instancetype) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
toExpression:(SA_DiceExpression *)rightHandExpression
withOperator:(SA_DiceExpressionOperator)operator;

@end @end

+ 71
- 2
SA_DiceExpression.m 查看文件



#import "SA_DiceExpression.h" #import "SA_DiceExpression.h"


#import "SA_DiceFormatter.h"

/*********************/ /*********************/
#pragma mark Functions #pragma mark Functions
/*********************/ /*********************/
@(SA_DiceExpressionError_INTEGER_UNDERFLOW_MULTIPLICATION) : @"SA_DB_ERROR_INTEGER_UNDERFLOW_MULTIPLICATION", @(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_EXCEEDS_ROLL_COUNT) : @"SA_DB_ERROR_KEEP_COUNT_EXCEEDS_ROLL_COUNT",
@(SA_DiceExpressionError_KEEP_COUNT_NEGATIVE) : @"SA_DB_ERROR_KEEP_COUNT_NEGATIVE" @(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, NSComparisonResult compareEvaluatedExpressionsByResult(SA_DiceExpression *expression1,


@implementation 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 #pragma mark - NSCopying methods
/*******************************/ /*******************************/

+ 2
- 4
SA_DiceParser.h 查看文件

NOTE 2: Legacy mode does not support whitespace within roll strings. NOTE 2: Legacy mode does not support whitespace within roll strings.
TODO: Document exploding dice, Fudge dice, and ‘k’ and ‘l’ operators.
===================== =====================
==== MODERN mode ==== ==== MODERN mode ====
===================== =====================


-(SA_DiceExpression *) expressionForString:(NSString *)dieRollString; -(SA_DiceExpression *) expressionForString:(NSString *)dieRollString;


-(SA_DiceExpression *) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
toExpression:(SA_DiceExpression *)rightHandExpression
withOperator:(SA_DiceExpressionOperator)operator;

@end @end

+ 14
- 64
SA_DiceParser.m 查看文件

return _defaultParserBehavior; return _defaultParserBehavior;
} }


// TODO: Should this be on a per-mode, and therefore per-instance, basis?
+(NSDictionary *) validCharactersDict { +(NSDictionary *) validCharactersDict {
if (_validCharactersDict == nil) { if (_validCharactersDict == nil) {
[SA_DiceParser loadValidCharactersDict]; [SA_DiceParser loadValidCharactersDict];
} }


-(instancetype) initWithBehavior:(SA_DiceParserBehavior)parserBehavior { -(instancetype) initWithBehavior:(SA_DiceParserBehavior)parserBehavior {
if (self = [super init]) {
self.parserBehavior = parserBehavior;
if (_validCharactersDict == nil) {
[SA_DiceParser loadValidCharactersDict];
}
if (!(self = [super init]))
return nil;

self.parserBehavior = parserBehavior;

if (_validCharactersDict == nil) {
[SA_DiceParser loadValidCharactersDict];
} }

return self; return self;
} }


} }
} }


-(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 #pragma mark - “Legacy” behavior implementation
/**********************************************/ /**********************************************/
// expression type fall through to the remaining cases (roll command // expression type fall through to the remaining cases (roll command
// or simple value). // or simple value).
// In the latter case, we register an error and return. // 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]; SA_DiceExpression *expression = [SA_DiceExpression new];

expression.type = SA_DiceExpressionTerm_OPERATION; expression.type = SA_DiceExpressionTerm_OPERATION;
expression.inputString = dieRollString; expression.inputString = dieRollString;
expression.errorBitMask |= SA_DiceExpressionError_INVALID_EXPRESSION; expression.errorBitMask |= SA_DiceExpressionError_INVALID_EXPRESSION;
if ([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_PLUS] containsCharactersInString:operatorString]) { if ([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_PLUS] containsCharactersInString:operatorString]) {
// Check to see if the term is an addition operation. // Check to see if the term is an addition operation.
expression.operator = SA_DiceExpressionOperator_PLUS; expression.operator = SA_DiceExpressionOperator_PLUS;
} else if([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_MINUS] containsCharactersInString:operatorString]) {
} else if ([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_MINUS] containsCharactersInString:operatorString]) {
// Check to see if the term is a subtraction operation. // Check to see if the term is a subtraction operation.
expression.operator = SA_DiceExpressionOperator_MINUS; expression.operator = SA_DiceExpressionOperator_MINUS;
} else if([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_TIMES] containsCharactersInString:operatorString]) {
} else if ([[SA_DiceParser validCharactersForOperator:SA_DiceExpressionOperator_TIMES] containsCharactersInString:operatorString]) {
// Check to see if the term is a multiplication operation. // Check to see if the term is a multiplication operation.
// Look for other, lower-precedence operators to the left of the // Look for other, lower-precedence operators to the left of the
// multiplication operator. If found, split the string there // multiplication operator. If found, split the string there
// These roll one or more dice of a given sort, and determine the sum of // 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 // their rolled values. (In the “exploding dice” version, each die can
// explode, of course.) // 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] if ([[SA_DiceParser validCharactersForRollCommandDelimiter:SA_DiceExpressionRollCommand_SUM]
containsString:[dieRollString substringWithRange:delimiterRange]]) containsString:[dieRollString substringWithRange:delimiterRange]])
expression.rollCommand = SA_DiceExpressionRollCommand_SUM; expression.rollCommand = SA_DiceExpressionRollCommand_SUM;
} }
} }


// TODO: Should this be on a per-mode, and therefore per-instance, basis?
+(NSString *) allValidCharacters { +(NSString *) allValidCharacters {
return [ @[ [SA_DiceParser validNumeralCharacters], return [ @[ [SA_DiceParser validNumeralCharacters],
[SA_DiceParser allValidRollCommandDelimiterCharacters], [SA_DiceParser allValidRollCommandDelimiterCharacters],

正在加载...
取消
保存