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

Unified Diff: sdk/lib/_internal/compiler/js_lib/js_helper.dart

Issue 988523002: Fix int.parse bug (dart2js version) (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sdk/lib/core/int.dart » ('j') | sdk/lib/core/int.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/compiler/js_lib/js_helper.dart
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index 89766d12b75c77824bc30d72c8a15331ff6f9f2d..6563192f335b05b7490c4d059f36699e8eb8b360 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -586,82 +586,81 @@ class Primitives {
return JS('int', '#', hash);
}
- static _throwFormatException(String string) {
- throw new FormatException(string);
+ @NoInline()
+ static int _parseError(String source, int handleError(String source)) {
+ if (handleError == null) throw new FormatException(source);
+ return handleError(source);
}
static int parseInt(String source,
int radix,
int handleError(String source)) {
- if (handleError == null) handleError = _throwFormatException;
-
checkString(source);
- var match = JS('JSExtendableArray|Null',
- r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(#)',
- source);
+ var re = JS('', r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i');
+ var match = JS('JSExtendableArray|Null', '#.exec(#)', re, source);
int digitsIndex = 1;
int hexIndex = 2;
int decimalIndex = 3;
int nonDecimalHexIndex = 4;
+ if (match == null) {
+ // TODO(sra): It might be that the match failed due to unrecognized U+0085
+ // spaces. We could replace them with U+0020 spaces and try matching
+ // again.
Lasse Reichstein Nielsen 2015/03/06 13:06:51 If \s doesn't always include U+0085, maybe change
sra1 2015/03/06 21:38:38 In that case, JavaScript's parseInt fails too.
+ return _parseError(source, handleError);
+ }
if (radix == null) {
- radix = 10;
- if (match != null) {
- if (match[hexIndex] != null) {
- // Cannot fail because we know that the digits are all hex.
- return JS('num', r'parseInt(#, 16)', source);
- }
- if (match[decimalIndex] != null) {
- // Cannot fail because we know that the digits are all decimal.
- return JS('num', r'parseInt(#, 10)', source);
- }
- return handleError(source);
+ if (match[decimalIndex] != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return JS('int', r'parseInt(#, 10)', source);
}
- } else {
- if (radix is! int) throw new ArgumentError("Radix is not an integer");
- if (radix < 2 || radix > 36) {
- throw new RangeError("Radix $radix not in range 2..36");
+ if (match[hexIndex] != null) {
+ // Cannot fail because we know that the digits are all hex.
+ return JS('int', r'parseInt(#, 16)', source);
}
- if (match != null) {
- if (radix == 10 && match[decimalIndex] != null) {
- // Cannot fail because we know that the digits are all decimal.
- return JS('num', r'parseInt(#, 10)', source);
- }
- if (radix < 10 || match[decimalIndex] == null) {
- // We know that the characters must be ASCII as otherwise the
- // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
- // guaranteed to be a safe operation, since it preserves digits
- // and lower-cases ASCII letters.
- int maxCharCode;
- if (radix <= 10) {
- // Allow all digits less than the radix. For example 0, 1, 2 for
- // radix 3.
- // "0".codeUnitAt(0) + radix - 1;
- maxCharCode = 0x30 + radix - 1;
- } else {
- // Letters are located after the digits in ASCII. Therefore we
- // only check for the character code. The regexp above made already
- // sure that the string does not contain anything but digits or
- // letters.
- // "a".codeUnitAt(0) + (radix - 10) - 1;
- maxCharCode = 0x61 + radix - 10 - 1;
- }
- String digitsPart = match[digitsIndex];
- for (int i = 0; i < digitsPart.length; i++) {
- int characterCode = digitsPart.codeUnitAt(0) | 0x20;
- if (digitsPart.codeUnitAt(i) > maxCharCode) {
- return handleError(source);
- }
- }
+ return _parseError(source, handleError);
+ }
+
+ if (radix is! int) throw new ArgumentError("Radix is not an integer");
+ if (radix < 2 || radix > 36) {
+ throw new RangeError("Radix $radix not in range 2..36");
Lasse Reichstein Nielsen 2015/03/06 13:06:51 You can change this one to: throw new RangeError
sra1 2015/03/06 21:38:39 Done.
+ }
+ if (radix == 10 && match[decimalIndex] != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return JS('int', r'parseInt(#, 10)', source);
+ }
+ if (radix < 10 || match[decimalIndex] == null) {
+ // We know that the characters must be ASCII as otherwise the
+ // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+ // guaranteed to be a safe operation, since it preserves digits
+ // and lower-cases ASCII letters.
Lasse Reichstein Nielsen 2015/03/06 13:06:51 How about doing parseInt first, and only scanning
sra1 2015/03/06 21:38:38 Another idea is to have a table of per-radix regex
+ int maxCharCode;
+ if (radix <= 10) {
+ // Allow all digits less than the radix. For example 0, 1, 2 for
+ // radix 3.
+ // "0".codeUnitAt(0) + radix - 1;
+ maxCharCode = 0x30 + radix - 1;
Lasse Reichstein Nielsen 2015/03/06 13:06:51 Maybe: 0x30 - 1 + radix to constant fold (0x30-1)
sra1 2015/03/06 21:38:38 Done.
+ } else {
+ // Letters are located after the digits in ASCII. Therefore we
+ // only check for the character code. The regexp above made already
+ // sure that the string does not contain anything but digits or
+ // letters.
+ // "a".codeUnitAt(0) + (radix - 10) - 1;
+ maxCharCode = 0x61 + radix - 10 - 1;
Lasse Reichstein Nielsen 2015/03/06 13:06:51 Similar constant folding possible.
sra1 2015/03/06 21:38:38 Done.
+ }
+ assert(match[digitsIndex] is String);
+ String digitsPart = JS('String', '#[#]', match, digitsIndex);
+ for (int i = 0; i < digitsPart.length; i++) {
+ int characterCode = digitsPart.codeUnitAt(i) | 0x20;
+ if (characterCode > maxCharCode) {
+ return _parseError(source, handleError);
}
}
}
- if (match == null) return handleError(source);
- return JS('num', r'parseInt(#, #)', source, radix);
+ return JS('int', r'parseInt(#, #)', source, radix);
Lasse Reichstein Nielsen 2015/03/06 13:06:51 Make a comment that the checks above guarantee tha
sra1 2015/03/06 21:38:39 Done.
}
static double parseDouble(String source, double handleError(String source)) {
checkString(source);
- if (handleError == null) handleError = _throwFormatException;
// Notice that JS parseFloat accepts garbage at the end of the string.
// Accept only:
// - [+/-]NaN
@@ -672,7 +671,7 @@ class Primitives {
r'/^\s*[+-]?(?:Infinity|NaN|'
r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
source)) {
- return handleError(source);
+ return _parseError(source, handleError);
}
var result = JS('num', r'parseFloat(#)', source);
if (result.isNaN) {
@@ -680,7 +679,7 @@ class Primitives {
if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
return result;
}
- return handleError(source);
+ return _parseError(source, handleError);
}
return result;
}
« no previous file with comments | « no previous file | sdk/lib/core/int.dart » ('j') | sdk/lib/core/int.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698