| OLD | NEW |
| 1 /* | 1 /* |
| 2 ****************************************************************************** | 2 ****************************************************************************** |
| 3 * Copyright (C) 1997-2014, International Business Machines | 3 * Copyright (C) 1997-2015, International Business Machines |
| 4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
| 5 ****************************************************************************** | 5 ****************************************************************************** |
| 6 * file name: nfrule.cpp | 6 * file name: nfrule.cpp |
| 7 * encoding: US-ASCII | 7 * encoding: US-ASCII |
| 8 * tab size: 8 (not used) | 8 * tab size: 8 (not used) |
| 9 * indentation:4 | 9 * indentation:4 |
| 10 * | 10 * |
| 11 * Modification history | 11 * Modification history |
| 12 * Date Name Comments | 12 * Date Name Comments |
| 13 * 10/11/2001 Doug Ported from ICU4J | 13 * 10/11/2001 Doug Ported from ICU4J |
| (...skipping 10 matching lines...) Expand all Loading... |
| 24 #include "unicode/upluralrules.h" | 24 #include "unicode/upluralrules.h" |
| 25 #include "unicode/coleitr.h" | 25 #include "unicode/coleitr.h" |
| 26 #include "unicode/uchar.h" | 26 #include "unicode/uchar.h" |
| 27 #include "nfrs.h" | 27 #include "nfrs.h" |
| 28 #include "nfrlist.h" | 28 #include "nfrlist.h" |
| 29 #include "nfsubs.h" | 29 #include "nfsubs.h" |
| 30 #include "patternprops.h" | 30 #include "patternprops.h" |
| 31 | 31 |
| 32 U_NAMESPACE_BEGIN | 32 U_NAMESPACE_BEGIN |
| 33 | 33 |
| 34 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf) | 34 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleTex
t, UErrorCode &status) |
| 35 : baseValue((int32_t)0) | 35 : baseValue((int32_t)0) |
| 36 , radix(0) | 36 , radix(10) |
| 37 , exponent(0) | 37 , exponent(0) |
| 38 , ruleText() | 38 , decimalPoint(0) |
| 39 , ruleText(_ruleText) |
| 39 , sub1(NULL) | 40 , sub1(NULL) |
| 40 , sub2(NULL) | 41 , sub2(NULL) |
| 41 , formatter(_rbnf) | 42 , formatter(_rbnf) |
| 42 , rulePatternFormat(NULL) | 43 , rulePatternFormat(NULL) |
| 43 { | 44 { |
| 45 if (!ruleText.isEmpty()) { |
| 46 parseRuleDescriptor(ruleText, status); |
| 47 } |
| 44 } | 48 } |
| 45 | 49 |
| 46 NFRule::~NFRule() | 50 NFRule::~NFRule() |
| 47 { | 51 { |
| 48 if (sub1 != sub2) { | 52 if (sub1 != sub2) { |
| 49 delete sub2; | 53 delete sub2; |
| 54 sub2 = NULL; |
| 50 } | 55 } |
| 51 delete sub1; | 56 delete sub1; |
| 57 sub1 = NULL; |
| 52 delete rulePatternFormat; | 58 delete rulePatternFormat; |
| 59 rulePatternFormat = NULL; |
| 53 } | 60 } |
| 54 | 61 |
| 55 static const UChar gLeftBracket = 0x005b; | 62 static const UChar gLeftBracket = 0x005b; |
| 56 static const UChar gRightBracket = 0x005d; | 63 static const UChar gRightBracket = 0x005d; |
| 57 static const UChar gColon = 0x003a; | 64 static const UChar gColon = 0x003a; |
| 58 static const UChar gZero = 0x0030; | 65 static const UChar gZero = 0x0030; |
| 59 static const UChar gNine = 0x0039; | 66 static const UChar gNine = 0x0039; |
| 60 static const UChar gSpace = 0x0020; | 67 static const UChar gSpace = 0x0020; |
| 61 static const UChar gSlash = 0x002f; | 68 static const UChar gSlash = 0x002f; |
| 62 static const UChar gGreaterThan = 0x003e; | 69 static const UChar gGreaterThan = 0x003e; |
| 63 static const UChar gLessThan = 0x003c; | 70 static const UChar gLessThan = 0x003c; |
| 64 static const UChar gComma = 0x002c; | 71 static const UChar gComma = 0x002c; |
| 65 static const UChar gDot = 0x002e; | 72 static const UChar gDot = 0x002e; |
| 66 static const UChar gTick = 0x0027; | 73 static const UChar gTick = 0x0027; |
| 67 //static const UChar gMinus = 0x002d; | 74 //static const UChar gMinus = 0x002d; |
| 68 static const UChar gSemicolon = 0x003b; | 75 static const UChar gSemicolon = 0x003b; |
| 76 static const UChar gX = 0x0078; |
| 69 | 77 |
| 70 static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */ | 78 static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */ |
| 71 static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x"
*/ | 79 static const UChar gInf[] = {0x49, 0x6E, 0x66, 0}; /* "Inf"
*/ |
| 72 static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0"
*/ | 80 static const UChar gNaN[] = {0x4E, 0x61, 0x4E, 0}; /* "NaN"
*/ |
| 73 static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x"
*/ | |
| 74 | 81 |
| 75 static const UChar gDollarOpenParenthesis[] = {0x24, 0x28, 0}; /* "$(" */ | 82 static const UChar gDollarOpenParenthesis[] = {0x24, 0x28, 0}; /* "$(" */ |
| 76 static const UChar gClosedParenthesisDollar[] = {0x29, 0x24, 0}; /* ")$" */ | 83 static const UChar gClosedParenthesisDollar[] = {0x29, 0x24, 0}; /* ")$" */ |
| 77 | 84 |
| 78 static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */ | 85 static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */ |
| 79 static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */ | 86 static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */ |
| 80 static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */ | 87 static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */ |
| 81 static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */ | 88 static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */ |
| 82 static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */ | 89 static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */ |
| 83 static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */ | 90 static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */ |
| 84 static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */ | 91 static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */ |
| 85 static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */ | 92 static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */ |
| 86 static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */ | 93 static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */ |
| 87 static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */ | 94 static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */ |
| 88 static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */ | 95 static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */ |
| 89 static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>"
*/ | 96 static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>"
*/ |
| 90 | 97 |
| 91 static const UChar * const tokenStrings[] = { | 98 static const UChar * const RULE_PREFIXES[] = { |
| 92 gLessLess, gLessPercent, gLessHash, gLessZero, | 99 gLessLess, gLessPercent, gLessHash, gLessZero, |
| 93 gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero, | 100 gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero, |
| 94 gEqualPercent, gEqualHash, gEqualZero, NULL | 101 gEqualPercent, gEqualHash, gEqualZero, NULL |
| 95 }; | 102 }; |
| 96 | 103 |
| 97 void | 104 void |
| 98 NFRule::makeRules(UnicodeString& description, | 105 NFRule::makeRules(UnicodeString& description, |
| 99 const NFRuleSet *ruleSet, | 106 NFRuleSet *owner, |
| 100 const NFRule *predecessor, | 107 const NFRule *predecessor, |
| 101 const RuleBasedNumberFormat *rbnf, | 108 const RuleBasedNumberFormat *rbnf, |
| 102 NFRuleList& rules, | 109 NFRuleList& rules, |
| 103 UErrorCode& status) | 110 UErrorCode& status) |
| 104 { | 111 { |
| 105 // we know we're making at least one rule, so go ahead and | 112 // we know we're making at least one rule, so go ahead and |
| 106 // new it up and initialize its basevalue and divisor | 113 // new it up and initialize its basevalue and divisor |
| 107 // (this also strips the rule descriptor, if any, off the | 114 // (this also strips the rule descriptor, if any, off the |
| 108 // descripton string) | 115 // descripton string) |
| 109 NFRule* rule1 = new NFRule(rbnf); | 116 NFRule* rule1 = new NFRule(rbnf, description, status); |
| 110 /* test for NULL */ | 117 /* test for NULL */ |
| 111 if (rule1 == 0) { | 118 if (rule1 == 0) { |
| 112 status = U_MEMORY_ALLOCATION_ERROR; | 119 status = U_MEMORY_ALLOCATION_ERROR; |
| 113 return; | 120 return; |
| 114 } | 121 } |
| 115 rule1->parseRuleDescriptor(description, status); | 122 description = rule1->ruleText; |
| 116 | 123 |
| 117 // check the description to see whether there's text enclosed | 124 // check the description to see whether there's text enclosed |
| 118 // in brackets | 125 // in brackets |
| 119 int32_t brack1 = description.indexOf(gLeftBracket); | 126 int32_t brack1 = description.indexOf(gLeftBracket); |
| 120 int32_t brack2 = description.indexOf(gRightBracket); | 127 int32_t brack2 = brack1 < 0 ? -1 : description.indexOf(gRightBracket); |
| 121 | 128 |
| 122 // if the description doesn't contain a matched pair of brackets, | 129 // if the description doesn't contain a matched pair of brackets, |
| 123 // or if it's of a type that doesn't recognize bracketed text, | 130 // or if it's of a type that doesn't recognize bracketed text, |
| 124 // then leave the description alone, initialize the rule's | 131 // then leave the description alone, initialize the rule's |
| 125 // rule text and substitutions, and return that rule | 132 // rule text and substitutions, and return that rule |
| 126 if (brack1 == -1 || brack2 == -1 || brack1 > brack2 | 133 if (brack2 < 0 || brack1 > brack2 |
| 127 || rule1->getType() == kProperFractionRule | 134 || rule1->getType() == kProperFractionRule |
| 128 || rule1->getType() == kNegativeNumberRule) { | 135 || rule1->getType() == kNegativeNumberRule |
| 129 rule1->extractSubstitutions(ruleSet, description, predecessor, status); | 136 || rule1->getType() == kInfinityRule |
| 130 rules.add(rule1); | 137 || rule1->getType() == kNaNRule) |
| 131 } else { | 138 { |
| 139 rule1->extractSubstitutions(owner, description, predecessor, status); |
| 140 } |
| 141 else { |
| 132 // if the description does contain a matched pair of brackets, | 142 // if the description does contain a matched pair of brackets, |
| 133 // then it's really shorthand for two rules (with one exception) | 143 // then it's really shorthand for two rules (with one exception) |
| 134 NFRule* rule2 = NULL; | 144 NFRule* rule2 = NULL; |
| 135 UnicodeString sbuf; | 145 UnicodeString sbuf; |
| 136 | 146 |
| 137 // we'll actually only split the rule into two rules if its | 147 // we'll actually only split the rule into two rules if its |
| 138 // base value is an even multiple of its divisor (or it's one | 148 // base value is an even multiple of its divisor (or it's one |
| 139 // of the special rules) | 149 // of the special rules) |
| 140 if ((rule1->baseValue > 0 | 150 if ((rule1->baseValue > 0 |
| 141 && (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) ==
0) | 151 && (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) ==
0) |
| 142 || rule1->getType() == kImproperFractionRule | 152 || rule1->getType() == kImproperFractionRule |
| 143 || rule1->getType() == kMasterRule) { | 153 || rule1->getType() == kMasterRule) { |
| 144 | 154 |
| 145 // if it passes that test, new up the second rule. If the | 155 // if it passes that test, new up the second rule. If the |
| 146 // rule set both rules will belong to is a fraction rule | 156 // rule set both rules will belong to is a fraction rule |
| 147 // set, they both have the same base value; otherwise, | 157 // set, they both have the same base value; otherwise, |
| 148 // increment the original rule's base value ("rule1" actually | 158 // increment the original rule's base value ("rule1" actually |
| 149 // goes SECOND in the rule set's rule list) | 159 // goes SECOND in the rule set's rule list) |
| 150 rule2 = new NFRule(rbnf); | 160 rule2 = new NFRule(rbnf, UnicodeString(), status); |
| 151 /* test for NULL */ | 161 /* test for NULL */ |
| 152 if (rule2 == 0) { | 162 if (rule2 == 0) { |
| 153 status = U_MEMORY_ALLOCATION_ERROR; | 163 status = U_MEMORY_ALLOCATION_ERROR; |
| 154 return; | 164 return; |
| 155 } | 165 } |
| 156 if (rule1->baseValue >= 0) { | 166 if (rule1->baseValue >= 0) { |
| 157 rule2->baseValue = rule1->baseValue; | 167 rule2->baseValue = rule1->baseValue; |
| 158 if (!ruleSet->isFractionRuleSet()) { | 168 if (!owner->isFractionRuleSet()) { |
| 159 ++rule1->baseValue; | 169 ++rule1->baseValue; |
| 160 } | 170 } |
| 161 } | 171 } |
| 162 | 172 |
| 163 // if the description began with "x.x" and contains bracketed | 173 // if the description began with "x.x" and contains bracketed |
| 164 // text, it describes both the improper fraction rule and | 174 // text, it describes both the improper fraction rule and |
| 165 // the proper fraction rule | 175 // the proper fraction rule |
| 166 else if (rule1->getType() == kImproperFractionRule) { | 176 else if (rule1->getType() == kImproperFractionRule) { |
| 167 rule2->setType(kProperFractionRule); | 177 rule2->setType(kProperFractionRule); |
| 168 } | 178 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 179 // same divisor) | 189 // same divisor) |
| 180 rule2->radix = rule1->radix; | 190 rule2->radix = rule1->radix; |
| 181 rule2->exponent = rule1->exponent; | 191 rule2->exponent = rule1->exponent; |
| 182 | 192 |
| 183 // rule2's rule text omits the stuff in brackets: initalize | 193 // rule2's rule text omits the stuff in brackets: initalize |
| 184 // its rule text and substitutions accordingly | 194 // its rule text and substitutions accordingly |
| 185 sbuf.append(description, 0, brack1); | 195 sbuf.append(description, 0, brack1); |
| 186 if (brack2 + 1 < description.length()) { | 196 if (brack2 + 1 < description.length()) { |
| 187 sbuf.append(description, brack2 + 1, description.length() - brac
k2 - 1); | 197 sbuf.append(description, brack2 + 1, description.length() - brac
k2 - 1); |
| 188 } | 198 } |
| 189 rule2->extractSubstitutions(ruleSet, sbuf, predecessor, status); | 199 rule2->extractSubstitutions(owner, sbuf, predecessor, status); |
| 190 } | 200 } |
| 191 | 201 |
| 192 // rule1's text includes the text in the brackets but omits | 202 // rule1's text includes the text in the brackets but omits |
| 193 // the brackets themselves: initialize _its_ rule text and | 203 // the brackets themselves: initialize _its_ rule text and |
| 194 // substitutions accordingly | 204 // substitutions accordingly |
| 195 sbuf.setTo(description, 0, brack1); | 205 sbuf.setTo(description, 0, brack1); |
| 196 sbuf.append(description, brack1 + 1, brack2 - brack1 - 1); | 206 sbuf.append(description, brack1 + 1, brack2 - brack1 - 1); |
| 197 if (brack2 + 1 < description.length()) { | 207 if (brack2 + 1 < description.length()) { |
| 198 sbuf.append(description, brack2 + 1, description.length() - brack2 -
1); | 208 sbuf.append(description, brack2 + 1, description.length() - brack2 -
1); |
| 199 } | 209 } |
| 200 rule1->extractSubstitutions(ruleSet, sbuf, predecessor, status); | 210 rule1->extractSubstitutions(owner, sbuf, predecessor, status); |
| 201 | 211 |
| 202 // if we only have one rule, return it; if we have two, return | 212 // if we only have one rule, return it; if we have two, return |
| 203 // a two-element array containing them (notice that rule2 goes | 213 // a two-element array containing them (notice that rule2 goes |
| 204 // BEFORE rule1 in the list: in all cases, rule2 OMITS the | 214 // BEFORE rule1 in the list: in all cases, rule2 OMITS the |
| 205 // material in the brackets and rule1 INCLUDES the material | 215 // material in the brackets and rule1 INCLUDES the material |
| 206 // in the brackets) | 216 // in the brackets) |
| 207 if (rule2 != NULL) { | 217 if (rule2 != NULL) { |
| 208 rules.add(rule2); | 218 if (rule2->baseValue >= kNoBase) { |
| 219 rules.add(rule2); |
| 220 } |
| 221 else { |
| 222 owner->setNonNumericalRule(rule2); |
| 223 } |
| 209 } | 224 } |
| 225 } |
| 226 if (rule1->baseValue >= kNoBase) { |
| 210 rules.add(rule1); | 227 rules.add(rule1); |
| 211 } | 228 } |
| 229 else { |
| 230 owner->setNonNumericalRule(rule1); |
| 231 } |
| 212 } | 232 } |
| 213 | 233 |
| 214 /** | 234 /** |
| 215 * This function parses the rule's rule descriptor (i.e., the base | 235 * This function parses the rule's rule descriptor (i.e., the base |
| 216 * value and/or other tokens that precede the rule's rule text | 236 * value and/or other tokens that precede the rule's rule text |
| 217 * in the description) and sets the rule's base value, radix, and | 237 * in the description) and sets the rule's base value, radix, and |
| 218 * exponent according to the descriptor. (If the description doesn't | 238 * exponent according to the descriptor. (If the description doesn't |
| 219 * include a rule descriptor, then this function sets everything to | 239 * include a rule descriptor, then this function sets everything to |
| 220 * default values and the rule set sets the rule's real base value). | 240 * default values and the rule set sets the rule's real base value). |
| 221 * @param description The rule's description | 241 * @param description The rule's description |
| 222 * @return If "description" included a rule descriptor, this is | 242 * @return If "description" included a rule descriptor, this is |
| 223 * "description" with the descriptor and any trailing whitespace | 243 * "description" with the descriptor and any trailing whitespace |
| 224 * stripped off. Otherwise; it's "descriptor" unchangd. | 244 * stripped off. Otherwise; it's "descriptor" unchangd. |
| 225 */ | 245 */ |
| 226 void | 246 void |
| 227 NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) | 247 NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) |
| 228 { | 248 { |
| 229 // the description consists of a rule descriptor and a rule body, | 249 // the description consists of a rule descriptor and a rule body, |
| 230 // separated by a colon. The rule descriptor is optional. If | 250 // separated by a colon. The rule descriptor is optional. If |
| 231 // it's omitted, just set the base value to 0. | 251 // it's omitted, just set the base value to 0. |
| 232 int32_t p = description.indexOf(gColon); | 252 int32_t p = description.indexOf(gColon); |
| 233 if (p == -1) { | 253 if (p != -1) { |
| 234 setBaseValue((int32_t)0, status); | |
| 235 } else { | |
| 236 // copy the descriptor out into its own string and strip it, | 254 // copy the descriptor out into its own string and strip it, |
| 237 // along with any trailing whitespace, out of the original | 255 // along with any trailing whitespace, out of the original |
| 238 // description | 256 // description |
| 239 UnicodeString descriptor; | 257 UnicodeString descriptor; |
| 240 descriptor.setTo(description, 0, p); | 258 descriptor.setTo(description, 0, p); |
| 241 | 259 |
| 242 ++p; | 260 ++p; |
| 243 while (p < description.length() && PatternProps::isWhiteSpace(descriptio
n.charAt(p))) { | 261 while (p < description.length() && PatternProps::isWhiteSpace(descriptio
n.charAt(p))) { |
| 244 ++p; | 262 ++p; |
| 245 } | 263 } |
| 246 description.removeBetween(0, p); | 264 description.removeBetween(0, p); |
| 247 | 265 |
| 248 // check first to see if the rule descriptor matches the token | 266 // check first to see if the rule descriptor matches the token |
| 249 // for one of the special rules. If it does, set the base | 267 // for one of the special rules. If it does, set the base |
| 250 // value to the correct identfier value | 268 // value to the correct identifier value |
| 251 if (0 == descriptor.compare(gMinusX, 2)) { | 269 int descriptorLength = descriptor.length(); |
| 252 setType(kNegativeNumberRule); | 270 UChar firstChar = descriptor.charAt(0); |
| 253 } | 271 UChar lastChar = descriptor.charAt(descriptorLength - 1); |
| 254 else if (0 == descriptor.compare(gXDotX, 3)) { | 272 if (firstChar >= gZero && firstChar <= gNine && lastChar != gX) { |
| 255 setType(kImproperFractionRule); | 273 // if the rule descriptor begins with a digit, it's a descriptor |
| 256 } | 274 // for a normal rule |
| 257 else if (0 == descriptor.compare(gZeroDotX, 3)) { | 275 // since we don't have Long.parseLong, and this isn't much work anyw
ay, |
| 258 setType(kProperFractionRule); | 276 // just build up the value as we encounter the digits. |
| 259 } | |
| 260 else if (0 == descriptor.compare(gXDotZero, 3)) { | |
| 261 setType(kMasterRule); | |
| 262 } | |
| 263 | |
| 264 // if the rule descriptor begins with a digit, it's a descriptor | |
| 265 // for a normal rule | |
| 266 // since we don't have Long.parseLong, and this isn't much work anyway, | |
| 267 // just build up the value as we encounter the digits. | |
| 268 else if (descriptor.charAt(0) >= gZero && descriptor.charAt(0) <= gNine)
{ | |
| 269 int64_t val = 0; | 277 int64_t val = 0; |
| 270 p = 0; | 278 p = 0; |
| 271 UChar c = gSpace; | 279 UChar c = gSpace; |
| 272 | 280 |
| 273 // begin parsing the descriptor: copy digits | 281 // begin parsing the descriptor: copy digits |
| 274 // into "tempValue", skip periods, commas, and spaces, | 282 // into "tempValue", skip periods, commas, and spaces, |
| 275 // stop on a slash or > sign (or at the end of the string), | 283 // stop on a slash or > sign (or at the end of the string), |
| 276 // and throw an exception on any other character | 284 // and throw an exception on any other character |
| 277 int64_t ll_10 = 10; | 285 int64_t ll_10 = 10; |
| 278 while (p < descriptor.length()) { | 286 while (p < descriptorLength) { |
| 279 c = descriptor.charAt(p); | 287 c = descriptor.charAt(p); |
| 280 if (c >= gZero && c <= gNine) { | 288 if (c >= gZero && c <= gNine) { |
| 281 val = val * ll_10 + (int32_t)(c - gZero); | 289 val = val * ll_10 + (int32_t)(c - gZero); |
| 282 } | 290 } |
| 283 else if (c == gSlash || c == gGreaterThan) { | 291 else if (c == gSlash || c == gGreaterThan) { |
| 284 break; | 292 break; |
| 285 } | 293 } |
| 286 else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gD
ot) { | 294 else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gD
ot) { |
| 287 } | 295 } |
| 288 else { | 296 else { |
| 289 // throw new IllegalArgumentException("Illegal character in
rule descriptor"); | 297 // throw new IllegalArgumentException("Illegal character in
rule descriptor"); |
| 290 status = U_PARSE_ERROR; | 298 status = U_PARSE_ERROR; |
| 291 return; | 299 return; |
| 292 } | 300 } |
| 293 ++p; | 301 ++p; |
| 294 } | 302 } |
| 295 | 303 |
| 296 // we have the base value, so set it | 304 // we have the base value, so set it |
| 297 setBaseValue(val, status); | 305 setBaseValue(val, status); |
| 298 | 306 |
| 299 // if we stopped the previous loop on a slash, we're | 307 // if we stopped the previous loop on a slash, we're |
| 300 // now parsing the rule's radix. Again, accumulate digits | 308 // now parsing the rule's radix. Again, accumulate digits |
| 301 // in tempValue, skip punctuation, stop on a > mark, and | 309 // in tempValue, skip punctuation, stop on a > mark, and |
| 302 // throw an exception on anything else | 310 // throw an exception on anything else |
| 303 if (c == gSlash) { | 311 if (c == gSlash) { |
| 304 val = 0; | 312 val = 0; |
| 305 ++p; | 313 ++p; |
| 306 int64_t ll_10 = 10; | 314 int64_t ll_10 = 10; |
| 307 while (p < descriptor.length()) { | 315 while (p < descriptorLength) { |
| 308 c = descriptor.charAt(p); | 316 c = descriptor.charAt(p); |
| 309 if (c >= gZero && c <= gNine) { | 317 if (c >= gZero && c <= gNine) { |
| 310 val = val * ll_10 + (int32_t)(c - gZero); | 318 val = val * ll_10 + (int32_t)(c - gZero); |
| 311 } | 319 } |
| 312 else if (c == gGreaterThan) { | 320 else if (c == gGreaterThan) { |
| 313 break; | 321 break; |
| 314 } | 322 } |
| 315 else if (PatternProps::isWhiteSpace(c) || c == gComma || c =
= gDot) { | 323 else if (PatternProps::isWhiteSpace(c) || c == gComma || c =
= gDot) { |
| 316 } | 324 } |
| 317 else { | 325 else { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 345 --exponent; | 353 --exponent; |
| 346 } else { | 354 } else { |
| 347 // throw new IllegalArgumentException("Illegal character
in rule descriptor"); | 355 // throw new IllegalArgumentException("Illegal character
in rule descriptor"); |
| 348 status = U_PARSE_ERROR; | 356 status = U_PARSE_ERROR; |
| 349 return; | 357 return; |
| 350 } | 358 } |
| 351 ++p; | 359 ++p; |
| 352 } | 360 } |
| 353 } | 361 } |
| 354 } | 362 } |
| 363 else if (0 == descriptor.compare(gMinusX, 2)) { |
| 364 setType(kNegativeNumberRule); |
| 365 } |
| 366 else if (descriptorLength == 3) { |
| 367 if (firstChar == gZero && lastChar == gX) { |
| 368 setBaseValue(kProperFractionRule, status); |
| 369 decimalPoint = descriptor.charAt(1); |
| 370 } |
| 371 else if (firstChar == gX && lastChar == gX) { |
| 372 setBaseValue(kImproperFractionRule, status); |
| 373 decimalPoint = descriptor.charAt(1); |
| 374 } |
| 375 else if (firstChar == gX && lastChar == gZero) { |
| 376 setBaseValue(kMasterRule, status); |
| 377 decimalPoint = descriptor.charAt(1); |
| 378 } |
| 379 else if (descriptor.compare(gNaN, 3) == 0) { |
| 380 setBaseValue(kNaNRule, status); |
| 381 } |
| 382 else if (descriptor.compare(gInf, 3) == 0) { |
| 383 setBaseValue(kInfinityRule, status); |
| 384 } |
| 385 } |
| 355 } | 386 } |
| 387 // else use the default base value for now. |
| 356 | 388 |
| 357 // finally, if the rule body begins with an apostrophe, strip it off | 389 // finally, if the rule body begins with an apostrophe, strip it off |
| 358 // (this is generally used to put whitespace at the beginning of | 390 // (this is generally used to put whitespace at the beginning of |
| 359 // a rule's rule text) | 391 // a rule's rule text) |
| 360 if (description.length() > 0 && description.charAt(0) == gTick) { | 392 if (description.length() > 0 && description.charAt(0) == gTick) { |
| 361 description.removeBetween(0, 1); | 393 description.removeBetween(0, 1); |
| 362 } | 394 } |
| 363 | 395 |
| 364 // return the description with all the stuff we've just waded through | 396 // return the description with all the stuff we've just waded through |
| 365 // stripped off the front. It now contains just the rule body. | 397 // stripped off the front. It now contains just the rule body. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 377 void | 409 void |
| 378 NFRule::extractSubstitutions(const NFRuleSet* ruleSet, | 410 NFRule::extractSubstitutions(const NFRuleSet* ruleSet, |
| 379 const UnicodeString &ruleText, | 411 const UnicodeString &ruleText, |
| 380 const NFRule* predecessor, | 412 const NFRule* predecessor, |
| 381 UErrorCode& status) | 413 UErrorCode& status) |
| 382 { | 414 { |
| 383 if (U_FAILURE(status)) { | 415 if (U_FAILURE(status)) { |
| 384 return; | 416 return; |
| 385 } | 417 } |
| 386 this->ruleText = ruleText; | 418 this->ruleText = ruleText; |
| 387 this->rulePatternFormat = NULL; | |
| 388 sub1 = extractSubstitution(ruleSet, predecessor, status); | 419 sub1 = extractSubstitution(ruleSet, predecessor, status); |
| 389 if (sub1 == NULL || sub1->isNullSubstitution()) { | 420 if (sub1 == NULL) { |
| 390 // Small optimization. There is no need to create a redundant NullSubsti
tution. | 421 // Small optimization. There is no need to create a redundant NullSubsti
tution. |
| 391 sub2 = sub1; | 422 sub2 = NULL; |
| 392 } | 423 } |
| 393 else { | 424 else { |
| 394 sub2 = extractSubstitution(ruleSet, predecessor, status); | 425 sub2 = extractSubstitution(ruleSet, predecessor, status); |
| 395 } | 426 } |
| 396 int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1,
0); | 427 int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1,
0); |
| 397 int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClos
edParenthesisDollar, -1, pluralRuleStart) : -1); | 428 int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClos
edParenthesisDollar, -1, pluralRuleStart) : -1); |
| 398 if (pluralRuleEnd >= 0) { | 429 if (pluralRuleEnd >= 0) { |
| 399 int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart); | 430 int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart); |
| 400 if (endType < 0) { | 431 if (endType < 0) { |
| 401 status = U_PARSE_ERROR; | 432 status = U_PARSE_ERROR; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 432 */ | 463 */ |
| 433 NFSubstitution * | 464 NFSubstitution * |
| 434 NFRule::extractSubstitution(const NFRuleSet* ruleSet, | 465 NFRule::extractSubstitution(const NFRuleSet* ruleSet, |
| 435 const NFRule* predecessor, | 466 const NFRule* predecessor, |
| 436 UErrorCode& status) | 467 UErrorCode& status) |
| 437 { | 468 { |
| 438 NFSubstitution* result = NULL; | 469 NFSubstitution* result = NULL; |
| 439 | 470 |
| 440 // search the rule's rule text for the first two characters of | 471 // search the rule's rule text for the first two characters of |
| 441 // a substitution token | 472 // a substitution token |
| 442 int32_t subStart = indexOfAny(tokenStrings); | 473 int32_t subStart = indexOfAnyRulePrefix(); |
| 443 int32_t subEnd = subStart; | 474 int32_t subEnd = subStart; |
| 444 | 475 |
| 445 // if we didn't find one, create a null substitution positioned | 476 // if we didn't find one, create a null substitution positioned |
| 446 // at the end of the rule text | 477 // at the end of the rule text |
| 447 if (subStart == -1) { | 478 if (subStart == -1) { |
| 448 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece
ssor, | 479 return NULL; |
| 449 ruleSet, this->formatter, UnicodeString(), status); | |
| 450 } | 480 } |
| 451 | 481 |
| 452 // special-case the ">>>" token, since searching for the > at the | 482 // special-case the ">>>" token, since searching for the > at the |
| 453 // end will actually find the > in the middle | 483 // end will actually find the > in the middle |
| 454 if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { | 484 if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { |
| 455 subEnd = subStart + 2; | 485 subEnd = subStart + 2; |
| 456 | 486 |
| 457 // otherwise the substitution token ends with the same character | 487 // otherwise the substitution token ends with the same character |
| 458 // it began with | 488 // it began with |
| 459 } else { | 489 } else { |
| 460 UChar c = ruleText.charAt(subStart); | 490 UChar c = ruleText.charAt(subStart); |
| 461 subEnd = ruleText.indexOf(c, subStart + 1); | 491 subEnd = ruleText.indexOf(c, subStart + 1); |
| 462 // special case for '<%foo<<' | 492 // special case for '<%foo<<' |
| 463 if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 &&
ruleText.charAt(subEnd+1) == c) { | 493 if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 &&
ruleText.charAt(subEnd+1) == c) { |
| 464 // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '
==' in the middle | 494 // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '
==' in the middle |
| 465 // occurs because of the juxtaposition of two different rules. The
check for '<' is a hack | 495 // occurs because of the juxtaposition of two different rules. The
check for '<' is a hack |
| 466 // to get around this. Having the duplicate at the front would caus
e problems with | 496 // to get around this. Having the duplicate at the front would caus
e problems with |
| 467 // rules like "<<%" to format, say, percents... | 497 // rules like "<<%" to format, say, percents... |
| 468 ++subEnd; | 498 ++subEnd; |
| 469 } | 499 } |
| 470 } | 500 } |
| 471 | 501 |
| 472 // if we don't find the end of the token (i.e., if we're on a single, | 502 // if we don't find the end of the token (i.e., if we're on a single, |
| 473 // unmatched token character), create a null substitution positioned | 503 // unmatched token character), create a null substitution positioned |
| 474 // at the end of the rule | 504 // at the end of the rule |
| 475 if (subEnd == -1) { | 505 if (subEnd == -1) { |
| 476 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece
ssor, | 506 return NULL; |
| 477 ruleSet, this->formatter, UnicodeString(), status); | |
| 478 } | 507 } |
| 479 | 508 |
| 480 // if we get here, we have a real substitution token (or at least | 509 // if we get here, we have a real substitution token (or at least |
| 481 // some text bounded by substitution token characters). Use | 510 // some text bounded by substitution token characters). Use |
| 482 // makeSubstitution() to create the right kind of substitution | 511 // makeSubstitution() to create the right kind of substitution |
| 483 UnicodeString subToken; | 512 UnicodeString subToken; |
| 484 subToken.setTo(ruleText, subStart, subEnd + 1 - subStart); | 513 subToken.setTo(ruleText, subStart, subEnd + 1 - subStart); |
| 485 result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleS
et, | 514 result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleS
et, |
| 486 this->formatter, subToken, status); | 515 this->formatter, subToken, status); |
| 487 | 516 |
| 488 // remove the substitution from the rule text | 517 // remove the substitution from the rule text |
| 489 ruleText.removeBetween(subStart, subEnd+1); | 518 ruleText.removeBetween(subStart, subEnd+1); |
| 490 | 519 |
| 491 return result; | 520 return result; |
| 492 } | 521 } |
| 493 | 522 |
| 494 /** | 523 /** |
| 495 * Sets the rule's base value, and causes the radix and exponent | 524 * Sets the rule's base value, and causes the radix and exponent |
| 496 * to be recalculated. This is used during construction when we | 525 * to be recalculated. This is used during construction when we |
| 497 * don't know the rule's base value until after it's been | 526 * don't know the rule's base value until after it's been |
| 498 * constructed. It should be used at any other time. | 527 * constructed. It should be used at any other time. |
| 499 * @param The new base value for the rule. | 528 * @param The new base value for the rule. |
| 500 */ | 529 */ |
| 501 void | 530 void |
| 502 NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status) | 531 NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status) |
| 503 { | 532 { |
| 504 // set the base value | 533 // set the base value |
| 505 baseValue = newBaseValue; | 534 baseValue = newBaseValue; |
| 535 radix = 10; |
| 506 | 536 |
| 507 // if this isn't a special rule, recalculate the radix and exponent | 537 // if this isn't a special rule, recalculate the radix and exponent |
| 508 // (the radix always defaults to 10; if it's supposed to be something | 538 // (the radix always defaults to 10; if it's supposed to be something |
| 509 // else, it's cleaned up by the caller and the exponent is | 539 // else, it's cleaned up by the caller and the exponent is |
| 510 // recalculated again-- the only function that does this is | 540 // recalculated again-- the only function that does this is |
| 511 // NFRule.parseRuleDescriptor() ) | 541 // NFRule.parseRuleDescriptor() ) |
| 512 if (baseValue >= 1) { | 542 if (baseValue >= 1) { |
| 513 radix = 10; | |
| 514 exponent = expectedExponent(); | 543 exponent = expectedExponent(); |
| 515 | 544 |
| 516 // this function gets called on a fully-constructed rule whose | 545 // this function gets called on a fully-constructed rule whose |
| 517 // description didn't specify a base value. This means it | 546 // description didn't specify a base value. This means it |
| 518 // has substitutions, and some substitutions hold on to copies | 547 // has substitutions, and some substitutions hold on to copies |
| 519 // of the rule's divisor. Fix their copies of the divisor. | 548 // of the rule's divisor. Fix their copies of the divisor. |
| 520 if (sub1 != NULL) { | 549 if (sub1 != NULL) { |
| 521 sub1->setDivisor(radix, exponent, status); | 550 sub1->setDivisor(radix, exponent, status); |
| 522 } | 551 } |
| 523 if (sub2 != NULL) { | 552 if (sub2 != NULL) { |
| 524 sub2->setDivisor(radix, exponent, status); | 553 sub2->setDivisor(radix, exponent, status); |
| 525 } | 554 } |
| 526 | 555 |
| 527 // if this is a special rule, its radix and exponent are basically | 556 // if this is a special rule, its radix and exponent are basically |
| 528 // ignored. Set them to "safe" default values | 557 // ignored. Set them to "safe" default values |
| 529 } else { | 558 } else { |
| 530 radix = 10; | |
| 531 exponent = 0; | 559 exponent = 0; |
| 532 } | 560 } |
| 533 } | 561 } |
| 534 | 562 |
| 535 /** | 563 /** |
| 536 * This calculates the rule's exponent based on its radix and base | 564 * This calculates the rule's exponent based on its radix and base |
| 537 * value. This will be the highest power the radix can be raised to | 565 * value. This will be the highest power the radix can be raised to |
| 538 * and still produce a result less than or equal to the base value. | 566 * and still produce a result less than or equal to the base value. |
| 539 */ | 567 */ |
| 540 int16_t | 568 int16_t |
| (...skipping 12 matching lines...) Expand all Loading... |
| 553 int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((doubl
e)radix)); | 581 int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((doubl
e)radix)); |
| 554 int64_t temp = util64_pow(radix, tempResult + 1); | 582 int64_t temp = util64_pow(radix, tempResult + 1); |
| 555 if (temp <= baseValue) { | 583 if (temp <= baseValue) { |
| 556 tempResult += 1; | 584 tempResult += 1; |
| 557 } | 585 } |
| 558 return tempResult; | 586 return tempResult; |
| 559 } | 587 } |
| 560 | 588 |
| 561 /** | 589 /** |
| 562 * Searches the rule's rule text for any of the specified strings. | 590 * Searches the rule's rule text for any of the specified strings. |
| 563 * @param strings An array of strings to search the rule's rule | |
| 564 * text for | |
| 565 * @return The index of the first match in the rule's rule text | 591 * @return The index of the first match in the rule's rule text |
| 566 * (i.e., the first substring in the rule's rule text that matches | 592 * (i.e., the first substring in the rule's rule text that matches |
| 567 * _any_ of the strings in "strings"). If none of the strings in | 593 * _any_ of the strings in "strings"). If none of the strings in |
| 568 * "strings" is found in the rule's rule text, returns -1. | 594 * "strings" is found in the rule's rule text, returns -1. |
| 569 */ | 595 */ |
| 570 int32_t | 596 int32_t |
| 571 NFRule::indexOfAny(const UChar* const strings[]) const | 597 NFRule::indexOfAnyRulePrefix() const |
| 572 { | 598 { |
| 573 int result = -1; | 599 int result = -1; |
| 574 for (int i = 0; strings[i]; i++) { | 600 for (int i = 0; RULE_PREFIXES[i]; i++) { |
| 575 int32_t pos = ruleText.indexOf(*strings[i]); | 601 int32_t pos = ruleText.indexOf(*RULE_PREFIXES[i]); |
| 576 if (pos != -1 && (result == -1 || pos < result)) { | 602 if (pos != -1 && (result == -1 || pos < result)) { |
| 577 result = pos; | 603 result = pos; |
| 578 } | 604 } |
| 579 } | 605 } |
| 580 return result; | 606 return result; |
| 581 } | 607 } |
| 582 | 608 |
| 583 //----------------------------------------------------------------------- | 609 //----------------------------------------------------------------------- |
| 584 // boilerplate | 610 // boilerplate |
| 585 //----------------------------------------------------------------------- | 611 //----------------------------------------------------------------------- |
| 586 | 612 |
| 613 static UBool |
| 614 util_equalSubstitutions(const NFSubstitution* sub1, const NFSubstitution* sub2) |
| 615 { |
| 616 if (sub1) { |
| 617 if (sub2) { |
| 618 return *sub1 == *sub2; |
| 619 } |
| 620 } else if (!sub2) { |
| 621 return TRUE; |
| 622 } |
| 623 return FALSE; |
| 624 } |
| 625 |
| 587 /** | 626 /** |
| 588 * Tests two rules for equality. | 627 * Tests two rules for equality. |
| 589 * @param that The rule to compare this one against | 628 * @param that The rule to compare this one against |
| 590 * @return True is the two rules are functionally equivalent | 629 * @return True is the two rules are functionally equivalent |
| 591 */ | 630 */ |
| 592 UBool | 631 UBool |
| 593 NFRule::operator==(const NFRule& rhs) const | 632 NFRule::operator==(const NFRule& rhs) const |
| 594 { | 633 { |
| 595 return baseValue == rhs.baseValue | 634 return baseValue == rhs.baseValue |
| 596 && radix == rhs.radix | 635 && radix == rhs.radix |
| 597 && exponent == rhs.exponent | 636 && exponent == rhs.exponent |
| 598 && ruleText == rhs.ruleText | 637 && ruleText == rhs.ruleText |
| 599 && *sub1 == *rhs.sub1 | 638 && util_equalSubstitutions(sub1, rhs.sub1) |
| 600 && *sub2 == *rhs.sub2; | 639 && util_equalSubstitutions(sub2, rhs.sub2); |
| 601 } | 640 } |
| 602 | 641 |
| 603 /** | 642 /** |
| 604 * Returns a textual representation of the rule. This won't | 643 * Returns a textual representation of the rule. This won't |
| 605 * necessarily be the same as the description that this rule | 644 * necessarily be the same as the description that this rule |
| 606 * was created with, but it will produce the same result. | 645 * was created with, but it will produce the same result. |
| 607 * @return A textual description of the rule | 646 * @return A textual description of the rule |
| 608 */ | 647 */ |
| 609 static void util_append64(UnicodeString& result, int64_t n) | 648 static void util_append64(UnicodeString& result, int64_t n) |
| 610 { | 649 { |
| 611 UChar buffer[256]; | 650 UChar buffer[256]; |
| 612 int32_t len = util64_tou(n, buffer, sizeof(buffer)); | 651 int32_t len = util64_tou(n, buffer, sizeof(buffer)); |
| 613 UnicodeString temp(buffer, len); | 652 UnicodeString temp(buffer, len); |
| 614 result.append(temp); | 653 result.append(temp); |
| 615 } | 654 } |
| 616 | 655 |
| 617 void | 656 void |
| 618 NFRule::_appendRuleText(UnicodeString& result) const | 657 NFRule::_appendRuleText(UnicodeString& result) const |
| 619 { | 658 { |
| 620 switch (getType()) { | 659 switch (getType()) { |
| 621 case kNegativeNumberRule: result.append(gMinusX, 2); break; | 660 case kNegativeNumberRule: result.append(gMinusX, 2); break; |
| 622 case kImproperFractionRule: result.append(gXDotX, 3); break; | 661 case kImproperFractionRule: result.append(gX).append(decimalPoint == 0 ? gDo
t : decimalPoint).append(gX); break; |
| 623 case kProperFractionRule: result.append(gZeroDotX, 3); break; | 662 case kProperFractionRule: result.append(gZero).append(decimalPoint == 0 ? gD
ot : decimalPoint).append(gX); break; |
| 624 case kMasterRule: result.append(gXDotZero, 3); break; | 663 case kMasterRule: result.append(gX).append(decimalPoint == 0 ? gDot : decima
lPoint).append(gZero); break; |
| 664 case kInfinityRule: result.append(gInf, 3); break; |
| 665 case kNaNRule: result.append(gNaN, 3); break; |
| 625 default: | 666 default: |
| 626 // for a normal rule, write out its base value, and if the radix is | 667 // for a normal rule, write out its base value, and if the radix is |
| 627 // something other than 10, write out the radix (with the preceding | 668 // something other than 10, write out the radix (with the preceding |
| 628 // slash, of course). Then calculate the expected exponent and if | 669 // slash, of course). Then calculate the expected exponent and if |
| 629 // if isn't the same as the actual exponent, write an appropriate | 670 // if isn't the same as the actual exponent, write an appropriate |
| 630 // number of > signs. Finally, terminate the whole thing with | 671 // number of > signs. Finally, terminate the whole thing with |
| 631 // a colon. | 672 // a colon. |
| 632 util_append64(result, baseValue); | 673 util_append64(result, baseValue); |
| 633 if (radix != 10) { | 674 if (radix != 10) { |
| 634 result.append(gSlash); | 675 result.append(gSlash); |
| 635 util_append64(result, radix); | 676 util_append64(result, radix); |
| 636 } | 677 } |
| 637 int numCarets = expectedExponent() - exponent; | 678 int numCarets = expectedExponent() - exponent; |
| 638 for (int i = 0; i < numCarets; i++) { | 679 for (int i = 0; i < numCarets; i++) { |
| 639 result.append(gGreaterThan); | 680 result.append(gGreaterThan); |
| 640 } | 681 } |
| 641 break; | 682 break; |
| 642 } | 683 } |
| 643 result.append(gColon); | 684 result.append(gColon); |
| 644 result.append(gSpace); | 685 result.append(gSpace); |
| 645 | 686 |
| 646 // if the rule text begins with a space, write an apostrophe | 687 // if the rule text begins with a space, write an apostrophe |
| 647 // (whitespace after the rule descriptor is ignored; the | 688 // (whitespace after the rule descriptor is ignored; the |
| 648 // apostrophe is used to make the whitespace significant) | 689 // apostrophe is used to make the whitespace significant) |
| 649 if (ruleText.charAt(0) == gSpace && sub1->getPos() != 0) { | 690 if (ruleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) { |
| 650 result.append(gTick); | 691 result.append(gTick); |
| 651 } | 692 } |
| 652 | 693 |
| 653 // now, write the rule's rule text, inserting appropriate | 694 // now, write the rule's rule text, inserting appropriate |
| 654 // substitution tokens in the appropriate places | 695 // substitution tokens in the appropriate places |
| 655 UnicodeString ruleTextCopy; | 696 UnicodeString ruleTextCopy; |
| 656 ruleTextCopy.setTo(ruleText); | 697 ruleTextCopy.setTo(ruleText); |
| 657 | 698 |
| 658 UnicodeString temp; | 699 UnicodeString temp; |
| 659 sub2->toString(temp); | 700 if (sub2 != NULL) { |
| 660 ruleTextCopy.insert(sub2->getPos(), temp); | 701 sub2->toString(temp); |
| 661 sub1->toString(temp); | 702 ruleTextCopy.insert(sub2->getPos(), temp); |
| 662 ruleTextCopy.insert(sub1->getPos(), temp); | 703 } |
| 704 if (sub1 != NULL) { |
| 705 sub1->toString(temp); |
| 706 ruleTextCopy.insert(sub1->getPos(), temp); |
| 707 } |
| 663 | 708 |
| 664 result.append(ruleTextCopy); | 709 result.append(ruleTextCopy); |
| 665 | 710 |
| 666 // and finally, top the whole thing off with a semicolon and | 711 // and finally, top the whole thing off with a semicolon and |
| 667 // return the result | 712 // return the result |
| 668 result.append(gSemicolon); | 713 result.append(gSemicolon); |
| 669 } | 714 } |
| 670 | 715 |
| 671 //----------------------------------------------------------------------- | 716 //----------------------------------------------------------------------- |
| 672 // formatting | 717 // formatting |
| 673 //----------------------------------------------------------------------- | 718 //----------------------------------------------------------------------- |
| 674 | 719 |
| 675 /** | 720 /** |
| 676 * Formats the number, and inserts the resulting text into | 721 * Formats the number, and inserts the resulting text into |
| 677 * toInsertInto. | 722 * toInsertInto. |
| 678 * @param number The number being formatted | 723 * @param number The number being formatted |
| 679 * @param toInsertInto The string where the resultant text should | 724 * @param toInsertInto The string where the resultant text should |
| 680 * be inserted | 725 * be inserted |
| 681 * @param pos The position in toInsertInto where the resultant text | 726 * @param pos The position in toInsertInto where the resultant text |
| 682 * should be inserted | 727 * should be inserted |
| 683 */ | 728 */ |
| 684 void | 729 void |
| 685 NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErro
rCode& status) const | 730 NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32
_t recursionCount, UErrorCode& status) const |
| 686 { | 731 { |
| 687 // first, insert the rule's rule text into toInsertInto at the | 732 // first, insert the rule's rule text into toInsertInto at the |
| 688 // specified position, then insert the results of the substitutions | 733 // specified position, then insert the results of the substitutions |
| 689 // into the right places in toInsertInto (notice we do the | 734 // into the right places in toInsertInto (notice we do the |
| 690 // substitutions in reverse order so that the offsets don't get | 735 // substitutions in reverse order so that the offsets don't get |
| 691 // messed up) | 736 // messed up) |
| 692 int32_t pluralRuleStart = ruleText.length(); | 737 int32_t pluralRuleStart = ruleText.length(); |
| 693 int32_t lengthOffset = 0; | 738 int32_t lengthOffset = 0; |
| 694 if (!rulePatternFormat) { | 739 if (!rulePatternFormat) { |
| 695 toInsertInto.insert(pos, ruleText); | 740 toInsertInto.insert(pos, ruleText); |
| 696 } | 741 } |
| 697 else { | 742 else { |
| 698 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); | 743 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); |
| 699 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura
lRuleStart); | 744 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura
lRuleStart); |
| 700 int initialLength = toInsertInto.length(); | 745 int initialLength = toInsertInto.length(); |
| 701 if (pluralRuleEnd < ruleText.length() - 1) { | 746 if (pluralRuleEnd < ruleText.length() - 1) { |
| 702 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); | 747 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); |
| 703 } | 748 } |
| 704 toInsertInto.insert(pos, | 749 toInsertInto.insert(pos, |
| 705 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)
), status)); | 750 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)
), status)); |
| 706 if (pluralRuleStart > 0) { | 751 if (pluralRuleStart > 0) { |
| 707 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart))
; | 752 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart))
; |
| 708 } | 753 } |
| 709 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt
h); | 754 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt
h); |
| 710 } | 755 } |
| 711 | 756 |
| 712 if (!sub2->isNullSubstitution()) { | 757 if (sub2 != NULL) { |
| 713 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura
lRuleStart ? lengthOffset : 0), status); | 758 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura
lRuleStart ? lengthOffset : 0), recursionCount, status); |
| 714 } | 759 } |
| 715 if (!sub1->isNullSubstitution()) { | 760 if (sub1 != NULL) { |
| 716 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura
lRuleStart ? lengthOffset : 0), status); | 761 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura
lRuleStart ? lengthOffset : 0), recursionCount, status); |
| 717 } | 762 } |
| 718 } | 763 } |
| 719 | 764 |
| 720 /** | 765 /** |
| 721 * Formats the number, and inserts the resulting text into | 766 * Formats the number, and inserts the resulting text into |
| 722 * toInsertInto. | 767 * toInsertInto. |
| 723 * @param number The number being formatted | 768 * @param number The number being formatted |
| 724 * @param toInsertInto The string where the resultant text should | 769 * @param toInsertInto The string where the resultant text should |
| 725 * be inserted | 770 * be inserted |
| 726 * @param pos The position in toInsertInto where the resultant text | 771 * @param pos The position in toInsertInto where the resultant text |
| 727 * should be inserted | 772 * should be inserted |
| 728 */ | 773 */ |
| 729 void | 774 void |
| 730 NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, UError
Code& status) const | 775 NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_
t recursionCount, UErrorCode& status) const |
| 731 { | 776 { |
| 732 // first, insert the rule's rule text into toInsertInto at the | 777 // first, insert the rule's rule text into toInsertInto at the |
| 733 // specified position, then insert the results of the substitutions | 778 // specified position, then insert the results of the substitutions |
| 734 // into the right places in toInsertInto | 779 // into the right places in toInsertInto |
| 735 // [again, we have two copies of this routine that do the same thing | 780 // [again, we have two copies of this routine that do the same thing |
| 736 // so that we don't sacrifice precision in a long by casting it | 781 // so that we don't sacrifice precision in a long by casting it |
| 737 // to a double] | 782 // to a double] |
| 738 int32_t pluralRuleStart = ruleText.length(); | 783 int32_t pluralRuleStart = ruleText.length(); |
| 739 int32_t lengthOffset = 0; | 784 int32_t lengthOffset = 0; |
| 740 if (!rulePatternFormat) { | 785 if (!rulePatternFormat) { |
| 741 toInsertInto.insert(pos, ruleText); | 786 toInsertInto.insert(pos, ruleText); |
| 742 } | 787 } |
| 743 else { | 788 else { |
| 744 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); | 789 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); |
| 745 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura
lRuleStart); | 790 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura
lRuleStart); |
| 746 int initialLength = toInsertInto.length(); | 791 int initialLength = toInsertInto.length(); |
| 747 if (pluralRuleEnd < ruleText.length() - 1) { | 792 if (pluralRuleEnd < ruleText.length() - 1) { |
| 748 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); | 793 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); |
| 749 } | 794 } |
| 750 toInsertInto.insert(pos, | 795 double pluralVal = number; |
| 751 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)
), status)); | 796 if (0 <= pluralVal && pluralVal < 1) { |
| 797 // We're in a fractional rule, and we have to match the NumeratorSub
stitution behavior. |
| 798 // 2.3 can become 0.2999999999999998 for the fraction due to roundin
g errors. |
| 799 pluralVal = uprv_round(pluralVal * uprv_pow(radix, exponent)); |
| 800 } |
| 801 else { |
| 802 pluralVal = pluralVal / uprv_pow(radix, exponent); |
| 803 } |
| 804 toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal),
status)); |
| 752 if (pluralRuleStart > 0) { | 805 if (pluralRuleStart > 0) { |
| 753 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart))
; | 806 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart))
; |
| 754 } | 807 } |
| 755 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt
h); | 808 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt
h); |
| 756 } | 809 } |
| 757 | 810 |
| 758 if (!sub2->isNullSubstitution()) { | 811 if (sub2 != NULL) { |
| 759 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura
lRuleStart ? lengthOffset : 0), status); | 812 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura
lRuleStart ? lengthOffset : 0), recursionCount, status); |
| 760 } | 813 } |
| 761 if (!sub1->isNullSubstitution()) { | 814 if (sub1 != NULL) { |
| 762 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura
lRuleStart ? lengthOffset : 0), status); | 815 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura
lRuleStart ? lengthOffset : 0), recursionCount, status); |
| 763 } | 816 } |
| 764 } | 817 } |
| 765 | 818 |
| 766 /** | 819 /** |
| 767 * Used by the owning rule set to determine whether to invoke the | 820 * Used by the owning rule set to determine whether to invoke the |
| 768 * rollback rule (i.e., whether this rule or the one that precedes | 821 * rollback rule (i.e., whether this rule or the one that precedes |
| 769 * it in the rule set's list should be used to format the number) | 822 * it in the rule set's list should be used to format the number) |
| 770 * @param The number being formatted | 823 * @param The number being formatted |
| 771 * @return True if the rule set should use the rule that precedes | 824 * @return True if the rule set should use the rule that precedes |
| 772 * this one in its list; false if it should use this rule | 825 * this one in its list; false if it should use this rule |
| (...skipping 10 matching lines...) Expand all Loading... |
| 783 // that expands into | 836 // that expands into |
| 784 // 100: << hundred; | 837 // 100: << hundred; |
| 785 // 101: << hundred >>; | 838 // 101: << hundred >>; |
| 786 // internally. But when we're formatting 200, if we use the rule | 839 // internally. But when we're formatting 200, if we use the rule |
| 787 // at 101, which would normally apply, we get "two hundred zero". | 840 // at 101, which would normally apply, we get "two hundred zero". |
| 788 // To prevent this, we roll back and use the rule at 100 instead. | 841 // To prevent this, we roll back and use the rule at 100 instead. |
| 789 // This is the logic that makes this happen: the rule at 101 has | 842 // This is the logic that makes this happen: the rule at 101 has |
| 790 // a modulus substitution, its base value isn't an even multiple | 843 // a modulus substitution, its base value isn't an even multiple |
| 791 // of 100, and the value we're trying to format _is_ an even | 844 // of 100, and the value we're trying to format _is_ an even |
| 792 // multiple of 100. This is called the "rollback rule." | 845 // multiple of 100. This is called the "rollback rule." |
| 793 if ((sub1->isModulusSubstitution()) || (sub2->isModulusSubstitution())) { | 846 if ((sub1 != NULL && sub1->isModulusSubstitution()) || (sub2 != NULL && sub2
->isModulusSubstitution())) { |
| 794 int64_t re = util64_pow(radix, exponent); | 847 int64_t re = util64_pow(radix, exponent); |
| 795 return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0; | 848 return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0; |
| 796 } | 849 } |
| 797 return FALSE; | 850 return FALSE; |
| 798 } | 851 } |
| 799 | 852 |
| 800 //----------------------------------------------------------------------- | 853 //----------------------------------------------------------------------- |
| 801 // parsing | 854 // parsing |
| 802 //----------------------------------------------------------------------- | 855 //----------------------------------------------------------------------- |
| 803 | 856 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 826 int len = us.length(); | 879 int len = us.length(); |
| 827 char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1]; | 880 char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1]; |
| 828 if (buf != NULL) { | 881 if (buf != NULL) { |
| 829 us.extract(0, len, buf); | 882 us.extract(0, len, buf); |
| 830 buf[len] = 0; | 883 buf[len] = 0; |
| 831 fprintf(f, "%s", buf); | 884 fprintf(f, "%s", buf); |
| 832 uprv_free(buf); //delete[] buf; | 885 uprv_free(buf); //delete[] buf; |
| 833 } | 886 } |
| 834 } | 887 } |
| 835 #endif | 888 #endif |
| 836 | |
| 837 UBool | 889 UBool |
| 838 NFRule::doParse(const UnicodeString& text, | 890 NFRule::doParse(const UnicodeString& text, |
| 839 ParsePosition& parsePosition, | 891 ParsePosition& parsePosition, |
| 840 UBool isFractionRule, | 892 UBool isFractionRule, |
| 841 double upperBound, | 893 double upperBound, |
| 842 Formattable& resVal) const | 894 Formattable& resVal) const |
| 843 { | 895 { |
| 844 // internally we operate on a copy of the string being parsed | 896 // internally we operate on a copy of the string being parsed |
| 845 // (because we're going to change it) and use our own ParsePosition | 897 // (because we're going to change it) and use our own ParsePosition |
| 846 ParsePosition pp; | 898 ParsePosition pp; |
| 847 UnicodeString workText(text); | 899 UnicodeString workText(text); |
| 848 | 900 |
| 901 int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : ruleText.length(); |
| 902 int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : ruleText.length(); |
| 903 |
| 849 // check to see whether the text before the first substitution | 904 // check to see whether the text before the first substitution |
| 850 // matches the text at the beginning of the string being | 905 // matches the text at the beginning of the string being |
| 851 // parsed. If it does, strip that off the front of workText; | 906 // parsed. If it does, strip that off the front of workText; |
| 852 // otherwise, dump out with a mismatch | 907 // otherwise, dump out with a mismatch |
| 853 UnicodeString prefix; | 908 UnicodeString prefix; |
| 854 prefix.setTo(ruleText, 0, sub1->getPos()); | 909 prefix.setTo(ruleText, 0, sub1Pos); |
| 855 | 910 |
| 856 #ifdef RBNF_DEBUG | 911 #ifdef RBNF_DEBUG |
| 857 fprintf(stderr, "doParse %x ", this); | 912 fprintf(stderr, "doParse %p ", this); |
| 858 { | 913 { |
| 859 UnicodeString rt; | 914 UnicodeString rt; |
| 860 _appendRuleText(rt); | 915 _appendRuleText(rt); |
| 861 dumpUS(stderr, rt); | 916 dumpUS(stderr, rt); |
| 862 } | 917 } |
| 863 | 918 |
| 864 fprintf(stderr, " text: '", this); | 919 fprintf(stderr, " text: '"); |
| 865 dumpUS(stderr, text); | 920 dumpUS(stderr, text); |
| 866 fprintf(stderr, "' prefix: '"); | 921 fprintf(stderr, "' prefix: '"); |
| 867 dumpUS(stderr, prefix); | 922 dumpUS(stderr, prefix); |
| 868 #endif | 923 #endif |
| 869 stripPrefix(workText, prefix, pp); | 924 stripPrefix(workText, prefix, pp); |
| 870 int32_t prefixLength = text.length() - workText.length(); | 925 int32_t prefixLength = text.length() - workText.length(); |
| 871 | 926 |
| 872 #ifdef RBNF_DEBUG | 927 #ifdef RBNF_DEBUG |
| 873 fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), s
ub1->getPos()); | 928 fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), s
ub1Pos); |
| 874 #endif | 929 #endif |
| 875 | 930 |
| 876 if (pp.getIndex() == 0 && sub1->getPos() != 0) { | 931 if (pp.getIndex() == 0 && sub1Pos != 0) { |
| 877 // commented out because ParsePosition doesn't have error index in 1.1.x | 932 // commented out because ParsePosition doesn't have error index in 1.1.x |
| 878 // restored for ICU4C port | 933 // restored for ICU4C port |
| 879 parsePosition.setErrorIndex(pp.getErrorIndex()); | 934 parsePosition.setErrorIndex(pp.getErrorIndex()); |
| 880 resVal.setLong(0); | 935 resVal.setLong(0); |
| 881 return TRUE; | 936 return TRUE; |
| 882 } | 937 } |
| 938 if (baseValue == kInfinityRule) { |
| 939 // If you match this, don't try to perform any calculations on it. |
| 940 parsePosition.setIndex(pp.getIndex()); |
| 941 resVal.setDouble(uprv_getInfinity()); |
| 942 return TRUE; |
| 943 } |
| 944 if (baseValue == kNaNRule) { |
| 945 // If you match this, don't try to perform any calculations on it. |
| 946 parsePosition.setIndex(pp.getIndex()); |
| 947 resVal.setDouble(uprv_getNaN()); |
| 948 return TRUE; |
| 949 } |
| 883 | 950 |
| 884 // this is the fun part. The basic guts of the rule-matching | 951 // this is the fun part. The basic guts of the rule-matching |
| 885 // logic is matchToDelimiter(), which is called twice. The first | 952 // logic is matchToDelimiter(), which is called twice. The first |
| 886 // time it searches the input string for the rule text BETWEEN | 953 // time it searches the input string for the rule text BETWEEN |
| 887 // the substitutions and tries to match the intervening text | 954 // the substitutions and tries to match the intervening text |
| 888 // in the input string with the first substitution. If that | 955 // in the input string with the first substitution. If that |
| 889 // succeeds, it then calls it again, this time to look for the | 956 // succeeds, it then calls it again, this time to look for the |
| 890 // rule text after the second substitution and to match the | 957 // rule text after the second substitution and to match the |
| 891 // intervening input text against the second substitution. | 958 // intervening input text against the second substitution. |
| 892 // | 959 // |
| (...skipping 23 matching lines...) Expand all Loading... |
| 916 double tempBaseValue = (double)(baseValue <= 0 ? 0 : baseValue); | 983 double tempBaseValue = (double)(baseValue <= 0 ? 0 : baseValue); |
| 917 | 984 |
| 918 UnicodeString temp; | 985 UnicodeString temp; |
| 919 do { | 986 do { |
| 920 // our partial parse result starts out as this rule's base | 987 // our partial parse result starts out as this rule's base |
| 921 // value. If it finds a successful match, matchToDelimiter() | 988 // value. If it finds a successful match, matchToDelimiter() |
| 922 // will compose this in some way with what it gets back from | 989 // will compose this in some way with what it gets back from |
| 923 // the substitution, giving us a new partial parse result | 990 // the substitution, giving us a new partial parse result |
| 924 pp.setIndex(0); | 991 pp.setIndex(0); |
| 925 | 992 |
| 926 temp.setTo(ruleText, sub1->getPos(), sub2->getPos() - sub1->getPos()); | 993 temp.setTo(ruleText, sub1Pos, sub2Pos - sub1Pos); |
| 927 double partialResult = matchToDelimiter(workText, start, tempBaseValue, | 994 double partialResult = matchToDelimiter(workText, start, tempBaseValue, |
| 928 temp, pp, sub1, | 995 temp, pp, sub1, |
| 929 upperBound); | 996 upperBound); |
| 930 | 997 |
| 931 // if we got a successful match (or were trying to match a | 998 // if we got a successful match (or were trying to match a |
| 932 // null substitution), pp is now pointing at the first unmatched | 999 // null substitution), pp is now pointing at the first unmatched |
| 933 // character. Take note of that, and try matchToDelimiter() | 1000 // character. Take note of that, and try matchToDelimiter() |
| 934 // on the input text again | 1001 // on the input text again |
| 935 if (pp.getIndex() != 0 || sub1->isNullSubstitution()) { | 1002 if (pp.getIndex() != 0 || sub1 == NULL) { |
| 936 start = pp.getIndex(); | 1003 start = pp.getIndex(); |
| 937 | 1004 |
| 938 UnicodeString workText2; | 1005 UnicodeString workText2; |
| 939 workText2.setTo(workText, pp.getIndex(), workText.length() - pp.getI
ndex()); | 1006 workText2.setTo(workText, pp.getIndex(), workText.length() - pp.getI
ndex()); |
| 940 ParsePosition pp2; | 1007 ParsePosition pp2; |
| 941 | 1008 |
| 942 // the second matchToDelimiter() will compose our previous | 1009 // the second matchToDelimiter() will compose our previous |
| 943 // partial result with whatever it gets back from its | 1010 // partial result with whatever it gets back from its |
| 944 // substitution if there's a successful match, giving us | 1011 // substitution if there's a successful match, giving us |
| 945 // a real result | 1012 // a real result |
| 946 temp.setTo(ruleText, sub2->getPos(), ruleText.length() - sub2->getPo
s()); | 1013 temp.setTo(ruleText, sub2Pos, ruleText.length() - sub2Pos); |
| 947 partialResult = matchToDelimiter(workText2, 0, partialResult, | 1014 partialResult = matchToDelimiter(workText2, 0, partialResult, |
| 948 temp, pp2, sub2, | 1015 temp, pp2, sub2, |
| 949 upperBound); | 1016 upperBound); |
| 950 | 1017 |
| 951 // if we got a successful match on this second | 1018 // if we got a successful match on this second |
| 952 // matchToDelimiter() call, update the high-water mark | 1019 // matchToDelimiter() call, update the high-water mark |
| 953 // and result (if necessary) | 1020 // and result (if necessary) |
| 954 if (pp2.getIndex() != 0 || sub2->isNullSubstitution()) { | 1021 if (pp2.getIndex() != 0 || sub2 == NULL) { |
| 955 if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMar
k) { | 1022 if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMar
k) { |
| 956 highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex(
); | 1023 highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex(
); |
| 957 result = partialResult; | 1024 result = partialResult; |
| 958 } | 1025 } |
| 959 } | 1026 } |
| 960 // commented out because ParsePosition doesn't have error index in 1
.1.x | |
| 961 // restored for ICU4C port | |
| 962 else { | 1027 else { |
| 963 int32_t temp = pp2.getErrorIndex() + sub1->getPos() + pp.getInde
x(); | 1028 // commented out because ParsePosition doesn't have error index
in 1.1.x |
| 1029 // restored for ICU4C port |
| 1030 int32_t temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex(); |
| 964 if (temp> parsePosition.getErrorIndex()) { | 1031 if (temp> parsePosition.getErrorIndex()) { |
| 965 parsePosition.setErrorIndex(temp); | 1032 parsePosition.setErrorIndex(temp); |
| 966 } | 1033 } |
| 967 } | 1034 } |
| 968 } | 1035 } |
| 969 // commented out because ParsePosition doesn't have error index in 1.1.x | |
| 970 // restored for ICU4C port | |
| 971 else { | 1036 else { |
| 972 int32_t temp = sub1->getPos() + pp.getErrorIndex(); | 1037 // commented out because ParsePosition doesn't have error index in 1
.1.x |
| 1038 // restored for ICU4C port |
| 1039 int32_t temp = sub1Pos + pp.getErrorIndex(); |
| 973 if (temp > parsePosition.getErrorIndex()) { | 1040 if (temp > parsePosition.getErrorIndex()) { |
| 974 parsePosition.setErrorIndex(temp); | 1041 parsePosition.setErrorIndex(temp); |
| 975 } | 1042 } |
| 976 } | 1043 } |
| 977 // keep trying to match things until the outer matchToDelimiter() | 1044 // keep trying to match things until the outer matchToDelimiter() |
| 978 // call fails to make a match (each time, it picks up where it | 1045 // call fails to make a match (each time, it picks up where it |
| 979 // left off the previous time) | 1046 // left off the previous time) |
| 980 } while (sub1->getPos() != sub2->getPos() | 1047 } while (sub1Pos != sub2Pos |
| 981 && pp.getIndex() > 0 | 1048 && pp.getIndex() > 0 |
| 982 && pp.getIndex() < workText.length() | 1049 && pp.getIndex() < workText.length() |
| 983 && pp.getIndex() != start); | 1050 && pp.getIndex() != start); |
| 984 | 1051 |
| 985 // update the caller's ParsePosition with our high-water mark | 1052 // update the caller's ParsePosition with our high-water mark |
| 986 // (i.e., it now points at the first character this function | 1053 // (i.e., it now points at the first character this function |
| 987 // didn't match-- the ParsePosition is therefore unchanged if | 1054 // didn't match-- the ParsePosition is therefore unchanged if |
| 988 // we didn't match anything) | 1055 // we didn't match anything) |
| 989 parsePosition.setIndex(highWaterMark); | 1056 parsePosition.setIndex(highWaterMark); |
| 990 // commented out because ParsePosition doesn't have error index in 1.1.x | 1057 // commented out because ParsePosition doesn't have error index in 1.1.x |
| 991 // restored for ICU4C port | 1058 // restored for ICU4C port |
| 992 if (highWaterMark > 0) { | 1059 if (highWaterMark > 0) { |
| 993 parsePosition.setErrorIndex(0); | 1060 parsePosition.setErrorIndex(0); |
| 994 } | 1061 } |
| 995 | 1062 |
| 996 // this is a hack for one unusual condition: Normally, whether this | 1063 // this is a hack for one unusual condition: Normally, whether this |
| 997 // rule belong to a fraction rule set or not is handled by its | 1064 // rule belong to a fraction rule set or not is handled by its |
| 998 // substitutions. But if that rule HAS NO substitutions, then | 1065 // substitutions. But if that rule HAS NO substitutions, then |
| 999 // we have to account for it here. By definition, if the matching | 1066 // we have to account for it here. By definition, if the matching |
| 1000 // rule in a fraction rule set has no substitutions, its numerator | 1067 // rule in a fraction rule set has no substitutions, its numerator |
| 1001 // is 1, and so the result is the reciprocal of its base value. | 1068 // is 1, and so the result is the reciprocal of its base value. |
| 1002 if (isFractionRule && | 1069 if (isFractionRule && highWaterMark > 0 && sub1 == NULL) { |
| 1003 highWaterMark > 0 && | |
| 1004 sub1->isNullSubstitution()) { | |
| 1005 result = 1 / result; | 1070 result = 1 / result; |
| 1006 } | 1071 } |
| 1007 | 1072 |
| 1008 resVal.setDouble(result); | 1073 resVal.setDouble(result); |
| 1009 return TRUE; // ??? do we need to worry if it is a long or a double? | 1074 return TRUE; // ??? do we need to worry if it is a long or a double? |
| 1010 } | 1075 } |
| 1011 | 1076 |
| 1012 /** | 1077 /** |
| 1013 * This function is used by parse() to match the text being parsed | 1078 * This function is used by parse() to match the text being parsed |
| 1014 * against a possible prefix string. This function | 1079 * against a possible prefix string. This function |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 // if the substitution could match all the text up to | 1187 // if the substitution could match all the text up to |
| 1123 // where we found "delimiter", then this function has | 1188 // where we found "delimiter", then this function has |
| 1124 // a successful match. Bump the caller's parse position | 1189 // a successful match. Bump the caller's parse position |
| 1125 // to point to the first character after the text | 1190 // to point to the first character after the text |
| 1126 // that matches "delimiter", and return the result | 1191 // that matches "delimiter", and return the result |
| 1127 // we got from parsing the substitution. | 1192 // we got from parsing the substitution. |
| 1128 if (success && tempPP.getIndex() == dPos) { | 1193 if (success && tempPP.getIndex() == dPos) { |
| 1129 pp.setIndex(dPos + dLen); | 1194 pp.setIndex(dPos + dLen); |
| 1130 return result.getDouble(); | 1195 return result.getDouble(); |
| 1131 } | 1196 } |
| 1132 // commented out because ParsePosition doesn't have error index
in 1.1.x | |
| 1133 // restored for ICU4C port | |
| 1134 else { | 1197 else { |
| 1198 // commented out because ParsePosition doesn't have error in
dex in 1.1.x |
| 1199 // restored for ICU4C port |
| 1135 if (tempPP.getErrorIndex() > 0) { | 1200 if (tempPP.getErrorIndex() > 0) { |
| 1136 pp.setErrorIndex(tempPP.getErrorIndex()); | 1201 pp.setErrorIndex(tempPP.getErrorIndex()); |
| 1137 } else { | 1202 } else { |
| 1138 pp.setErrorIndex(tempPP.getIndex()); | 1203 pp.setErrorIndex(tempPP.getIndex()); |
| 1139 } | 1204 } |
| 1140 } | 1205 } |
| 1141 } | 1206 } |
| 1142 | 1207 |
| 1143 // if we didn't match the substitution, search for another | 1208 // if we didn't match the substitution, search for another |
| 1144 // copy of "delimiter" in "text" and repeat the loop if | 1209 // copy of "delimiter" in "text" and repeat the loop if |
| 1145 // we find it | 1210 // we find it |
| 1146 tempPP.setIndex(0); | 1211 tempPP.setIndex(0); |
| 1147 dPos = findText(text, delimiter, dPos + dLen, &dLen); | 1212 dPos = findText(text, delimiter, dPos + dLen, &dLen); |
| 1148 } | 1213 } |
| 1149 // if we make it here, this was an unsuccessful match, and we | 1214 // if we make it here, this was an unsuccessful match, and we |
| 1150 // leave pp unchanged and return 0 | 1215 // leave pp unchanged and return 0 |
| 1151 pp.setIndex(0); | 1216 pp.setIndex(0); |
| 1152 return 0; | 1217 return 0; |
| 1153 | 1218 |
| 1154 // if "delimiter" is empty, or consists only of ignorable characters | 1219 // if "delimiter" is empty, or consists only of ignorable characters |
| 1155 // (i.e., is semantically empty), thwe we obviously can't search | 1220 // (i.e., is semantically empty), thwe we obviously can't search |
| 1156 // for "delimiter". Instead, just use "sub" to parse as much of | 1221 // for "delimiter". Instead, just use "sub" to parse as much of |
| 1157 // "text" as possible. | 1222 // "text" as possible. |
| 1158 } else { | 1223 } |
| 1224 else if (sub == NULL) { |
| 1225 return _baseValue; |
| 1226 } |
| 1227 else { |
| 1159 ParsePosition tempPP; | 1228 ParsePosition tempPP; |
| 1160 Formattable result; | 1229 Formattable result; |
| 1161 | 1230 |
| 1162 // try to match the whole string against the substitution | 1231 // try to match the whole string against the substitution |
| 1163 UBool success = sub->doParse(text, tempPP, _baseValue, upperBound, | 1232 UBool success = sub->doParse(text, tempPP, _baseValue, upperBound, |
| 1164 #if UCONFIG_NO_COLLATION | 1233 #if UCONFIG_NO_COLLATION |
| 1165 FALSE, | 1234 FALSE, |
| 1166 #else | 1235 #else |
| 1167 formatter->isLenient(), | 1236 formatter->isLenient(), |
| 1168 #endif | 1237 #endif |
| 1169 result); | 1238 result); |
| 1170 if (success && (tempPP.getIndex() != 0 || sub->isNullSubstitution())) { | 1239 if (success && (tempPP.getIndex() != 0)) { |
| 1171 // if there's a successful match (or it's a null | 1240 // if there's a successful match (or it's a null |
| 1172 // substitution), update pp to point to the first | 1241 // substitution), update pp to point to the first |
| 1173 // character we didn't match, and pass the result from | 1242 // character we didn't match, and pass the result from |
| 1174 // sub.doParse() on through to the caller | 1243 // sub.doParse() on through to the caller |
| 1175 pp.setIndex(tempPP.getIndex()); | 1244 pp.setIndex(tempPP.getIndex()); |
| 1176 return result.getDouble(); | 1245 return result.getDouble(); |
| 1177 } | 1246 } |
| 1178 // commented out because ParsePosition doesn't have error index in 1.1.x | |
| 1179 // restored for ICU4C port | |
| 1180 else { | 1247 else { |
| 1248 // commented out because ParsePosition doesn't have error index in 1
.1.x |
| 1249 // restored for ICU4C port |
| 1181 pp.setErrorIndex(tempPP.getErrorIndex()); | 1250 pp.setErrorIndex(tempPP.getErrorIndex()); |
| 1182 } | 1251 } |
| 1183 | 1252 |
| 1184 // and if we get to here, then nothing matched, so we return | 1253 // and if we get to here, then nothing matched, so we return |
| 1185 // 0 and leave pp alone | 1254 // 0 and leave pp alone |
| 1186 return 0; | 1255 return 0; |
| 1187 } | 1256 } |
| 1188 } | 1257 } |
| 1189 | 1258 |
| 1190 /** | 1259 /** |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1515 | 1584 |
| 1516 return o == CollationElementIterator::NULLORDER; | 1585 return o == CollationElementIterator::NULLORDER; |
| 1517 } | 1586 } |
| 1518 #endif | 1587 #endif |
| 1519 | 1588 |
| 1520 // if lenient parsing is turned off, there is no such thing as | 1589 // if lenient parsing is turned off, there is no such thing as |
| 1521 // an ignorable character: return true only if the string is empty | 1590 // an ignorable character: return true only if the string is empty |
| 1522 return FALSE; | 1591 return FALSE; |
| 1523 } | 1592 } |
| 1524 | 1593 |
| 1594 void |
| 1595 NFRule::setDecimalFormatSymbols(const DecimalFormatSymbols& newSymbols, UErrorCo
de& status) { |
| 1596 if (sub1 != NULL) { |
| 1597 sub1->setDecimalFormatSymbols(newSymbols, status); |
| 1598 } |
| 1599 if (sub2 != NULL) { |
| 1600 sub2->setDecimalFormatSymbols(newSymbols, status); |
| 1601 } |
| 1602 } |
| 1603 |
| 1525 U_NAMESPACE_END | 1604 U_NAMESPACE_END |
| 1526 | 1605 |
| 1527 /* U_HAVE_RBNF */ | 1606 /* U_HAVE_RBNF */ |
| 1528 #endif | 1607 #endif |
| OLD | NEW |