Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: pkg/intl/lib/number_format.dart

Issue 222763002: Code cleanup in _NumberFormatParser (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of intl; 5 part of intl;
6 /** 6 /**
7 * Provides the ability to format a number in a locale-specific way. The 7 * Provides the ability to format a number in a locale-specific way. The
8 * format is specified as a pattern using a subset of the ICU formatting 8 * format is specified as a pattern using a subset of the ICU formatting
9 * patterns. 9 * patterns.
10 * 10 *
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 /** Caches the symbols used for our locale. */ 75 /** Caches the symbols used for our locale. */
76 NumberSymbols _symbols; 76 NumberSymbols _symbols;
77 77
78 /** 78 /**
79 * Transient internal state in which to build up the result of the format 79 * Transient internal state in which to build up the result of the format
80 * operation. We can have this be just an instance variable because Dart is 80 * operation. We can have this be just an instance variable because Dart is
81 * single-threaded and unless we do an asynchronous operation in the process 81 * single-threaded and unless we do an asynchronous operation in the process
82 * of formatting then there will only ever be one number being formatted 82 * of formatting then there will only ever be one number being formatted
83 * at a time. In languages with threads we'd need to pass this on the stack. 83 * at a time. In languages with threads we'd need to pass this on the stack.
84 */ 84 */
85 StringBuffer _buffer; 85 final StringBuffer _buffer = new StringBuffer();
86 86
87 /** 87 /**
88 * Create a number format that prints using [newPattern] as it applies in 88 * Create a number format that prints using [newPattern] as it applies in
89 * [locale]. 89 * [locale].
90 */ 90 */
91 factory NumberFormat([String newPattern, String locale]) => 91 factory NumberFormat([String newPattern, String locale]) =>
92 new NumberFormat._forPattern(locale, (x) => newPattern); 92 new NumberFormat._forPattern(locale, (x) => newPattern);
93 93
94 /** Create a number format that prints as DECIMAL_PATTERN. */ 94 /** Create a number format that prints as DECIMAL_PATTERN. */
95 NumberFormat.decimalPattern([String locale]) : 95 NumberFormat.decimalPattern([String locale]) :
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 139
140 /** 140 /**
141 * Format [number] according to our pattern and return the formatted string. 141 * Format [number] according to our pattern and return the formatted string.
142 */ 142 */
143 String format(num number) { 143 String format(num number) {
144 // TODO(alanknight): Do we have to do anything for printing numbers bidi? 144 // TODO(alanknight): Do we have to do anything for printing numbers bidi?
145 // Or are they always printed left to right? 145 // Or are they always printed left to right?
146 if (number.isNaN) return symbols.NAN; 146 if (number.isNaN) return symbols.NAN;
147 if (number.isInfinite) return "${_signPrefix(number)}${symbols.INFINITY}"; 147 if (number.isInfinite) return "${_signPrefix(number)}${symbols.INFINITY}";
148 148
149 _newBuffer();
150 _add(_signPrefix(number)); 149 _add(_signPrefix(number));
151 _formatNumber(number.abs() * _multiplier); 150 _formatNumber(number.abs() * _multiplier);
152 _add(_signSuffix(number)); 151 _add(_signSuffix(number));
153 152
154 var result = _buffer.toString(); 153 var result = _buffer.toString();
155 _buffer = null; 154 _buffer.clear();
156 return result; 155 return result;
157 } 156 }
158 157
159 /** 158 /**
160 * Format the main part of the number in the form dictated by the pattern. 159 * Format the main part of the number in the form dictated by the pattern.
161 */ 160 */
162 void _formatNumber(num number) { 161 void _formatNumber(num number) {
163 if (_useExponentialNotation) { 162 if (_useExponentialNotation) {
164 _formatExponential(number); 163 _formatExponential(number);
165 } else { 164 } else {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 fracValue = 0; 242 fracValue = 0;
244 } else { 243 } else {
245 intValue = shiftedNumber.round() ~/ power; 244 intValue = shiftedNumber.round() ~/ power;
246 fracValue = (shiftedNumber - intValue * power).floor(); 245 fracValue = (shiftedNumber - intValue * power).floor();
247 } 246 }
248 var fractionPresent = minimumFractionDigits > 0 || fracValue > 0; 247 var fractionPresent = minimumFractionDigits > 0 || fracValue > 0;
249 248
250 // If the int part is larger than 2^52 and we're on Javascript (so it's 249 // If the int part is larger than 2^52 and we're on Javascript (so it's
251 // really a float) it will lose precision, so pad out the rest of it 250 // really a float) it will lose precision, so pad out the rest of it
252 // with zeros. Check for Javascript by seeing if an integer is double. 251 // with zeros. Check for Javascript by seeing if an integer is double.
253 var paddingDigits = new StringBuffer(); 252 var paddingDigits = '';
254 if (1 is double && intValue > _maxInt) { 253 if (1 is double && intValue > _maxInt) {
255 var howManyDigitsTooBig = (log(intValue) / LN10).ceil() - 16; 254 var howManyDigitsTooBig = (log(intValue) / LN10).ceil() - 16;
256 var divisor = pow(10, howManyDigitsTooBig).round(); 255 var divisor = pow(10, howManyDigitsTooBig).round();
257 for (var each in new List(howManyDigitsTooBig.toInt())) { 256 paddingDigits = symbols.ZERO_DIGIT * howManyDigitsTooBig.toInt();
258 paddingDigits.write(symbols.ZERO_DIGIT); 257
259 }
260 intValue = (intValue / divisor).truncate(); 258 intValue = (intValue / divisor).truncate();
261 } 259 }
262 var integerDigits = "${intValue}${paddingDigits}".codeUnits; 260 var integerDigits = "${intValue}${paddingDigits}".codeUnits;
263 var digitLength = integerDigits.length; 261 var digitLength = integerDigits.length;
264 262
265 if (_hasPrintableIntegerPart(intValue)) { 263 if (_hasPrintableIntegerPart(intValue)) {
266 _pad(minimumIntegerDigits - digitLength); 264 _pad(minimumIntegerDigits - digitLength);
267 for (var i = 0; i < digitLength; i++) { 265 for (var i = 0; i < digitLength; i++) {
268 _addDigit(integerDigits[i]); 266 _addDigit(integerDigits[i]);
269 _group(digitLength, i); 267 _group(digitLength, i);
(...skipping 30 matching lines...) Expand all
300 } 298 }
301 299
302 /** 300 /**
303 * Return true if we have a main integer part which is printable, either 301 * Return true if we have a main integer part which is printable, either
304 * because we have digits left of the decimal point, or because there are 302 * because we have digits left of the decimal point, or because there are
305 * a minimum number of printable digits greater than 1. 303 * a minimum number of printable digits greater than 1.
306 */ 304 */
307 bool _hasPrintableIntegerPart(int intValue) => 305 bool _hasPrintableIntegerPart(int intValue) =>
308 intValue > 0 || minimumIntegerDigits > 0; 306 intValue > 0 || minimumIntegerDigits > 0;
309 307
310 /**
311 * Create a new empty buffer. See comment on [_buffer] variable for why
312 * we have it as an instance variable rather than passing it on the stack.
313 */
314 void _newBuffer() { _buffer = new StringBuffer(); }
315
316 /** A group of methods that provide support for writing digits and other 308 /** A group of methods that provide support for writing digits and other
317 * required characters into [_buffer] easily. 309 * required characters into [_buffer] easily.
318 */ 310 */
319 void _add(String x) { _buffer.write(x);} 311 void _add(String x) { _buffer.write(x);}
320 void _addCharCode(int x) { _buffer.writeCharCode(x); } 312 void _addCharCode(int x) { _buffer.writeCharCode(x); }
321 void _addZero() { _buffer.write(symbols.ZERO_DIGIT); } 313 void _addZero() { _buffer.write(symbols.ZERO_DIGIT); }
322 void _addDigit(int x) { _buffer.writeCharCode(_localeZero + x - _zero); } 314 void _addDigit(int x) { _buffer.writeCharCode(_localeZero + x - _zero); }
323 315
324 /** Print padding up to [numberOfDigits] above what's included in [basic]. */ 316 /** Print padding up to [numberOfDigits] above what's included in [basic]. */
325 void _pad(int numberOfDigits, [String basic = '']) { 317 void _pad(int numberOfDigits, [String basic = '']) {
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 pattern.moveNext(); 432 pattern.moveNext();
441 } 433 }
442 format._negativeSuffix = _parseAffix(); 434 format._negativeSuffix = _parseAffix();
443 } else { 435 } else {
444 // If no negative affix is specified, they share the same positive affix. 436 // If no negative affix is specified, they share the same positive affix.
445 format._negativePrefix = format._positivePrefix + format._negativePrefix; 437 format._negativePrefix = format._positivePrefix + format._negativePrefix;
446 format._negativeSuffix = format._negativeSuffix + format._positiveSuffix; 438 format._negativeSuffix = format._negativeSuffix + format._positiveSuffix;
447 } 439 }
448 } 440 }
449 441
450 /** Variable used in parsing prefixes and suffixes to keep track of 442 /**
451 * whether or not we are in a quoted region. */ 443 * Variable used in parsing prefixes and suffixes to keep track of
444 * whether or not we are in a quoted region.
445 */
452 bool inQuote = false; 446 bool inQuote = false;
453 447
454 /** 448 /**
455 * Parse a prefix or suffix and return the prefix/suffix string. Note that 449 * Parse a prefix or suffix and return the prefix/suffix string. Note that
456 * this also may modify the state of [format]. 450 * this also may modify the state of [format].
457 */ 451 */
458 String _parseAffix() { 452 String _parseAffix() {
459 var affix = new StringBuffer(); 453 var affix = new StringBuffer();
460 inQuote = false; 454 inQuote = false;
461 while (parseCharacterAffix(affix) && pattern.moveNext()); 455 while (parseCharacterAffix(affix) && pattern.moveNext());
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 affix.write(symbols.PERMILL); 503 affix.write(symbols.PERMILL);
510 break; 504 break;
511 default: 505 default:
512 affix.write(ch); 506 affix.write(ch);
513 } 507 }
514 } 508 }
515 return true; 509 return true;
516 } 510 }
517 511
518 /** Variables used in [_parseTrunk] and [parseTrunkCharacter]. */ 512 /** Variables used in [_parseTrunk] and [parseTrunkCharacter]. */
519 var decimalPos; 513 var decimalPos = -1;
520 var digitLeftCount; 514 var digitLeftCount = 0;
521 var zeroDigitCount; 515 var zeroDigitCount = 0;
522 var digitRightCount; 516 var digitRightCount = 0;
523 var groupingCount; 517 var groupingCount = -1;
524 var trunk;
525 518
526 /** 519 /**
527 * Parse the "trunk" portion of the pattern, the piece that doesn't include 520 * Parse the "trunk" portion of the pattern, the piece that doesn't include
528 * positive or negative prefixes or suffixes. 521 * positive or negative prefixes or suffixes.
529 */ 522 */
530 String _parseTrunk() { 523 String _parseTrunk() {
531 decimalPos = -1;
532 digitLeftCount = 0;
533 zeroDigitCount = 0;
534 digitRightCount = 0;
535 groupingCount = -1;
536
537 var loop = true; 524 var loop = true;
538 trunk = new StringBuffer(); 525 var trunk = new StringBuffer();
539 while (pattern.current != null && loop) { 526 while (pattern.current != null && loop) {
540 loop = parseTrunkCharacter(); 527 loop = parseTrunkCharacter(trunk);
541 } 528 }
542 529
543 if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { 530 if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
544 // Handle '###.###' and '###.' and '.###' 531 // Handle '###.###' and '###.' and '.###'
545 // Handle '.###' 532 // Handle '.###'
546 var n = decimalPos == 0 ? 1 : decimalPos; 533 var n = decimalPos == 0 ? 1 : decimalPos;
547 digitRightCount = digitLeftCount - n; 534 digitRightCount = digitLeftCount - n;
548 digitLeftCount = n - 1; 535 digitLeftCount = n - 1;
549 zeroDigitCount = 1; 536 zeroDigitCount = 1;
550 } 537 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 decimalPos == totalDigits; 576 decimalPos == totalDigits;
590 577
591 return trunk.toString(); 578 return trunk.toString();
592 } 579 }
593 580
594 /** 581 /**
595 * Parse an individual character of the trunk. Return true if we should 582 * Parse an individual character of the trunk. Return true if we should
596 * continue to look for additional trunk characters or false if we have 583 * continue to look for additional trunk characters or false if we have
597 * reached the end. 584 * reached the end.
598 */ 585 */
599 bool parseTrunkCharacter() { 586 bool parseTrunkCharacter(trunk) {
600 var ch = pattern.current; 587 var ch = pattern.current;
601 switch (ch) { 588 switch (ch) {
602 case _PATTERN_DIGIT: 589 case _PATTERN_DIGIT:
603 if (zeroDigitCount > 0) { 590 if (zeroDigitCount > 0) {
604 digitRightCount++; 591 digitRightCount++;
605 } else { 592 } else {
606 digitLeftCount++; 593 digitLeftCount++;
607 } 594 }
608 if (groupingCount >= 0 && decimalPos < 0) { 595 if (groupingCount >= 0 && decimalPos < 0) {
609 groupingCount++; 596 groupingCount++;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 677
691 _StringIterable(String s) : iterator = _iterator(s); 678 _StringIterable(String s) : iterator = _iterator(s);
692 } 679 }
693 680
694 /** 681 /**
695 * Provides an iterator over a string as a list of substrings, and also 682 * Provides an iterator over a string as a list of substrings, and also
696 * gives us a lookahead of one via the [peek] method. 683 * gives us a lookahead of one via the [peek] method.
697 */ 684 */
698 class _StringIterator implements Iterator<String> { 685 class _StringIterator implements Iterator<String> {
699 final String input; 686 final String input;
700 int index = -1; 687 int nextIndex = 0;
701 inBounds(i) => i >= 0 && i < input.length; 688 String _current = null;
702 _StringIterator(this.input);
703 String get current => inBounds(index) ? input[index] : null;
704 689
705 bool moveNext() => inBounds(++index); 690 _StringIterator(input) : input = _validate(input);
706 String get peek => inBounds(index + 1) ? input[index + 1] : null; 691
692 String get current => _current;
693
694 bool moveNext() {
695 if (nextIndex >= input.length) {
696 _current = null;
697 return false;
698 }
699 _current = input[nextIndex++];
700 return true;
701 }
702
703 String get peek => nextIndex >= input.length ? null : input[nextIndex];
704
707 Iterator<String> get iterator => this; 705 Iterator<String> get iterator => this;
706
707 static String _validate(input) {
708 if (input is! String) throw new ArgumentError(input);
709 return input;
710 }
711
708 } 712 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698