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 |