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

Side by Side Diff: frog/corejs.dart

Issue 9408001: Throw NoSuchMethod or IllegalArgument on bad operators or bad arguments to (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/language/language.status » ('j') | 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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** 5 /**
6 * Generates JS helpers for dart:core. This used to be in a file "core.js". 6 * Generates JS helpers for dart:core. This used to be in a file "core.js".
7 * Having them in Dart code means we can easily control which are generated. 7 * Having them in Dart code means we can easily control which are generated.
8 */ 8 */
9 // TODO(jmesserly): one idea to make this cleaner: put these as private "native" 9 // TODO(jmesserly): one idea to make this cleaner: put these as private "native"
10 // methods somewhere in a library that we import. This would be rather elegant 10 // methods somewhere in a library that we import. This would be rather elegant
(...skipping 18 matching lines...) Expand all
29 bool _generatedInherits = false; 29 bool _generatedInherits = false;
30 bool _generatedDefProp = false; 30 bool _generatedDefProp = false;
31 31
32 32
33 Map<String, String> _usedOperators; 33 Map<String, String> _usedOperators;
34 34
35 CodeWriter writer; 35 CodeWriter writer;
36 36
37 CoreJs(): _usedOperators = {}, writer = new CodeWriter(); 37 CoreJs(): _usedOperators = {}, writer = new CodeWriter();
38 38
39 void markCorelibTypeUsed(String typeName) {
40 world.gen.markTypeUsed(world.corelib.types[typeName]);
41 }
42
39 /** 43 /**
40 * Generates the special operator method, e.g. $add. 44 * Generates the special operator method, e.g. $add.
41 * We want to do $add(x, y) instead of x.$add(y) so it doesn't box. 45 * We want to do $add(x, y) instead of x.$add(y) so it doesn't box.
42 * Same idea for the other methods. 46 * Same idea for the other methods.
43 */ 47 */
44 void useOperator(String name) { 48 void useOperator(String name) {
45 if (_usedOperators[name] != null) return; 49 if (_usedOperators[name] != null) return;
46 50
51 if (name != ':ne' && name != ':eq') {
52 // TODO(jimhug): Only do this once!
53 markCorelibTypeUsed('NoSuchMethodException');
54 }
55 if (name != ':bit_not' && name != ':negate') {
56 // TODO(jimhug): Only do this once!
57 markCorelibTypeUsed('IllegalArgumentException');
58 }
59
47 var code; 60 var code;
48 switch (name) { 61 switch (name) {
49 case ':ne': 62 case ':ne':
50 code = _NE_FUNCTION; 63 code = _NE_FUNCTION;
51 break; 64 break;
52 65
53 case ':eq': 66 case ':eq':
54 ensureDefProp(); 67 ensureDefProp();
55 code = _EQ_FUNCTION; 68 code = _EQ_FUNCTION;
56 break; 69 break;
57 70
58 case ':bit_not': 71 case ':bit_not':
59 code = _BIT_NOT_FUNCTION; 72 code = _BIT_NOT_FUNCTION;
60 break; 73 break;
61 74
62 case ':negate': 75 case ':negate':
63 code = _NEGATE_FUNCTION; 76 code = _NEGATE_FUNCTION;
64 break; 77 break;
65 78
66 case ':add': 79 case ':add':
67 code = _ADD_FUNCTION; 80 code = _ADD_FUNCTION;
68 break; 81 break;
69 82
70 case ':truncdiv': 83 case ':truncdiv':
71 useThrow = true; 84 useThrow = true;
72 // TODO(jimhug): Only do this once! 85 // TODO(jimhug): Only do this once!
73 world.gen.markTypeUsed( 86 markCorelibTypeUsed('IntegerDivisionByZeroException');
74 world.corelib.types['IntegerDivisionByZeroException']);
75 code = _TRUNCDIV_FUNCTION; 87 code = _TRUNCDIV_FUNCTION;
76 break; 88 break;
77 89
78 case ':mod': 90 case ':mod':
79 code = _MOD_FUNCTION; 91 code = _MOD_FUNCTION;
80 break; 92 break;
81 93
82 default: 94 default:
83 // All of the other helpers are generated the same way 95 // All of the other helpers are generated the same way
84 var op = TokenKind.rawOperatorFromMethod(name); 96 var op = TokenKind.rawOperatorFromMethod(name);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 if (useNotNullBool) { 150 if (useNotNullBool) {
139 useThrow = true; 151 useThrow = true;
140 w.writeln(_NOTNULL_BOOL_FUNCTION); 152 w.writeln(_NOTNULL_BOOL_FUNCTION);
141 } 153 }
142 154
143 if (useThrow) { 155 if (useThrow) {
144 w.writeln(_THROW_FUNCTION); 156 w.writeln(_THROW_FUNCTION);
145 } 157 }
146 158
147 if (useIndex) { 159 if (useIndex) {
160 markCorelibTypeUsed('NoSuchMethodException');
148 ensureDefProp(); 161 ensureDefProp();
149 w.writeln(options.disableBoundsChecks ? 162 w.writeln(options.disableBoundsChecks ?
150 _INDEX_OPERATORS : _CHECKED_INDEX_OPERATORS); 163 _INDEX_OPERATORS : _CHECKED_INDEX_OPERATORS);
151 } 164 }
152 165
153 if (useSetIndex) { 166 if (useSetIndex) {
167 markCorelibTypeUsed('NoSuchMethodException');
154 ensureDefProp(); 168 ensureDefProp();
155 w.writeln(options.disableBoundsChecks ? 169 w.writeln(options.disableBoundsChecks ?
156 _SETINDEX_OPERATORS : _CHECKED_SETINDEX_OPERATORS); 170 _SETINDEX_OPERATORS : _CHECKED_SETINDEX_OPERATORS);
157 } 171 }
158 172
159 if (useIsolates) { 173 if (useIsolates) {
160 if (useWrap0) { 174 if (useWrap0) {
161 w.writeln(_WRAP_CALL0_FUNCTION); 175 w.writeln(_WRAP_CALL0_FUNCTION);
162 } 176 }
163 if (useWrap1) { 177 if (useWrap1) {
(...skipping 24 matching lines...) Expand all
188 'Object.prototype.\$typeNameOf);'); 202 'Object.prototype.\$typeNameOf);');
189 } 203 }
190 } 204 }
191 } 205 }
192 206
193 207
194 /** Snippet for `$ne`. */ 208 /** Snippet for `$ne`. */
195 final String _NE_FUNCTION = @""" 209 final String _NE_FUNCTION = @"""
196 function $ne(x, y) { 210 function $ne(x, y) {
197 if (x == null) return y != null; 211 if (x == null) return y != null;
198 return (typeof(x) == 'number' && typeof(y) == 'number') || 212 return (typeof(x) != 'object') ? x !== y : !x.$eq(y);
199 (typeof(x) == 'boolean' && typeof(y) == 'boolean') ||
200 (typeof(x) == 'string' && typeof(y) == 'string')
201 ? x != y : !x.$eq(y);
202 }"""; 213 }""";
203 214
204 /** Snippet for `$eq`. */ 215 /** Snippet for `$eq`. */
205 final String _EQ_FUNCTION = @""" 216 final String _EQ_FUNCTION = @"""
206 function $eq(x, y) { 217 function $eq(x, y) {
207 if (x == null) return y == null; 218 if (x == null) return y == null;
208 return (typeof(x) == 'number' && typeof(y) == 'number') || 219 return (typeof(x) != 'object') ? x === y : x.$eq(y);
209 (typeof(x) == 'boolean' && typeof(y) == 'boolean') ||
210 (typeof(x) == 'string' && typeof(y) == 'string')
211 ? x == y : x.$eq(y);
212 } 220 }
213 // TODO(jimhug): Should this or should it not match equals? 221 // TODO(jimhug): Should this or should it not match equals?
214 $defProp(Object.prototype, '$eq', function(other) { 222 $defProp(Object.prototype, '$eq', function(other) {
215 return this === other; 223 return this === other;
216 });"""; 224 });""";
217 225
218 /** Snippet for `$bit_not`. */ 226 /** Snippet for `$bit_not`. */
219 final String _BIT_NOT_FUNCTION = @""" 227 final String _BIT_NOT_FUNCTION = @"""
220 function $bit_not(x) { 228 function $bit_not(x) {
221 return (typeof(x) == 'number') ? ~x : x.$bit_not(); 229 if (typeof(x) == 'number') return ~x;
230 if (typeof(x) == 'object') return x.$bit_not();
231 $throw(new NoSuchMethodException(x, "operator ~", []));
222 }"""; 232 }""";
223 233
224 /** Snippet for `$negate`. */ 234 /** Snippet for `$negate`. */
225 final String _NEGATE_FUNCTION = @""" 235 final String _NEGATE_FUNCTION = @"""
226 function $negate(x) { 236 function $negate(x) {
227 return (typeof(x) == 'number') ? -x : x.$negate(); 237 if (typeof(x) == 'number') return -x;
238 if (typeof(x) == 'object') return x.$negate();
239 $throw(new NoSuchMethodException(x, "operator negate", []));
228 }"""; 240 }""";
229 241
230 /** Snippet for `$add`. This relies on JS's string "+" to match Dart's. */ 242 /** Snippet for `$add`. This relies on JS's string "+" to match Dart's. */
231 final String _ADD_FUNCTION = @""" 243 final String _ADD_FUNCTION = @"""
244 function $add$complex(x, y) {
245 if (typeof(x) == 'number') {
246 $throw(new IllegalArgumentException(y));
247 } else if (typeof(x) == 'string') {
248 var str = (y == null) ? 'null' : y.toString();
249 if (typeof(str) != 'string') {
250 throw new Error("calling toString() on right hand operand of operator " +
251 "+ did not return a String");
252 }
253 return x + str;
254 } else if (typeof(x) == 'object') {
255 return x.$add(y);
256 } else {
257 $throw(new NoSuchMethodException(x, "operator +", [y]));
258 }
259 }
260
232 function $add(x, y) { 261 function $add(x, y) {
233 return ((typeof(x) == 'number' && typeof(y) == 'number') || 262 if (typeof(x) == 'number' && typeof(y) == 'number') return x + y;
234 (typeof(x) == 'string')) 263 return $add$complex(x, y);
235 ? x + y : x.$add(y);
236 }"""; 264 }""";
237 265
238 /** Snippet for `$truncdiv`. This uses `$throw`. */ 266 /** Snippet for `$truncdiv`. This uses `$throw`. */
239 final String _TRUNCDIV_FUNCTION = @""" 267 final String _TRUNCDIV_FUNCTION = @"""
240 function $truncdiv(x, y) { 268 function $truncdiv(x, y) {
241 if (typeof(x) == 'number' && typeof(y) == 'number') { 269 if (typeof(x) == 'number') {
242 if (y == 0) $throw(new IntegerDivisionByZeroException()); 270 if (typeof(y) == 'number') {
243 var tmp = x / y; 271 if (y == 0) $throw(new IntegerDivisionByZeroException());
244 return (tmp < 0) ? Math.ceil(tmp) : Math.floor(tmp); 272 var tmp = x / y;
273 return (tmp < 0) ? Math.ceil(tmp) : Math.floor(tmp);
274 } else {
275 $throw(new IllegalArgumentException(y));
276 }
277 } else if (typeof(x) == 'object') {
278 return x.$truncdiv(y);
245 } else { 279 } else {
246 return x.$truncdiv(y); 280 $throw(new NoSuchMethodException(x, "operator ~/", [y]));
247 } 281 }
248 }"""; 282 }""";
249 283
250 /** Snippet for `$mod`. */ 284 /** Snippet for `$mod`. */
251 final String _MOD_FUNCTION = @""" 285 final String _MOD_FUNCTION = @"""
252 function $mod(x, y) { 286 function $mod(x, y) {
253 if (typeof(x) == 'number' && typeof(y) == 'number') { 287 if (typeof(x) == 'number') {
254 var result = x % y; 288 if (typeof(y) == 'number') {
255 if (result == 0) { 289 var result = x % y;
256 return 0; // Make sure we don't return -0.0. 290 if (result == 0) {
257 } else if (result < 0) { 291 return 0; // Make sure we don't return -0.0.
258 if (y < 0) { 292 } else if (result < 0) {
259 return result - y; 293 if (y < 0) {
260 } else { 294 return result - y;
261 return result + y; 295 } else {
296 return result + y;
297 }
262 } 298 }
299 return result;
300 } else {
301 $throw(new IllegalArgumentException(y));
263 } 302 }
264 return result; 303 } else if (typeof(x) == 'object') {
304 return x.$mod(y);
265 } else { 305 } else {
266 return x.$mod(y); 306 $throw(new NoSuchMethodException(x, "operator %", [y]));
267 } 307 }
268 }"""; 308 }""";
269 309
270 /** Code snippet for all other operators. */ 310 /** Code snippet for all other operators. */
271 String _otherOperator(String jsname, String op) { 311 String _otherOperator(String jsname, String op) {
272 return """ 312 return """
313 function $jsname\$complex(x, y) {
314 if (typeof(x) == 'number') {
315 \$throw(new IllegalArgumentException(y));
316 } else if (typeof(x) == 'object') {
317 return x.$jsname(y);
318 } else {
319 \$throw(new NoSuchMethodException(x, "operator $op", [y]));
320 }
321 }
273 function $jsname(x, y) { 322 function $jsname(x, y) {
274 return (typeof(x) == 'number' && typeof(y) == 'number') 323 if (typeof(x) == 'number' && typeof(y) == 'number') return x $op y;
275 ? x $op y : x.$jsname(y); 324 return $jsname\$complex(x, y);
276 }"""; 325 }""";
277 } 326 }
278 327
279 /** 328 /**
280 * Snippet for `$dynamic`. Usage: 329 * Snippet for `$dynamic`. Usage:
281 * $dynamic(name).SomeTypeName = ... method ...; 330 * $dynamic(name).SomeTypeName = ... method ...;
282 * $dynamic(name).Object = ... noSuchMethod ...; 331 * $dynamic(name).Object = ... noSuchMethod ...;
283 */ 332 */
284 final String _DYNAMIC_FUNCTION = @""" 333 final String _DYNAMIC_FUNCTION = @"""
285 function $dynamic(name) { 334 function $dynamic(name) {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 // to get the right errors - at least in checked mode (once we have that). 465 // to get the right errors - at least in checked mode (once we have that).
417 // TODO(jmesserly): do perf analysis, figure out if this is worth it and 466 // TODO(jmesserly): do perf analysis, figure out if this is worth it and
418 // what the cost of $index $setindex is on all browsers 467 // what the cost of $index $setindex is on all browsers
419 468
420 // Performance of Object.prototype methods can go down because there are 469 // Performance of Object.prototype methods can go down because there are
421 // so many of them. Instead, first time we hit it, put it on the derived 470 // so many of them. Instead, first time we hit it, put it on the derived
422 // prototype. TODO(jmesserly): make this go away by handling index more 471 // prototype. TODO(jmesserly): make this go away by handling index more
423 // like a normal method. 472 // like a normal method.
424 final String _INDEX_OPERATORS = @""" 473 final String _INDEX_OPERATORS = @"""
425 $defProp(Object.prototype, '$index', function(i) { 474 $defProp(Object.prototype, '$index', function(i) {
426 var proto = Object.getPrototypeOf(this); 475 $throw(new NoSuchMethodException(this, "operator []", [i]));
427 if (proto !== Object) {
428 proto.$index = function(i) { return this[i]; }
429 }
430 return this[i];
431 }); 476 });
432 $defProp(Array.prototype, '$index', function(i) { 477 $defProp(Array.prototype, '$index', function(i) {
433 return this[i]; 478 return this[i];
434 }); 479 });
435 $defProp(String.prototype, '$index', function(i) { 480 $defProp(String.prototype, '$index', function(i) {
436 return this[i]; 481 return this[i];
437 });"""; 482 });""";
438 483
439 final String _CHECKED_INDEX_OPERATORS = @""" 484 final String _CHECKED_INDEX_OPERATORS = @"""
440 $defProp(Object.prototype, '$index', function(i) { 485 $defProp(Object.prototype, '$index', function(i) {
441 var proto = Object.getPrototypeOf(this); 486 $throw(new NoSuchMethodException(this, "operator []", [i]));
442 if (proto !== Object) {
443 proto.$index = function(i) { return this[i]; }
444 }
445 return this[i];
446 }); 487 });
447 $defProp(Array.prototype, '$index', function(index) { 488 $defProp(Array.prototype, '$index', function(index) {
448 var i = index | 0; 489 var i = index | 0;
449 if (i !== index) { 490 if (i !== index) {
450 throw new IllegalArgumentException('index is not int'); 491 throw new IllegalArgumentException('index is not int');
451 } else if (i < 0 || i >= this.length) { 492 } else if (i < 0 || i >= this.length) {
452 throw new IndexOutOfRangeException(index); 493 throw new IndexOutOfRangeException(index);
453 } 494 }
454 return this[i]; 495 return this[i];
455 }); 496 });
456 $defProp(String.prototype, '$index', function(i) { 497 $defProp(String.prototype, '$index', function(i) {
457 return this[i]; 498 return this[i];
458 });"""; 499 });""";
459 500
460 501
461 502
462 /** Snippet for `$setindex` in Object, Array, and String. */ 503 /** Snippet for `$setindex` in Object, Array, and String. */
463 final String _SETINDEX_OPERATORS = @""" 504 final String _SETINDEX_OPERATORS = @"""
464 $defProp(Object.prototype, '$setindex', function(i, value) { 505 $defProp(Object.prototype, '$setindex', function(i, value) {
465 var proto = Object.getPrototypeOf(this); 506 $throw(new NoSuchMethodException(this, "operator []=", [i, value]));
466 if (proto !== Object) {
467 proto.$setindex = function(i, value) { return this[i] = value; }
468 }
469 return this[i] = value;
470 }); 507 });
471 $defProp(Array.prototype, '$setindex', 508 $defProp(Array.prototype, '$setindex',
472 function(i, value) { return this[i] = value; });"""; 509 function(i, value) { return this[i] = value; });""";
473 510
474 final String _CHECKED_SETINDEX_OPERATORS = @""" 511 final String _CHECKED_SETINDEX_OPERATORS = @"""
475 $defProp(Object.prototype, '$setindex', function(i, value) { 512 $defProp(Object.prototype, '$setindex', function(i, value) {
476 var proto = Object.getPrototypeOf(this); 513 $throw(new NoSuchMethodException(this, "operator []=", [i, value]));
477 if (proto !== Object) {
478 proto.$setindex = function(i, value) { return this[i] = value; }
479 }
480 return this[i] = value;
481 }); 514 });
482 $defProp(Array.prototype, '$setindex', function(index, value) { 515 $defProp(Array.prototype, '$setindex', function(index, value) {
483 var i = index | 0; 516 var i = index | 0;
484 if (i !== index) { 517 if (i !== index) {
485 throw new IllegalArgumentException('index is not int'); 518 throw new IllegalArgumentException('index is not int');
486 } else if (i < 0 || i >= this.length) { 519 } else if (i < 0 || i >= this.length) {
487 throw new IndexOutOfRangeException(index); 520 throw new IndexOutOfRangeException(index);
488 } 521 }
489 return this[i] = value; 522 return this[i] = value;
490 });"""; 523 });""";
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 558
526 /** Snippet for `$wrap_call$1`, in case it was not necessary. */ 559 /** Snippet for `$wrap_call$1`, in case it was not necessary. */
527 final String _EMPTY_WRAP_CALL1_FUNCTION = 560 final String _EMPTY_WRAP_CALL1_FUNCTION =
528 @"function $wrap_call$1(fn) { return fn; }"; 561 @"function $wrap_call$1(fn) { return fn; }";
529 562
530 /** Snippet that initializes the isolates state. */ 563 /** Snippet that initializes the isolates state. */
531 final String _ISOLATE_INIT_CODE = @""" 564 final String _ISOLATE_INIT_CODE = @"""
532 var $globalThis = this; 565 var $globalThis = this;
533 var $globals = null; 566 var $globals = null;
534 var $globalState = null;"""; 567 var $globalState = null;""";
OLDNEW
« no previous file with comments | « no previous file | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698