| OLD | NEW |
| 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 dart._interceptors; | 5 part of dart._interceptors; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * The implementation of Dart's int & double methods. | 8 * The implementation of Dart's int & double methods. |
| 9 * These are made available as extension methods on `Number` in JS. | 9 * These are made available as extension methods on `Number` in JS. |
| 10 */ | 10 */ |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 } else { | 33 } else { |
| 34 return -1; | 34 return -1; |
| 35 } | 35 } |
| 36 } | 36 } |
| 37 | 37 |
| 38 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0; | 38 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0; |
| 39 | 39 |
| 40 bool get isNaN => JS('bool', r'isNaN(#)', this); | 40 bool get isNaN => JS('bool', r'isNaN(#)', this); |
| 41 | 41 |
| 42 bool get isInfinite { | 42 bool get isInfinite { |
| 43 return JS('bool', r'# == (1/0)', this) | 43 return JS('bool', r'# == (1/0)', this) || JS('bool', r'# == (-1/0)', this); |
| 44 || JS('bool', r'# == (-1/0)', this); | |
| 45 } | 44 } |
| 46 | 45 |
| 47 bool get isFinite => JS('bool', r'isFinite(#)', this); | 46 bool get isFinite => JS('bool', r'isFinite(#)', this); |
| 48 | 47 |
| 49 JSNumber remainder(num b) { | 48 JSNumber remainder(num b) { |
| 50 if (b is! num) throw argumentErrorValue(b); | 49 if (b is! num) throw argumentErrorValue(b); |
| 51 return JS('num', r'# % #', this, b); | 50 return JS('num', r'# % #', this, b); |
| 52 } | 51 } |
| 53 | 52 |
| 54 JSNumber abs() => JS('num', r'Math.abs(#)', this); | 53 JSNumber abs() => JS('num', r'Math.abs(#)', this); |
| 55 | 54 |
| 56 JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this; | 55 JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this; |
| 57 | 56 |
| 58 static const int _MIN_INT32 = -0x80000000; | 57 static const int _MIN_INT32 = -0x80000000; |
| 59 static const int _MAX_INT32 = 0x7FFFFFFF; | 58 static const int _MAX_INT32 = 0x7FFFFFFF; |
| 60 | 59 |
| 61 int toInt() { | 60 int toInt() { |
| 62 if (this >= _MIN_INT32 && this <= _MAX_INT32) { | 61 if (this >= _MIN_INT32 && this <= _MAX_INT32) { |
| 63 return JS('int', '# | 0', this); | 62 return JS('int', '# | 0', this); |
| 64 } | 63 } |
| 65 if (JS('bool', r'isFinite(#)', this)) { | 64 if (JS('bool', r'isFinite(#)', this)) { |
| 66 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0. | 65 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0. |
| 67 } | 66 } |
| 68 // This is either NaN, Infinity or -Infinity. | 67 // This is either NaN, Infinity or -Infinity. |
| 69 throw new UnsupportedError(JS("String", '"" + #', this)); | 68 throw new UnsupportedError(JS("String", '"" + #', this)); |
| 70 } | 69 } |
| 71 | 70 |
| 72 int truncate() => toInt(); | 71 int truncate() => toInt(); |
| 73 | 72 |
| 74 int ceil() => ceilToDouble().toInt(); | 73 int ceil() => ceilToDouble().toInt(); |
| 75 | 74 |
| 76 int floor() => floorToDouble().toInt(); | 75 int floor() => floorToDouble().toInt(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 } | 141 } |
| 143 if (this == 0 && isNegative) return "-$result"; | 142 if (this == 0 && isNegative) return "-$result"; |
| 144 return result; | 143 return result; |
| 145 } | 144 } |
| 146 | 145 |
| 147 String toStringAsPrecision(int precision) { | 146 String toStringAsPrecision(int precision) { |
| 148 checkInt(precision); | 147 checkInt(precision); |
| 149 if (precision < 1 || precision > 21) { | 148 if (precision < 1 || precision > 21) { |
| 150 throw new RangeError.range(precision, 1, 21, "precision"); | 149 throw new RangeError.range(precision, 1, 21, "precision"); |
| 151 } | 150 } |
| 152 String result = JS('String', r'#.toPrecision(#)', | 151 String result = JS('String', r'#.toPrecision(#)', this, precision); |
| 153 this, precision); | |
| 154 if (this == 0 && isNegative) return "-$result"; | 152 if (this == 0 && isNegative) return "-$result"; |
| 155 return result; | 153 return result; |
| 156 } | 154 } |
| 157 | 155 |
| 158 String toRadixString(int radix) { | 156 String toRadixString(int radix) { |
| 159 checkInt(radix); | 157 checkInt(radix); |
| 160 if (radix < 2 || radix > 36) { | 158 if (radix < 2 || radix > 36) { |
| 161 throw new RangeError.range(radix, 2, 36, "radix"); | 159 throw new RangeError.range(radix, 2, 36, "radix"); |
| 162 } | 160 } |
| 163 String result = JS('String', r'#.toString(#)', this, radix); | 161 String result = JS('String', r'#.toString(#)', this, radix); |
| 164 const int rightParenCode = 0x29; | 162 const int rightParenCode = 0x29; |
| 165 if (result.codeUnitAt(result.length - 1) != rightParenCode) { | 163 if (result.codeUnitAt(result.length - 1) != rightParenCode) { |
| 166 return result; | 164 return result; |
| 167 } | 165 } |
| 168 return _handleIEtoString(result); | 166 return _handleIEtoString(result); |
| 169 } | 167 } |
| 170 | 168 |
| 171 static String _handleIEtoString(String result) { | 169 static String _handleIEtoString(String result) { |
| 172 // Result is probably IE's untraditional format for large numbers, | 170 // Result is probably IE's untraditional format for large numbers, |
| 173 // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16). | 171 // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16). |
| 174 var match = JS('List|Null', | 172 var match = JS('List|Null', |
| 175 r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', | 173 r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result); |
| 176 result); | |
| 177 if (match == null) { | 174 if (match == null) { |
| 178 // Then we don't know how to handle it at all. | 175 // Then we don't know how to handle it at all. |
| 179 throw new UnsupportedError("Unexpected toString result: $result"); | 176 throw new UnsupportedError("Unexpected toString result: $result"); |
| 180 } | 177 } |
| 181 result = JS('String', '#', match[1]); | 178 result = JS('String', '#', match[1]); |
| 182 int exponent = JS("int", "+#", match[3]); | 179 int exponent = JS("int", "+#", match[3]); |
| 183 if (match[2] != null) { | 180 if (match[2] != null) { |
| 184 result = JS('String', '# + #', result, match[2]); | 181 result = JS('String', '# + #', result, match[2]); |
| 185 exponent -= JS('int', '#.length', match[2]); | 182 exponent -= JS('int', '#.length', match[2]); |
| 186 } | 183 } |
| 187 return result + "0" * exponent; | 184 return result + "0" * exponent; |
| 188 } | 185 } |
| 189 | 186 |
| 190 // Note: if you change this, also change the function [S]. | 187 // Note: if you change this, also change the function [S]. |
| 191 String toString() { | 188 String toString() { |
| 192 if (this == 0 && JS('bool', '(1 / #) < 0', this)) { | 189 if (this == 0 && JS('bool', '(1 / #) < 0', this)) { |
| 193 return '-0.0'; | 190 return '-0.0'; |
| 194 } else { | 191 } else { |
| 195 return JS('String', r'"" + (#)', this); | 192 return JS('String', r'"" + (#)', this); |
| 196 } | 193 } |
| 197 } | 194 } |
| 198 | 195 |
| 199 int get hashCode => JS('int', '# & 0x1FFFFFFF', this); | 196 int get hashCode => JS('int', '# & 0x1FFFFFFF', this); |
| 200 | 197 |
| 201 JSNumber operator -() => JS('num', r'-#', this); | 198 JSNumber operator -() => JS('num', r'-#', this); |
| 202 | 199 |
| 203 JSNumber operator +(num other) { | 200 JSNumber operator +(num other) { |
| 204 if (other is !num) throw argumentErrorValue(other); | 201 if (other is! num) throw argumentErrorValue(other); |
| 205 return JS('num', '# + #', this, other); | 202 return JS('num', '# + #', this, other); |
| 206 } | 203 } |
| 207 | 204 |
| 208 JSNumber operator -(num other) { | 205 JSNumber operator -(num other) { |
| 209 if (other is !num) throw argumentErrorValue(other); | 206 if (other is! num) throw argumentErrorValue(other); |
| 210 return JS('num', '# - #', this, other); | 207 return JS('num', '# - #', this, other); |
| 211 } | 208 } |
| 212 | 209 |
| 213 double operator /(num other) { | 210 double operator /(num other) { |
| 214 if (other is !num) throw argumentErrorValue(other); | 211 if (other is! num) throw argumentErrorValue(other); |
| 215 return JS('num', '# / #', this, other); | 212 return JS('num', '# / #', this, other); |
| 216 } | 213 } |
| 217 | 214 |
| 218 JSNumber operator *(num other) { | 215 JSNumber operator *(num other) { |
| 219 if (other is !num) throw argumentErrorValue(other); | 216 if (other is! num) throw argumentErrorValue(other); |
| 220 return JS('num', '# * #', this, other); | 217 return JS('num', '# * #', this, other); |
| 221 } | 218 } |
| 222 | 219 |
| 223 JSNumber operator %(num other) { | 220 JSNumber operator %(num other) { |
| 224 if (other is !num) throw argumentErrorValue(other); | 221 if (other is! num) throw argumentErrorValue(other); |
| 225 // Euclidean Modulo. | 222 // Euclidean Modulo. |
| 226 num result = JS('num', r'# % #', this, other); | 223 num result = JS('num', r'# % #', this, other); |
| 227 if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0. | 224 if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0. |
| 228 if (result > 0) return result; | 225 if (result > 0) return result; |
| 229 if (JS('num', '#', other) < 0) { | 226 if (JS('num', '#', other) < 0) { |
| 230 return result - JS('num', '#', other); | 227 return result - JS('num', '#', other); |
| 231 } else { | 228 } else { |
| 232 return result + JS('num', '#', other); | 229 return result + JS('num', '#', other); |
| 233 } | 230 } |
| 234 } | 231 } |
| 235 | 232 |
| 236 bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value); | 233 bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value); |
| 237 | 234 |
| 238 int operator ~/(num other) { | 235 int operator ~/(num other) { |
| 239 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) { | 236 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) { |
| 240 return JS('int', r'(# / #) | 0', this, other); | 237 return JS('int', r'(# / #) | 0', this, other); |
| 241 } else { | 238 } else { |
| 242 return _tdivSlow(other); | 239 return _tdivSlow(other); |
| 243 } | 240 } |
| 244 } | 241 } |
| 245 | 242 |
| 246 int _tdivSlow(num other) { | 243 int _tdivSlow(num other) { |
| 247 if (other is !num) throw argumentErrorValue(other); | 244 if (other is! num) throw argumentErrorValue(other); |
| 248 return (JS('num', r'# / #', this, other)).toInt(); | 245 return (JS('num', r'# / #', this, other)).toInt(); |
| 249 } | 246 } |
| 250 | 247 |
| 251 // TODO(ngeoffray): Move the bit operations below to [JSInt] and | 248 // TODO(ngeoffray): Move the bit operations below to [JSInt] and |
| 252 // make them take an int. Because this will make operations slower, | 249 // make them take an int. Because this will make operations slower, |
| 253 // we define these methods on number for now but we need to decide | 250 // we define these methods on number for now but we need to decide |
| 254 // the grain at which we do the type checks. | 251 // the grain at which we do the type checks. |
| 255 | 252 |
| 256 int operator <<(num other) { | 253 int operator <<(num other) { |
| 257 if (other is !num) throw argumentErrorValue(other); | 254 if (other is! num) throw argumentErrorValue(other); |
| 258 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); | 255 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); |
| 259 return _shlPositive(other); | 256 return _shlPositive(other); |
| 260 } | 257 } |
| 261 | 258 |
| 262 int _shlPositive(num other) { | 259 int _shlPositive(num other) { |
| 263 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting | 260 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting |
| 264 // by 33 is hence equivalent to a shift by 1. | 261 // by 33 is hence equivalent to a shift by 1. |
| 265 return JS('bool', r'# > 31', other) | 262 return JS('bool', r'# > 31', other) |
| 266 ? 0 | 263 ? 0 |
| 267 : JS('int', r'(# << #) >>> 0', this, other); | 264 : JS('int', r'(# << #) >>> 0', this, other); |
| 268 } | 265 } |
| 269 | 266 |
| 270 int operator >>(num other) { | 267 int operator >>(num other) { |
| 271 if (other is !num) throw argumentErrorValue(other); | 268 if (other is! num) throw argumentErrorValue(other); |
| 272 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); | 269 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); |
| 273 return _shrOtherPositive(other); | 270 return _shrOtherPositive(other); |
| 274 } | 271 } |
| 275 | 272 |
| 276 int _shrOtherPositive(num other) { | 273 int _shrOtherPositive(num other) { |
| 277 return JS('num', '#', this) > 0 | 274 return JS('num', '#', this) > 0 |
| 278 ? _shrBothPositive(other) | 275 ? _shrBothPositive(other) |
| 279 // For negative numbers we just clamp the shift-by amount. | 276 // For negative numbers we just clamp the shift-by amount. |
| 280 // `this` could be negative but not have its 31st bit set. | 277 // `this` could be negative but not have its 31st bit set. |
| 281 // The ">>" would then shift in 0s instead of 1s. Therefore | 278 // The ">>" would then shift in 0s instead of 1s. Therefore |
| 282 // we cannot simply return 0xFFFFFFFF. | 279 // we cannot simply return 0xFFFFFFFF. |
| 283 : JS('int', r'(# >> #) >>> 0', this, other > 31 ? 31 : other); | 280 : JS('int', r'(# >> #) >>> 0', this, other > 31 ? 31 : other); |
| 284 } | 281 } |
| 285 | 282 |
| 286 int _shrBothPositive(num other) { | 283 int _shrBothPositive(num other) { |
| 287 return JS('bool', r'# > 31', other) | 284 return JS('bool', r'# > 31', other) |
| 288 // JavaScript only looks at the last 5 bits of the shift-amount. In JS | 285 // JavaScript only looks at the last 5 bits of the shift-amount. In JS |
| 289 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the | 286 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the |
| 290 // computation when that happens. | 287 // computation when that happens. |
| 291 ? 0 | 288 ? 0 |
| 292 // Given that `this` is positive we must not use '>>'. Otherwise a | 289 // Given that `this` is positive we must not use '>>'. Otherwise a |
| 293 // number that has the 31st bit set would be treated as negative and | 290 // number that has the 31st bit set would be treated as negative and |
| 294 // shift in ones. | 291 // shift in ones. |
| 295 : JS('int', r'# >>> #', this, other); | 292 : JS('int', r'# >>> #', this, other); |
| 296 } | 293 } |
| 297 | 294 |
| 298 int operator &(num other) { | 295 int operator &(num other) { |
| 299 if (other is !num) throw argumentErrorValue(other); | 296 if (other is! num) throw argumentErrorValue(other); |
| 300 return JS('int', r'(# & #) >>> 0', this, other); | 297 return JS('int', r'(# & #) >>> 0', this, other); |
| 301 } | 298 } |
| 302 | 299 |
| 303 int operator |(num other) { | 300 int operator |(num other) { |
| 304 if (other is !num) throw argumentErrorValue(other); | 301 if (other is! num) throw argumentErrorValue(other); |
| 305 return JS('int', r'(# | #) >>> 0', this, other); | 302 return JS('int', r'(# | #) >>> 0', this, other); |
| 306 } | 303 } |
| 307 | 304 |
| 308 int operator ^(num other) { | 305 int operator ^(num other) { |
| 309 if (other is !num) throw argumentErrorValue(other); | 306 if (other is! num) throw argumentErrorValue(other); |
| 310 return JS('int', r'(# ^ #) >>> 0', this, other); | 307 return JS('int', r'(# ^ #) >>> 0', this, other); |
| 311 } | 308 } |
| 312 | 309 |
| 313 bool operator <(num other) { | 310 bool operator <(num other) { |
| 314 if (other is !num) throw argumentErrorValue(other); | 311 if (other is! num) throw argumentErrorValue(other); |
| 315 return JS('bool', '# < #', this, other); | 312 return JS('bool', '# < #', this, other); |
| 316 } | 313 } |
| 317 | 314 |
| 318 bool operator >(num other) { | 315 bool operator >(num other) { |
| 319 if (other is !num) throw argumentErrorValue(other); | 316 if (other is! num) throw argumentErrorValue(other); |
| 320 return JS('bool', '# > #', this, other); | 317 return JS('bool', '# > #', this, other); |
| 321 } | 318 } |
| 322 | 319 |
| 323 bool operator <=(num other) { | 320 bool operator <=(num other) { |
| 324 if (other is !num) throw argumentErrorValue(other); | 321 if (other is! num) throw argumentErrorValue(other); |
| 325 return JS('bool', '# <= #', this, other); | 322 return JS('bool', '# <= #', this, other); |
| 326 } | 323 } |
| 327 | 324 |
| 328 bool operator >=(num other) { | 325 bool operator >=(num other) { |
| 329 if (other is !num) throw argumentErrorValue(other); | 326 if (other is! num) throw argumentErrorValue(other); |
| 330 return JS('bool', '# >= #', this, other); | 327 return JS('bool', '# >= #', this, other); |
| 331 } | 328 } |
| 332 | 329 |
| 333 // int members. | 330 // int members. |
| 334 // TODO(jmesserly): all numbers will have these in dynamic dispatch. | 331 // TODO(jmesserly): all numbers will have these in dynamic dispatch. |
| 335 // We can fix by checking it at dispatch time but we'd need to structure them | 332 // We can fix by checking it at dispatch time but we'd need to structure them |
| 336 // differently. | 333 // differently. |
| 337 | 334 |
| 338 bool get isEven => (this & 1) == 0; | 335 bool get isEven => (this & 1) == 0; |
| 339 | 336 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 } | 393 } |
| 397 if (y.isOdd) { | 394 if (y.isOdd) { |
| 398 var t = x; | 395 var t = x; |
| 399 x = y; | 396 x = y; |
| 400 y = t; | 397 y = t; |
| 401 } | 398 } |
| 402 } | 399 } |
| 403 final bool ac = x.isEven; | 400 final bool ac = x.isEven; |
| 404 int u = x; | 401 int u = x; |
| 405 int v = y; | 402 int v = y; |
| 406 int a = 1, | 403 int a = 1, b = 0, c = 0, d = 1; |
| 407 b = 0, | |
| 408 c = 0, | |
| 409 d = 1; | |
| 410 do { | 404 do { |
| 411 while (u.isEven) { | 405 while (u.isEven) { |
| 412 u ~/= 2; | 406 u ~/= 2; |
| 413 if (ac) { | 407 if (ac) { |
| 414 if (!a.isEven || !b.isEven) { | 408 if (!a.isEven || !b.isEven) { |
| 415 a += y; | 409 a += y; |
| 416 b -= x; | 410 b -= x; |
| 417 } | 411 } |
| 418 a ~/= 2; | 412 a ~/= 2; |
| 419 } else if (!b.isEven) { | 413 } else if (!b.isEven) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 437 if (u >= v) { | 431 if (u >= v) { |
| 438 u -= v; | 432 u -= v; |
| 439 if (ac) a -= c; | 433 if (ac) a -= c; |
| 440 b -= d; | 434 b -= d; |
| 441 } else { | 435 } else { |
| 442 v -= u; | 436 v -= u; |
| 443 if (ac) c -= a; | 437 if (ac) c -= a; |
| 444 d -= b; | 438 d -= b; |
| 445 } | 439 } |
| 446 } while (u != 0); | 440 } while (u != 0); |
| 447 if (!inv) return s*v; | 441 if (!inv) return s * v; |
| 448 if (v != 1) throw new Exception("Not coprime"); | 442 if (v != 1) throw new Exception("Not coprime"); |
| 449 if (d < 0) { | 443 if (d < 0) { |
| 450 d += x; | 444 d += x; |
| 451 if (d < 0) d += x; | 445 if (d < 0) d += x; |
| 452 } else if (d > x) { | 446 } else if (d > x) { |
| 453 d -= x; | 447 d -= x; |
| 454 if (d > x) d -= x; | 448 if (d > x) d -= x; |
| 455 } | 449 } |
| 456 return d; | 450 return d; |
| 457 } | 451 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 i = _ors(i, _shrs(i, 1)); | 515 i = _ors(i, _shrs(i, 1)); |
| 522 i = _ors(i, _shrs(i, 2)); | 516 i = _ors(i, _shrs(i, 2)); |
| 523 i = _ors(i, _shrs(i, 4)); | 517 i = _ors(i, _shrs(i, 4)); |
| 524 i = _ors(i, _shrs(i, 8)); | 518 i = _ors(i, _shrs(i, 8)); |
| 525 i = _shru(_ors(i, _shrs(i, 16)), 0); | 519 i = _shru(_ors(i, _shrs(i, 16)), 0); |
| 526 return i; | 520 return i; |
| 527 } | 521 } |
| 528 | 522 |
| 529 int operator ~() => JS('int', r'(~#) >>> 0', this); | 523 int operator ~() => JS('int', r'(~#) >>> 0', this); |
| 530 } | 524 } |
| OLD | NEW |