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

Side by Side Diff: tool/input_sdk_patch/js_number.dart

Issue 955513008: cleans up sdk patching so we no longer have unresolved names (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 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
« no previous file with comments | « tool/input_sdk_patch/js_names.dart ('k') | tool/input_sdk_patch/js_primitives.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of _interceptors;
6
7 /**
8 * The super interceptor class for [JSInt] and [JSDouble]. The compiler
9 * recognizes this class as an interceptor, and changes references to
10 * [:this:] to actually use the receiver of the method, which is
11 * generated as an extra argument added to each member.
12 *
13 * Note that none of the methods here delegate to a method defined on JSInt or
14 * JSDouble. This is exploited in [tryComputeConstantInterceptor].
15 */
16 class JSNumber extends Interceptor implements num {
17 const JSNumber();
18
19 int compareTo(num b) {
20 if (b is! num) throw new ArgumentError(b);
21 if (this < b) {
22 return -1;
23 } else if (this > b) {
24 return 1;
25 } else if (this == b) {
26 if (this == 0) {
27 bool bIsNegative = b.isNegative;
28 if (isNegative == bIsNegative) return 0;
29 if (isNegative) return -1;
30 return 1;
31 }
32 return 0;
33 } else if (isNaN) {
34 if (b.isNaN) {
35 return 0;
36 }
37 return 1;
38 } else {
39 return -1;
40 }
41 }
42
43 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
44
45 bool get isNaN => JS('bool', r'isNaN(#)', this);
46
47 bool get isInfinite {
48 return JS('bool', r'# == Infinity', this)
49 || JS('bool', r'# == -Infinity', this);
50 }
51
52 bool get isFinite => JS('bool', r'isFinite(#)', this);
53
54 num remainder(num b) {
55 checkNull(b); // TODO(ngeoffray): This is not specified but co19 tests it.
56 if (b is! num) throw new ArgumentError(b);
57 return JS('num', r'# % #', this, b);
58 }
59
60 num abs() => JS('num', r'Math.abs(#)', this);
61
62 num get sign => this > 0 ? 1 : this < 0 ? -1 : this;
63
64 static const int _MIN_INT32 = -0x80000000;
65 static const int _MAX_INT32 = 0x7FFFFFFF;
66
67 int toInt() {
68 if (this >= _MIN_INT32 && this <= _MAX_INT32) {
69 return JS('int', '# | 0', this);
70 }
71 if (JS('bool', r'isFinite(#)', this)) {
72 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
73 }
74 // This is either NaN, Infinity or -Infinity.
75 throw new UnsupportedError(JS("String", "''+#", this));
76 }
77
78 int truncate() => toInt();
79 int ceil() => ceilToDouble().toInt();
80 int floor() => floorToDouble().toInt();
81 int round() => roundToDouble().toInt();
82
83 double ceilToDouble() => JS('num', r'Math.ceil(#)', this);
84
85 double floorToDouble() => JS('num', r'Math.floor(#)', this);
86
87 double roundToDouble() {
88 if (this < 0) {
89 return JS('num', r'-Math.round(-#)', this);
90 } else {
91 return JS('num', r'Math.round(#)', this);
92 }
93 }
94
95 double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
96
97 num clamp(lowerLimit, upperLimit) {
98 if (lowerLimit is! num) throw new ArgumentError(lowerLimit);
99 if (upperLimit is! num) throw new ArgumentError(upperLimit);
100 if (lowerLimit.compareTo(upperLimit) > 0) {
101 throw new ArgumentError(lowerLimit);
102 }
103 if (this.compareTo(lowerLimit) < 0) return lowerLimit;
104 if (this.compareTo(upperLimit) > 0) return upperLimit;
105 return this;
106 }
107
108 // The return type is intentionally omitted to avoid type checker warnings
109 // from assigning JSNumber to double.
110 toDouble() => this;
111
112 String toStringAsFixed(int fractionDigits) {
113 checkInt(fractionDigits);
114 if (fractionDigits < 0 || fractionDigits > 20) {
115 throw new RangeError(fractionDigits);
116 }
117 String result = JS('String', r'#.toFixed(#)', this, fractionDigits);
118 if (this == 0 && isNegative) return "-$result";
119 return result;
120 }
121
122 String toStringAsExponential([int fractionDigits]) {
123 String result;
124 if (fractionDigits != null) {
125 checkInt(fractionDigits);
126 if (fractionDigits < 0 || fractionDigits > 20) {
127 throw new RangeError(fractionDigits);
128 }
129 result = JS('String', r'#.toExponential(#)', this, fractionDigits);
130 } else {
131 result = JS('String', r'#.toExponential()', this);
132 }
133 if (this == 0 && isNegative) return "-$result";
134 return result;
135 }
136
137 String toStringAsPrecision(int precision) {
138 checkInt(precision);
139 if (precision < 1 || precision > 21) {
140 throw new RangeError(precision);
141 }
142 String result = JS('String', r'#.toPrecision(#)',
143 this, precision);
144 if (this == 0 && isNegative) return "-$result";
145 return result;
146 }
147
148 String toRadixString(int radix) {
149 checkInt(radix);
150 if (radix < 2 || radix > 36) throw new RangeError(radix);
151 String result = JS('String', r'#.toString(#)', this, radix);
152 const int rightParenCode = 0x29;
153 if (result.codeUnitAt(result.length - 1) != rightParenCode) {
154 return result;
155 }
156 return _handleIEtoString(result);
157 }
158
159 static String _handleIEtoString(String result) {
160 // Result is probably IE's untraditional format for large numbers,
161 // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
162 var match = JS('List|Null',
163 r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)',
164 result);
165 if (match == null) {
166 // Then we don't know how to handle it at all.
167 throw new UnsupportedError("Unexpected toString result: $result");
168 }
169 String result = JS('String', '#', match[1]);
170 int exponent = JS("int", "+#", match[3]);
171 if (match[2] != null) {
172 result = JS('String', '# + #', result, match[2]);
173 exponent -= JS('int', '#.length', match[2]);
174 }
175 return result + "0" * exponent;
176 }
177
178 // Note: if you change this, also change the function [S].
179 String toString() {
180 if (this == 0 && JS('bool', '(1 / #) < 0', this)) {
181 return '-0.0';
182 } else {
183 return JS('String', r'"" + (#)', this);
184 }
185 }
186
187 int get hashCode => JS('int', '# & 0x1FFFFFFF', this);
188
189 num operator -() => JS('num', r'-#', this);
190
191 num operator +(num other) {
192 if (other is !num) throw new ArgumentError(other);
193 return JS('num', '# + #', this, other);
194 }
195
196 num operator -(num other) {
197 if (other is !num) throw new ArgumentError(other);
198 return JS('num', '# - #', this, other);
199 }
200
201 num operator /(num other) {
202 if (other is !num) throw new ArgumentError(other);
203 return JS('num', '# / #', this, other);
204 }
205
206 num operator *(num other) {
207 if (other is !num) throw new ArgumentError(other);
208 return JS('num', '# * #', this, other);
209 }
210
211 num operator %(num other) {
212 if (other is !num) throw new ArgumentError(other);
213 // Euclidean Modulo.
214 num result = JS('num', r'# % #', this, other);
215 if (result == 0) return 0; // Make sure we don't return -0.0.
216 if (result > 0) return result;
217 if (JS('num', '#', other) < 0) {
218 return result - JS('num', '#', other);
219 } else {
220 return result + JS('num', '#', other);
221 }
222 }
223
224 bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value);
225
226 int operator ~/(num other) {
227 if (false) _tdivFast(other); // Ensure resolution.
228 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) {
229 return JS('int', r'(# / #) | 0', this, other);
230 } else {
231 return _tdivSlow(other);
232 }
233 }
234
235 int _tdivFast(num other) {
236 return _isInt32(this)
237 ? JS('int', r'(# / #) | 0', this, other)
238 : (JS('num', r'# / #', this, other)).toInt();
239 }
240
241 int _tdivSlow(num other) {
242 if (other is !num) throw new ArgumentError(other);
243 return (JS('num', r'# / #', this, other)).toInt();
244 }
245
246 // TODO(ngeoffray): Move the bit operations below to [JSInt] and
247 // make them take an int. Because this will make operations slower,
248 // we define these methods on number for now but we need to decide
249 // the grain at which we do the type checks.
250
251 num operator <<(num other) {
252 if (other is !num) throw new ArgumentError(other);
253 if (JS('num', '#', other) < 0) throw new ArgumentError(other);
254 return _shlPositive(other);
255 }
256
257 num _shlPositive(num other) {
258 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting
259 // by 33 is hence equivalent to a shift by 1.
260 return JS('bool', r'# > 31', other)
261 ? 0
262 : JS('JSUInt32', r'(# << #) >>> 0', this, other);
263 }
264
265 num operator >>(num other) {
266 if (false) _shrReceiverPositive(other);
267 if (other is !num) throw new ArgumentError(other);
268 if (JS('num', '#', other) < 0) throw new ArgumentError(other);
269 return _shrOtherPositive(other);
270 }
271
272 num _shrOtherPositive(num other) {
273 return JS('num', '#', this) > 0
274 ? _shrBothPositive(other)
275 // For negative numbers we just clamp the shift-by amount.
276 // `this` could be negative but not have its 31st bit set.
277 // The ">>" would then shift in 0s instead of 1s. Therefore
278 // we cannot simply return 0xFFFFFFFF.
279 : JS('JSUInt32', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
280 }
281
282 num _shrReceiverPositive(num other) {
283 if (JS('num', '#', other) < 0) throw new ArgumentError(other);
284 return _shrBothPositive(other);
285 }
286
287 num _shrBothPositive(num other) {
288 return JS('bool', r'# > 31', other)
289 // JavaScript only looks at the last 5 bits of the shift-amount. In JS
290 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the
291 // computation when that happens.
292 ? 0
293 // Given that `this` is positive we must not use '>>'. Otherwise a
294 // number that has the 31st bit set would be treated as negative and
295 // shift in ones.
296 : JS('JSUInt32', r'# >>> #', this, other);
297 }
298
299 num operator &(num other) {
300 if (other is !num) throw new ArgumentError(other);
301 return JS('JSUInt32', r'(# & #) >>> 0', this, other);
302 }
303
304 num operator |(num other) {
305 if (other is !num) throw new ArgumentError(other);
306 return JS('JSUInt32', r'(# | #) >>> 0', this, other);
307 }
308
309 num operator ^(num other) {
310 if (other is !num) throw new ArgumentError(other);
311 return JS('JSUInt32', r'(# ^ #) >>> 0', this, other);
312 }
313
314 bool operator <(num other) {
315 if (other is !num) throw new ArgumentError(other);
316 return JS('bool', '# < #', this, other);
317 }
318
319 bool operator >(num other) {
320 if (other is !num) throw new ArgumentError(other);
321 return JS('bool', '# > #', this, other);
322 }
323
324 bool operator <=(num other) {
325 if (other is !num) throw new ArgumentError(other);
326 return JS('bool', '# <= #', this, other);
327 }
328
329 bool operator >=(num other) {
330 if (other is !num) throw new ArgumentError(other);
331 return JS('bool', '# >= #', this, other);
332 }
333
334 Type get runtimeType => num;
335 }
336
337 /**
338 * The interceptor class for [int]s.
339 *
340 * This class implements double since in JavaScript all numbers are doubles, so
341 * while we want to treat `2.0` as an integer for some operations, its
342 * interceptor should answer `true` to `is double`.
343 */
344 class JSInt extends JSNumber implements int, double {
345 const JSInt();
346
347 bool get isEven => (this & 1) == 0;
348
349 bool get isOdd => (this & 1) == 1;
350
351 int toUnsigned(int width) {
352 return this & ((1 << width) - 1);
353 }
354
355 int toSigned(int width) {
356 int signMask = 1 << (width - 1);
357 return (this & (signMask - 1)) - (this & signMask);
358 }
359
360 int get bitLength {
361 int nonneg = this < 0 ? -this - 1 : this;
362 if (nonneg >= 0x100000000) {
363 nonneg = nonneg ~/ 0x100000000;
364 return _bitCount(_spread(nonneg)) + 32;
365 }
366 return _bitCount(_spread(nonneg));
367 }
368
369 // Assumes i is <= 32-bit and unsigned.
370 static int _bitCount(int i) {
371 // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
372
373 // The basic strategy is to use "divide and conquer" to
374 // add pairs (then quads, etc.) of bits together to obtain
375 // sub-counts.
376 //
377 // A straightforward approach would look like:
378 //
379 // i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
380 // i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
381 // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
382 // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
383 // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
384 //
385 // The code below removes unnecessary &'s and uses a
386 // trick to remove one instruction in the first line.
387
388 i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
389 i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
390 i = 0x0F0F0F0F & (i + _shru(i, 4));
391 i += _shru(i, 8);
392 i += _shru(i, 16);
393 return (i & 0x0000003F);
394 }
395
396 static _shru(int value, int shift) => JS('int', '# >>> #', value, shift);
397 static _shrs(int value, int shift) => JS('int', '# >> #', value, shift);
398 static _ors(int a, int b) => JS('int', '# | #', a, b);
399
400 // Assumes i is <= 32-bit
401 static int _spread(int i) {
402 i = _ors(i, _shrs(i, 1));
403 i = _ors(i, _shrs(i, 2));
404 i = _ors(i, _shrs(i, 4));
405 i = _ors(i, _shrs(i, 8));
406 i = _shru(_ors(i, _shrs(i, 16)), 0);
407 return i;
408 }
409
410 Type get runtimeType => int;
411
412 int operator ~() => JS('JSUInt32', r'(~#) >>> 0', this);
413 }
414
415 class JSDouble extends JSNumber implements double {
416 const JSDouble();
417 Type get runtimeType => double;
418 }
419
420 class JSPositiveInt extends JSInt {}
421 class JSUInt32 extends JSPositiveInt {}
422 class JSUInt31 extends JSUInt32 {}
OLDNEW
« no previous file with comments | « tool/input_sdk_patch/js_names.dart ('k') | tool/input_sdk_patch/js_primitives.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698