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 |