Index: source/i18n/nfrule.cpp |
diff --git a/source/i18n/nfrule.cpp b/source/i18n/nfrule.cpp |
index f8ed0b6c35fa68e57555f276b467363e576b9965..f0e0953d802e1aa1cdb730ced1901e97e871c7e7 100644 |
--- a/source/i18n/nfrule.cpp |
+++ b/source/i18n/nfrule.cpp |
@@ -1,6 +1,6 @@ |
/* |
****************************************************************************** |
-* Copyright (C) 1997-2014, International Business Machines |
+* Copyright (C) 1997-2015, International Business Machines |
* Corporation and others. All Rights Reserved. |
****************************************************************************** |
* file name: nfrule.cpp |
@@ -31,25 +31,32 @@ |
U_NAMESPACE_BEGIN |
-NFRule::NFRule(const RuleBasedNumberFormat* _rbnf) |
+NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleText, UErrorCode &status) |
: baseValue((int32_t)0) |
- , radix(0) |
+ , radix(10) |
, exponent(0) |
- , ruleText() |
+ , decimalPoint(0) |
+ , ruleText(_ruleText) |
, sub1(NULL) |
, sub2(NULL) |
, formatter(_rbnf) |
, rulePatternFormat(NULL) |
{ |
+ if (!ruleText.isEmpty()) { |
+ parseRuleDescriptor(ruleText, status); |
+ } |
} |
NFRule::~NFRule() |
{ |
if (sub1 != sub2) { |
delete sub2; |
+ sub2 = NULL; |
} |
delete sub1; |
+ sub1 = NULL; |
delete rulePatternFormat; |
+ rulePatternFormat = NULL; |
} |
static const UChar gLeftBracket = 0x005b; |
@@ -66,11 +73,11 @@ static const UChar gDot = 0x002e; |
static const UChar gTick = 0x0027; |
//static const UChar gMinus = 0x002d; |
static const UChar gSemicolon = 0x003b; |
+static const UChar gX = 0x0078; |
static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */ |
-static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x" */ |
-static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0" */ |
-static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x" */ |
+static const UChar gInf[] = {0x49, 0x6E, 0x66, 0}; /* "Inf" */ |
+static const UChar gNaN[] = {0x4E, 0x61, 0x4E, 0}; /* "NaN" */ |
static const UChar gDollarOpenParenthesis[] = {0x24, 0x28, 0}; /* "$(" */ |
static const UChar gClosedParenthesisDollar[] = {0x29, 0x24, 0}; /* ")$" */ |
@@ -88,7 +95,7 @@ static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */ |
static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */ |
static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */ |
-static const UChar * const tokenStrings[] = { |
+static const UChar * const RULE_PREFIXES[] = { |
gLessLess, gLessPercent, gLessHash, gLessZero, |
gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero, |
gEqualPercent, gEqualHash, gEqualZero, NULL |
@@ -96,7 +103,7 @@ static const UChar * const tokenStrings[] = { |
void |
NFRule::makeRules(UnicodeString& description, |
- const NFRuleSet *ruleSet, |
+ NFRuleSet *owner, |
const NFRule *predecessor, |
const RuleBasedNumberFormat *rbnf, |
NFRuleList& rules, |
@@ -106,29 +113,32 @@ NFRule::makeRules(UnicodeString& description, |
// new it up and initialize its basevalue and divisor |
// (this also strips the rule descriptor, if any, off the |
// descripton string) |
- NFRule* rule1 = new NFRule(rbnf); |
+ NFRule* rule1 = new NFRule(rbnf, description, status); |
/* test for NULL */ |
if (rule1 == 0) { |
status = U_MEMORY_ALLOCATION_ERROR; |
return; |
} |
- rule1->parseRuleDescriptor(description, status); |
+ description = rule1->ruleText; |
// check the description to see whether there's text enclosed |
// in brackets |
int32_t brack1 = description.indexOf(gLeftBracket); |
- int32_t brack2 = description.indexOf(gRightBracket); |
+ int32_t brack2 = brack1 < 0 ? -1 : description.indexOf(gRightBracket); |
// if the description doesn't contain a matched pair of brackets, |
// or if it's of a type that doesn't recognize bracketed text, |
// then leave the description alone, initialize the rule's |
// rule text and substitutions, and return that rule |
- if (brack1 == -1 || brack2 == -1 || brack1 > brack2 |
+ if (brack2 < 0 || brack1 > brack2 |
|| rule1->getType() == kProperFractionRule |
- || rule1->getType() == kNegativeNumberRule) { |
- rule1->extractSubstitutions(ruleSet, description, predecessor, status); |
- rules.add(rule1); |
- } else { |
+ || rule1->getType() == kNegativeNumberRule |
+ || rule1->getType() == kInfinityRule |
+ || rule1->getType() == kNaNRule) |
+ { |
+ rule1->extractSubstitutions(owner, description, predecessor, status); |
+ } |
+ else { |
// if the description does contain a matched pair of brackets, |
// then it's really shorthand for two rules (with one exception) |
NFRule* rule2 = NULL; |
@@ -147,7 +157,7 @@ NFRule::makeRules(UnicodeString& description, |
// set, they both have the same base value; otherwise, |
// increment the original rule's base value ("rule1" actually |
// goes SECOND in the rule set's rule list) |
- rule2 = new NFRule(rbnf); |
+ rule2 = new NFRule(rbnf, UnicodeString(), status); |
/* test for NULL */ |
if (rule2 == 0) { |
status = U_MEMORY_ALLOCATION_ERROR; |
@@ -155,7 +165,7 @@ NFRule::makeRules(UnicodeString& description, |
} |
if (rule1->baseValue >= 0) { |
rule2->baseValue = rule1->baseValue; |
- if (!ruleSet->isFractionRuleSet()) { |
+ if (!owner->isFractionRuleSet()) { |
++rule1->baseValue; |
} |
} |
@@ -186,7 +196,7 @@ NFRule::makeRules(UnicodeString& description, |
if (brack2 + 1 < description.length()) { |
sbuf.append(description, brack2 + 1, description.length() - brack2 - 1); |
} |
- rule2->extractSubstitutions(ruleSet, sbuf, predecessor, status); |
+ rule2->extractSubstitutions(owner, sbuf, predecessor, status); |
} |
// rule1's text includes the text in the brackets but omits |
@@ -197,7 +207,7 @@ NFRule::makeRules(UnicodeString& description, |
if (brack2 + 1 < description.length()) { |
sbuf.append(description, brack2 + 1, description.length() - brack2 - 1); |
} |
- rule1->extractSubstitutions(ruleSet, sbuf, predecessor, status); |
+ rule1->extractSubstitutions(owner, sbuf, predecessor, status); |
// if we only have one rule, return it; if we have two, return |
// a two-element array containing them (notice that rule2 goes |
@@ -205,10 +215,20 @@ NFRule::makeRules(UnicodeString& description, |
// material in the brackets and rule1 INCLUDES the material |
// in the brackets) |
if (rule2 != NULL) { |
- rules.add(rule2); |
+ if (rule2->baseValue >= kNoBase) { |
+ rules.add(rule2); |
+ } |
+ else { |
+ owner->setNonNumericalRule(rule2); |
+ } |
} |
+ } |
+ if (rule1->baseValue >= kNoBase) { |
rules.add(rule1); |
} |
+ else { |
+ owner->setNonNumericalRule(rule1); |
+ } |
} |
/** |
@@ -230,9 +250,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) |
// separated by a colon. The rule descriptor is optional. If |
// it's omitted, just set the base value to 0. |
int32_t p = description.indexOf(gColon); |
- if (p == -1) { |
- setBaseValue((int32_t)0, status); |
- } else { |
+ if (p != -1) { |
// copy the descriptor out into its own string and strip it, |
// along with any trailing whitespace, out of the original |
// description |
@@ -247,25 +265,15 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) |
// check first to see if the rule descriptor matches the token |
// for one of the special rules. If it does, set the base |
- // value to the correct identfier value |
- if (0 == descriptor.compare(gMinusX, 2)) { |
- setType(kNegativeNumberRule); |
- } |
- else if (0 == descriptor.compare(gXDotX, 3)) { |
- setType(kImproperFractionRule); |
- } |
- else if (0 == descriptor.compare(gZeroDotX, 3)) { |
- setType(kProperFractionRule); |
- } |
- else if (0 == descriptor.compare(gXDotZero, 3)) { |
- setType(kMasterRule); |
- } |
- |
- // if the rule descriptor begins with a digit, it's a descriptor |
- // for a normal rule |
- // since we don't have Long.parseLong, and this isn't much work anyway, |
- // just build up the value as we encounter the digits. |
- else if (descriptor.charAt(0) >= gZero && descriptor.charAt(0) <= gNine) { |
+ // value to the correct identifier value |
+ int descriptorLength = descriptor.length(); |
+ UChar firstChar = descriptor.charAt(0); |
+ UChar lastChar = descriptor.charAt(descriptorLength - 1); |
+ if (firstChar >= gZero && firstChar <= gNine && lastChar != gX) { |
+ // if the rule descriptor begins with a digit, it's a descriptor |
+ // for a normal rule |
+ // since we don't have Long.parseLong, and this isn't much work anyway, |
+ // just build up the value as we encounter the digits. |
int64_t val = 0; |
p = 0; |
UChar c = gSpace; |
@@ -275,7 +283,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) |
// stop on a slash or > sign (or at the end of the string), |
// and throw an exception on any other character |
int64_t ll_10 = 10; |
- while (p < descriptor.length()) { |
+ while (p < descriptorLength) { |
c = descriptor.charAt(p); |
if (c >= gZero && c <= gNine) { |
val = val * ll_10 + (int32_t)(c - gZero); |
@@ -304,7 +312,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) |
val = 0; |
++p; |
int64_t ll_10 = 10; |
- while (p < descriptor.length()) { |
+ while (p < descriptorLength) { |
c = descriptor.charAt(p); |
if (c >= gZero && c <= gNine) { |
val = val * ll_10 + (int32_t)(c - gZero); |
@@ -352,7 +360,31 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) |
} |
} |
} |
+ else if (0 == descriptor.compare(gMinusX, 2)) { |
+ setType(kNegativeNumberRule); |
+ } |
+ else if (descriptorLength == 3) { |
+ if (firstChar == gZero && lastChar == gX) { |
+ setBaseValue(kProperFractionRule, status); |
+ decimalPoint = descriptor.charAt(1); |
+ } |
+ else if (firstChar == gX && lastChar == gX) { |
+ setBaseValue(kImproperFractionRule, status); |
+ decimalPoint = descriptor.charAt(1); |
+ } |
+ else if (firstChar == gX && lastChar == gZero) { |
+ setBaseValue(kMasterRule, status); |
+ decimalPoint = descriptor.charAt(1); |
+ } |
+ else if (descriptor.compare(gNaN, 3) == 0) { |
+ setBaseValue(kNaNRule, status); |
+ } |
+ else if (descriptor.compare(gInf, 3) == 0) { |
+ setBaseValue(kInfinityRule, status); |
+ } |
+ } |
} |
+ // else use the default base value for now. |
// finally, if the rule body begins with an apostrophe, strip it off |
// (this is generally used to put whitespace at the beginning of |
@@ -384,11 +416,10 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet, |
return; |
} |
this->ruleText = ruleText; |
- this->rulePatternFormat = NULL; |
sub1 = extractSubstitution(ruleSet, predecessor, status); |
- if (sub1 == NULL || sub1->isNullSubstitution()) { |
+ if (sub1 == NULL) { |
// Small optimization. There is no need to create a redundant NullSubstitution. |
- sub2 = sub1; |
+ sub2 = NULL; |
} |
else { |
sub2 = extractSubstitution(ruleSet, predecessor, status); |
@@ -439,14 +470,13 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet, |
// search the rule's rule text for the first two characters of |
// a substitution token |
- int32_t subStart = indexOfAny(tokenStrings); |
+ int32_t subStart = indexOfAnyRulePrefix(); |
int32_t subEnd = subStart; |
// if we didn't find one, create a null substitution positioned |
// at the end of the rule text |
if (subStart == -1) { |
- return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor, |
- ruleSet, this->formatter, UnicodeString(), status); |
+ return NULL; |
} |
// special-case the ">>>" token, since searching for the > at the |
@@ -473,8 +503,7 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet, |
// unmatched token character), create a null substitution positioned |
// at the end of the rule |
if (subEnd == -1) { |
- return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor, |
- ruleSet, this->formatter, UnicodeString(), status); |
+ return NULL; |
} |
// if we get here, we have a real substitution token (or at least |
@@ -503,6 +532,7 @@ NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status) |
{ |
// set the base value |
baseValue = newBaseValue; |
+ radix = 10; |
// if this isn't a special rule, recalculate the radix and exponent |
// (the radix always defaults to 10; if it's supposed to be something |
@@ -510,7 +540,6 @@ NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status) |
// recalculated again-- the only function that does this is |
// NFRule.parseRuleDescriptor() ) |
if (baseValue >= 1) { |
- radix = 10; |
exponent = expectedExponent(); |
// this function gets called on a fully-constructed rule whose |
@@ -527,7 +556,6 @@ NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status) |
// if this is a special rule, its radix and exponent are basically |
// ignored. Set them to "safe" default values |
} else { |
- radix = 10; |
exponent = 0; |
} |
} |
@@ -560,19 +588,17 @@ NFRule::expectedExponent() const |
/** |
* Searches the rule's rule text for any of the specified strings. |
- * @param strings An array of strings to search the rule's rule |
- * text for |
* @return The index of the first match in the rule's rule text |
* (i.e., the first substring in the rule's rule text that matches |
* _any_ of the strings in "strings"). If none of the strings in |
* "strings" is found in the rule's rule text, returns -1. |
*/ |
int32_t |
-NFRule::indexOfAny(const UChar* const strings[]) const |
+NFRule::indexOfAnyRulePrefix() const |
{ |
int result = -1; |
- for (int i = 0; strings[i]; i++) { |
- int32_t pos = ruleText.indexOf(*strings[i]); |
+ for (int i = 0; RULE_PREFIXES[i]; i++) { |
+ int32_t pos = ruleText.indexOf(*RULE_PREFIXES[i]); |
if (pos != -1 && (result == -1 || pos < result)) { |
result = pos; |
} |
@@ -584,6 +610,19 @@ NFRule::indexOfAny(const UChar* const strings[]) const |
// boilerplate |
//----------------------------------------------------------------------- |
+static UBool |
+util_equalSubstitutions(const NFSubstitution* sub1, const NFSubstitution* sub2) |
+{ |
+ if (sub1) { |
+ if (sub2) { |
+ return *sub1 == *sub2; |
+ } |
+ } else if (!sub2) { |
+ return TRUE; |
+ } |
+ return FALSE; |
+} |
+ |
/** |
* Tests two rules for equality. |
* @param that The rule to compare this one against |
@@ -596,8 +635,8 @@ NFRule::operator==(const NFRule& rhs) const |
&& radix == rhs.radix |
&& exponent == rhs.exponent |
&& ruleText == rhs.ruleText |
- && *sub1 == *rhs.sub1 |
- && *sub2 == *rhs.sub2; |
+ && util_equalSubstitutions(sub1, rhs.sub1) |
+ && util_equalSubstitutions(sub2, rhs.sub2); |
} |
/** |
@@ -619,9 +658,11 @@ NFRule::_appendRuleText(UnicodeString& result) const |
{ |
switch (getType()) { |
case kNegativeNumberRule: result.append(gMinusX, 2); break; |
- case kImproperFractionRule: result.append(gXDotX, 3); break; |
- case kProperFractionRule: result.append(gZeroDotX, 3); break; |
- case kMasterRule: result.append(gXDotZero, 3); break; |
+ case kImproperFractionRule: result.append(gX).append(decimalPoint == 0 ? gDot : decimalPoint).append(gX); break; |
+ case kProperFractionRule: result.append(gZero).append(decimalPoint == 0 ? gDot : decimalPoint).append(gX); break; |
+ case kMasterRule: result.append(gX).append(decimalPoint == 0 ? gDot : decimalPoint).append(gZero); break; |
+ case kInfinityRule: result.append(gInf, 3); break; |
+ case kNaNRule: result.append(gNaN, 3); break; |
default: |
// for a normal rule, write out its base value, and if the radix is |
// something other than 10, write out the radix (with the preceding |
@@ -646,7 +687,7 @@ NFRule::_appendRuleText(UnicodeString& result) const |
// if the rule text begins with a space, write an apostrophe |
// (whitespace after the rule descriptor is ignored; the |
// apostrophe is used to make the whitespace significant) |
- if (ruleText.charAt(0) == gSpace && sub1->getPos() != 0) { |
+ if (ruleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) { |
result.append(gTick); |
} |
@@ -656,10 +697,14 @@ NFRule::_appendRuleText(UnicodeString& result) const |
ruleTextCopy.setTo(ruleText); |
UnicodeString temp; |
- sub2->toString(temp); |
- ruleTextCopy.insert(sub2->getPos(), temp); |
- sub1->toString(temp); |
- ruleTextCopy.insert(sub1->getPos(), temp); |
+ if (sub2 != NULL) { |
+ sub2->toString(temp); |
+ ruleTextCopy.insert(sub2->getPos(), temp); |
+ } |
+ if (sub1 != NULL) { |
+ sub1->toString(temp); |
+ ruleTextCopy.insert(sub1->getPos(), temp); |
+ } |
result.append(ruleTextCopy); |
@@ -682,7 +727,7 @@ NFRule::_appendRuleText(UnicodeString& result) const |
* should be inserted |
*/ |
void |
-NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErrorCode& status) const |
+NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const |
{ |
// first, insert the rule's rule text into toInsertInto at the |
// specified position, then insert the results of the substitutions |
@@ -709,11 +754,11 @@ NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErro |
lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength); |
} |
- if (!sub2->isNullSubstitution()) { |
- sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > pluralRuleStart ? lengthOffset : 0), status); |
+ if (sub2 != NULL) { |
+ sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount, status); |
} |
- if (!sub1->isNullSubstitution()) { |
- sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > pluralRuleStart ? lengthOffset : 0), status); |
+ if (sub1 != NULL) { |
+ sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount, status); |
} |
} |
@@ -727,7 +772,7 @@ NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErro |
* should be inserted |
*/ |
void |
-NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, UErrorCode& status) const |
+NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const |
{ |
// first, insert the rule's rule text into toInsertInto at the |
// specified position, then insert the results of the substitutions |
@@ -747,19 +792,27 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, UError |
if (pluralRuleEnd < ruleText.length() - 1) { |
toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); |
} |
- toInsertInto.insert(pos, |
- rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)), status)); |
+ double pluralVal = number; |
+ if (0 <= pluralVal && pluralVal < 1) { |
+ // We're in a fractional rule, and we have to match the NumeratorSubstitution behavior. |
+ // 2.3 can become 0.2999999999999998 for the fraction due to rounding errors. |
+ pluralVal = uprv_round(pluralVal * uprv_pow(radix, exponent)); |
+ } |
+ else { |
+ pluralVal = pluralVal / uprv_pow(radix, exponent); |
+ } |
+ toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal), status)); |
if (pluralRuleStart > 0) { |
toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)); |
} |
lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength); |
} |
- if (!sub2->isNullSubstitution()) { |
- sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > pluralRuleStart ? lengthOffset : 0), status); |
+ if (sub2 != NULL) { |
+ sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount, status); |
} |
- if (!sub1->isNullSubstitution()) { |
- sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > pluralRuleStart ? lengthOffset : 0), status); |
+ if (sub1 != NULL) { |
+ sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount, status); |
} |
} |
@@ -790,7 +843,7 @@ NFRule::shouldRollBack(double number) const |
// a modulus substitution, its base value isn't an even multiple |
// of 100, and the value we're trying to format _is_ an even |
// multiple of 100. This is called the "rollback rule." |
- if ((sub1->isModulusSubstitution()) || (sub2->isModulusSubstitution())) { |
+ if ((sub1 != NULL && sub1->isModulusSubstitution()) || (sub2 != NULL && sub2->isModulusSubstitution())) { |
int64_t re = util64_pow(radix, exponent); |
return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0; |
} |
@@ -833,7 +886,6 @@ static void dumpUS(FILE* f, const UnicodeString& us) { |
} |
} |
#endif |
- |
UBool |
NFRule::doParse(const UnicodeString& text, |
ParsePosition& parsePosition, |
@@ -846,22 +898,25 @@ NFRule::doParse(const UnicodeString& text, |
ParsePosition pp; |
UnicodeString workText(text); |
+ int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : ruleText.length(); |
+ int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : ruleText.length(); |
+ |
// check to see whether the text before the first substitution |
// matches the text at the beginning of the string being |
// parsed. If it does, strip that off the front of workText; |
// otherwise, dump out with a mismatch |
UnicodeString prefix; |
- prefix.setTo(ruleText, 0, sub1->getPos()); |
+ prefix.setTo(ruleText, 0, sub1Pos); |
#ifdef RBNF_DEBUG |
- fprintf(stderr, "doParse %x ", this); |
+ fprintf(stderr, "doParse %p ", this); |
{ |
UnicodeString rt; |
_appendRuleText(rt); |
dumpUS(stderr, rt); |
} |
- fprintf(stderr, " text: '", this); |
+ fprintf(stderr, " text: '"); |
dumpUS(stderr, text); |
fprintf(stderr, "' prefix: '"); |
dumpUS(stderr, prefix); |
@@ -870,16 +925,28 @@ NFRule::doParse(const UnicodeString& text, |
int32_t prefixLength = text.length() - workText.length(); |
#ifdef RBNF_DEBUG |
- fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), sub1->getPos()); |
+ fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), sub1Pos); |
#endif |
- if (pp.getIndex() == 0 && sub1->getPos() != 0) { |
+ if (pp.getIndex() == 0 && sub1Pos != 0) { |
// commented out because ParsePosition doesn't have error index in 1.1.x |
// restored for ICU4C port |
parsePosition.setErrorIndex(pp.getErrorIndex()); |
resVal.setLong(0); |
return TRUE; |
} |
+ if (baseValue == kInfinityRule) { |
+ // If you match this, don't try to perform any calculations on it. |
+ parsePosition.setIndex(pp.getIndex()); |
+ resVal.setDouble(uprv_getInfinity()); |
+ return TRUE; |
+ } |
+ if (baseValue == kNaNRule) { |
+ // If you match this, don't try to perform any calculations on it. |
+ parsePosition.setIndex(pp.getIndex()); |
+ resVal.setDouble(uprv_getNaN()); |
+ return TRUE; |
+ } |
// this is the fun part. The basic guts of the rule-matching |
// logic is matchToDelimiter(), which is called twice. The first |
@@ -923,7 +990,7 @@ NFRule::doParse(const UnicodeString& text, |
// the substitution, giving us a new partial parse result |
pp.setIndex(0); |
- temp.setTo(ruleText, sub1->getPos(), sub2->getPos() - sub1->getPos()); |
+ temp.setTo(ruleText, sub1Pos, sub2Pos - sub1Pos); |
double partialResult = matchToDelimiter(workText, start, tempBaseValue, |
temp, pp, sub1, |
upperBound); |
@@ -932,7 +999,7 @@ NFRule::doParse(const UnicodeString& text, |
// null substitution), pp is now pointing at the first unmatched |
// character. Take note of that, and try matchToDelimiter() |
// on the input text again |
- if (pp.getIndex() != 0 || sub1->isNullSubstitution()) { |
+ if (pp.getIndex() != 0 || sub1 == NULL) { |
start = pp.getIndex(); |
UnicodeString workText2; |
@@ -943,7 +1010,7 @@ NFRule::doParse(const UnicodeString& text, |
// partial result with whatever it gets back from its |
// substitution if there's a successful match, giving us |
// a real result |
- temp.setTo(ruleText, sub2->getPos(), ruleText.length() - sub2->getPos()); |
+ temp.setTo(ruleText, sub2Pos, ruleText.length() - sub2Pos); |
partialResult = matchToDelimiter(workText2, 0, partialResult, |
temp, pp2, sub2, |
upperBound); |
@@ -951,25 +1018,25 @@ NFRule::doParse(const UnicodeString& text, |
// if we got a successful match on this second |
// matchToDelimiter() call, update the high-water mark |
// and result (if necessary) |
- if (pp2.getIndex() != 0 || sub2->isNullSubstitution()) { |
+ if (pp2.getIndex() != 0 || sub2 == NULL) { |
if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMark) { |
highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex(); |
result = partialResult; |
} |
} |
- // commented out because ParsePosition doesn't have error index in 1.1.x |
- // restored for ICU4C port |
else { |
- int32_t temp = pp2.getErrorIndex() + sub1->getPos() + pp.getIndex(); |
+ // commented out because ParsePosition doesn't have error index in 1.1.x |
+ // restored for ICU4C port |
+ int32_t temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex(); |
if (temp> parsePosition.getErrorIndex()) { |
parsePosition.setErrorIndex(temp); |
} |
} |
} |
- // commented out because ParsePosition doesn't have error index in 1.1.x |
- // restored for ICU4C port |
else { |
- int32_t temp = sub1->getPos() + pp.getErrorIndex(); |
+ // commented out because ParsePosition doesn't have error index in 1.1.x |
+ // restored for ICU4C port |
+ int32_t temp = sub1Pos + pp.getErrorIndex(); |
if (temp > parsePosition.getErrorIndex()) { |
parsePosition.setErrorIndex(temp); |
} |
@@ -977,7 +1044,7 @@ NFRule::doParse(const UnicodeString& text, |
// keep trying to match things until the outer matchToDelimiter() |
// call fails to make a match (each time, it picks up where it |
// left off the previous time) |
- } while (sub1->getPos() != sub2->getPos() |
+ } while (sub1Pos != sub2Pos |
&& pp.getIndex() > 0 |
&& pp.getIndex() < workText.length() |
&& pp.getIndex() != start); |
@@ -999,9 +1066,7 @@ NFRule::doParse(const UnicodeString& text, |
// we have to account for it here. By definition, if the matching |
// rule in a fraction rule set has no substitutions, its numerator |
// is 1, and so the result is the reciprocal of its base value. |
- if (isFractionRule && |
- highWaterMark > 0 && |
- sub1->isNullSubstitution()) { |
+ if (isFractionRule && highWaterMark > 0 && sub1 == NULL) { |
result = 1 / result; |
} |
@@ -1129,9 +1194,9 @@ NFRule::matchToDelimiter(const UnicodeString& text, |
pp.setIndex(dPos + dLen); |
return result.getDouble(); |
} |
- // commented out because ParsePosition doesn't have error index in 1.1.x |
- // restored for ICU4C port |
else { |
+ // commented out because ParsePosition doesn't have error index in 1.1.x |
+ // restored for ICU4C port |
if (tempPP.getErrorIndex() > 0) { |
pp.setErrorIndex(tempPP.getErrorIndex()); |
} else { |
@@ -1155,7 +1220,11 @@ NFRule::matchToDelimiter(const UnicodeString& text, |
// (i.e., is semantically empty), thwe we obviously can't search |
// for "delimiter". Instead, just use "sub" to parse as much of |
// "text" as possible. |
- } else { |
+ } |
+ else if (sub == NULL) { |
+ return _baseValue; |
+ } |
+ else { |
ParsePosition tempPP; |
Formattable result; |
@@ -1167,7 +1236,7 @@ NFRule::matchToDelimiter(const UnicodeString& text, |
formatter->isLenient(), |
#endif |
result); |
- if (success && (tempPP.getIndex() != 0 || sub->isNullSubstitution())) { |
+ if (success && (tempPP.getIndex() != 0)) { |
// if there's a successful match (or it's a null |
// substitution), update pp to point to the first |
// character we didn't match, and pass the result from |
@@ -1175,9 +1244,9 @@ NFRule::matchToDelimiter(const UnicodeString& text, |
pp.setIndex(tempPP.getIndex()); |
return result.getDouble(); |
} |
- // commented out because ParsePosition doesn't have error index in 1.1.x |
- // restored for ICU4C port |
else { |
+ // commented out because ParsePosition doesn't have error index in 1.1.x |
+ // restored for ICU4C port |
pp.setErrorIndex(tempPP.getErrorIndex()); |
} |
@@ -1522,6 +1591,16 @@ NFRule::allIgnorable(const UnicodeString& str, UErrorCode& status) const |
return FALSE; |
} |
+void |
+NFRule::setDecimalFormatSymbols(const DecimalFormatSymbols& newSymbols, UErrorCode& status) { |
+ if (sub1 != NULL) { |
+ sub1->setDecimalFormatSymbols(newSymbols, status); |
+ } |
+ if (sub2 != NULL) { |
+ sub2->setDecimalFormatSymbols(newSymbols, status); |
+ } |
+} |
+ |
U_NAMESPACE_END |
/* U_HAVE_RBNF */ |