| 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 */
|
|
|