| @@ -180,7 +180,70 @@ static NSDictionary *_validCharactersDict; | |||
| { | |||
| NSString *operator = [dieRollString substringWithRange:lastOperatorRange]; | |||
| return [self legacyExpressionForStringDescribingOperation:dieRollString withOperator:operator atRange:lastOperatorRange]; | |||
| // If the last (and thus only) operator is the leading character of | |||
| // the expression, then this is one of several possible special cases. | |||
| if(lastOperatorRange.location == 0) | |||
| { | |||
| NSMutableDictionary *expression; | |||
| // First, we check for whether there even is anything more to the | |||
| // roll string besides the operator. If not, then the string is | |||
| // definitely malformed... | |||
| if(dieRollString.length == lastOperatorRange.length) | |||
| { | |||
| expression = [NSMutableDictionary dictionary]; | |||
| expression[SA_DB_TERM_TYPE] = SA_DB_TERM_TYPE_OPERATION; | |||
| expression[SA_DB_INPUT_STRING] = dieRollString; | |||
| addErrorToExpression(SA_DB_ERROR_INVALID_EXPRESSION, expression); | |||
| return expression; | |||
| } | |||
| // If the last operator is the leading character (i.e. there's just | |||
| // one operator in the expression, and it's at the beginning), and | |||
| // there's more to the expression than just the operator, then | |||
| // this is either an expression whose first term (which may or may | |||
| // not be its only term) is a simple value expression which | |||
| // represents a negative number - or, it's a malformed expression | |||
| // (because operators other than negation cannot begin an | |||
| // expression). | |||
| // In the former case, we do nothing, letting the testing for | |||
| // expression type fall through to the remaining cases (roll command | |||
| // or simple value). | |||
| // In the latter case, we register an error and return. | |||
| if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_MINUS] containsCharactersInString:operator]) | |||
| { | |||
| // We've determined that this expression begins with a simple | |||
| // value expression that represents a negative number. | |||
| // This next line is a hack to account for the fact that Cocoa's | |||
| // Unicode compliance is incomplete. :( NSString's integerValue | |||
| // method only accepts the hyphen as a negation sign when reading a | |||
| // number - not any of the Unicode characters which officially | |||
| // symbolize negation! But we are more modern-minded, and accept | |||
| // arbitrary symbols as minus-sign. For proper parsing, though, | |||
| // we have to replace it like this... | |||
| dieRollString = [dieRollString stringByReplacingCharactersInRange:lastOperatorRange withString:@"-"]; | |||
| // Now we skip the remainder of the "is it an operator?" code | |||
| // and fall through to "is it a roll command, or maybe a simple | |||
| // value?"... | |||
| } | |||
| else | |||
| { | |||
| expression = [NSMutableDictionary dictionary]; | |||
| expression[SA_DB_TERM_TYPE] = SA_DB_TERM_TYPE_OPERATION; | |||
| expression[SA_DB_INPUT_STRING] = dieRollString; | |||
| addErrorToExpression(SA_DB_ERROR_INVALID_EXPRESSION, expression); | |||
| return expression; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| return [self legacyExpressionForStringDescribingOperation:dieRollString withOperator:operator atRange:lastOperatorRange]; | |||
| } | |||
| } | |||
| // If not an operation, the top-level term might be a die roll command. | |||
| @@ -202,90 +265,44 @@ static NSDictionary *_validCharactersDict; | |||
| { | |||
| NSMutableDictionary *expression; | |||
| // If the operator is at the beginning, this may be negation; we handle that | |||
| // case later below. Otherwise, it's a binary operator. | |||
| if(operatorRange.location != 0) | |||
| expression = [NSMutableDictionary dictionary]; | |||
| expression[SA_DB_TERM_TYPE] = SA_DB_TERM_TYPE_OPERATION; | |||
| expression[SA_DB_INPUT_STRING] = dieRollString; | |||
| // Operands of a binary operator are the expressions generated by | |||
| // parsing the strings before and after the addition operator. | |||
| expression[SA_DB_OPERAND_LEFT] = [self legacyExpressionForLegalString:[dieRollString substringToIndex:operatorRange.location]]; | |||
| expression[SA_DB_OPERAND_RIGHT] = [self legacyExpressionForLegalString:[dieRollString substringFromIndex:(operatorRange.location + operatorRange.length)]]; | |||
| // Check to see if the term is a subtraction operation. | |||
| if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_MINUS] containsCharactersInString:operator]) | |||
| { | |||
| expression = [NSMutableDictionary dictionary]; | |||
| expression[SA_DB_TERM_TYPE] = SA_DB_TERM_TYPE_OPERATION; | |||
| expression[SA_DB_INPUT_STRING] = dieRollString; | |||
| // Operands of a binary operator are the expressions generated by | |||
| // parsing the strings before and after the addition operator. | |||
| expression[SA_DB_OPERAND_LEFT] = [self legacyExpressionForLegalString:[dieRollString substringToIndex:operatorRange.location]]; | |||
| expression[SA_DB_OPERAND_RIGHT] = [self legacyExpressionForLegalString:[dieRollString substringFromIndex:(operatorRange.location + operatorRange.length)]]; | |||
| // Check to see if the term is a subtraction operation. | |||
| if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_MINUS] containsCharactersInString:operator]) | |||
| { | |||
| expression[SA_DB_OPERATOR] = SA_DB_OPERATOR_MINUS; | |||
| } | |||
| // Check to see if the term is an addition operation. | |||
| else if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_PLUS] containsCharactersInString:operator]) | |||
| { | |||
| expression[SA_DB_OPERATOR] = SA_DB_OPERATOR_PLUS; | |||
| } | |||
| // Check to see if the term is a multiplication operation. | |||
| else if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_TIMES] containsCharactersInString:operator]) | |||
| { | |||
| // Look for other, lower-precedence operators to the left of the | |||
| // multiplication operator. If found, split the string there | |||
| // instead of at the current operator. | |||
| NSString *allLowerPrecedenceOperators = [NSString stringWithFormat:@"%@%@", [SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_PLUS], [SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_MINUS]]; | |||
| NSRange lastLowerPrecedenceOperatorRange = [dieRollString rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:allLowerPrecedenceOperators] options:NSBackwardsSearch range:NSMakeRange(1, operatorRange.location - 1)]; | |||
| if(lastLowerPrecedenceOperatorRange.location != NSNotFound) | |||
| { | |||
| NSString *lowerPrecedenceOperator = [dieRollString substringWithRange:lastLowerPrecedenceOperatorRange]; | |||
| return [self legacyExpressionForStringDescribingOperation:dieRollString withOperator:lowerPrecedenceOperator atRange:lastLowerPrecedenceOperatorRange]; | |||
| } | |||
| expression[SA_DB_OPERATOR] = SA_DB_OPERATOR_TIMES; | |||
| } | |||
| else | |||
| expression[SA_DB_OPERATOR] = SA_DB_OPERATOR_MINUS; | |||
| } | |||
| // Check to see if the term is an addition operation. | |||
| else if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_PLUS] containsCharactersInString:operator]) | |||
| { | |||
| expression[SA_DB_OPERATOR] = SA_DB_OPERATOR_PLUS; | |||
| } | |||
| // Check to see if the term is a multiplication operation. | |||
| else if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_TIMES] containsCharactersInString:operator]) | |||
| { | |||
| // Look for other, lower-precedence operators to the left of the | |||
| // multiplication operator. If found, split the string there | |||
| // instead of at the current operator. | |||
| NSString *allLowerPrecedenceOperators = [NSString stringWithFormat:@"%@%@", [SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_PLUS], [SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_MINUS]]; | |||
| NSRange lastLowerPrecedenceOperatorRange = [dieRollString rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:allLowerPrecedenceOperators] options:NSBackwardsSearch range:NSMakeRange(1, operatorRange.location - 1)]; | |||
| if(lastLowerPrecedenceOperatorRange.location != NSNotFound) | |||
| { | |||
| addErrorToExpression(SA_DB_ERROR_UNKNOWN_OPERATOR, expression); | |||
| NSString *lowerPrecedenceOperator = [dieRollString substringWithRange:lastLowerPrecedenceOperatorRange]; | |||
| return [self legacyExpressionForStringDescribingOperation:dieRollString withOperator:lowerPrecedenceOperator atRange:lastLowerPrecedenceOperatorRange]; | |||
| } | |||
| expression[SA_DB_OPERATOR] = SA_DB_OPERATOR_TIMES; | |||
| } | |||
| // Check to see if the term is a negation operation (we can only reach this | |||
| // case if the subtraction operator is at the beginning). | |||
| else | |||
| { | |||
| if(dieRollString.length == operatorRange.length) | |||
| { | |||
| expression = [NSMutableDictionary dictionary]; | |||
| expression[SA_DB_TERM_TYPE] = SA_DB_TERM_TYPE_OPERATION; | |||
| expression[SA_DB_INPUT_STRING] = dieRollString; | |||
| addErrorToExpression(SA_DB_ERROR_INVALID_EXPRESSION, expression); | |||
| return expression; | |||
| } | |||
| if([[SA_DiceParser validCharactersForOperator:SA_DB_OPERATOR_MINUS] containsCharactersInString:operator]) | |||
| { | |||
| // It turns out this isn't actually an operation expression. It's a | |||
| // simple value expression with a negative number. | |||
| // This next line is a hack to account for the fact that Cocoa's | |||
| // Unicode compliance is incomplete. :( NSString's integerValue | |||
| // method only accepts the hyphen as a negation sign when reading a | |||
| // number - not any of the Unicode characters which officially | |||
| // symbolize negation! But we are more modern-minded, and accept | |||
| // arbitrary symbols as minus-sign. For proper parsing, though, | |||
| // we have to replace it like this... | |||
| NSString *fixedRollString = [dieRollString stringByReplacingCharactersInRange:operatorRange withString:@"-"]; | |||
| return [self legacyExpressionForStringDescribingNumericValue:fixedRollString]; | |||
| } | |||
| else | |||
| { | |||
| expression = [NSMutableDictionary dictionary]; | |||
| expression[SA_DB_TERM_TYPE] = SA_DB_TERM_TYPE_OPERATION; | |||
| expression[SA_DB_INPUT_STRING] = dieRollString; | |||
| addErrorToExpression(SA_DB_ERROR_INVALID_EXPRESSION, expression); | |||
| return expression; | |||
| } | |||
| addErrorToExpression(SA_DB_ERROR_UNKNOWN_OPERATOR, expression); | |||
| } | |||
| // The operands have now been parsed recursively; this parsing may have | |||