| 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 #library('dart:_js_helper'); | 5 #library('dart:_js_helper'); |
| 6 | 6 |
| 7 #import('dart:collection'); | 7 #import('dart:collection'); |
| 8 | 8 |
| 9 #source('constant_map.dart'); | 9 #source('constant_map.dart'); |
| 10 #source('native_helper.dart'); | 10 #source('native_helper.dart'); |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 | 295 |
| 296 index$slow(var a, var index) { | 296 index$slow(var a, var index) { |
| 297 if (a is String || isJsArray(a)) { | 297 if (a is String || isJsArray(a)) { |
| 298 if (index is !int) { | 298 if (index is !int) { |
| 299 if (index is !num) throw new ArgumentError(index); | 299 if (index is !num) throw new ArgumentError(index); |
| 300 if (!identical(index.truncate(), index)) throw new ArgumentError(index); | 300 if (!identical(index.truncate(), index)) throw new ArgumentError(index); |
| 301 } | 301 } |
| 302 if (index < 0 || index >= a.length) { | 302 if (index < 0 || index >= a.length) { |
| 303 throw new RangeError.value(index); | 303 throw new RangeError.value(index); |
| 304 } | 304 } |
| 305 return JS('Object', r'#[#]', a, index); | 305 return JS('', r'#[#]', a, index); |
| 306 } | 306 } |
| 307 return UNINTERCEPTED(a[index]); | 307 return UNINTERCEPTED(a[index]); |
| 308 } | 308 } |
| 309 | 309 |
| 310 void indexSet$slow(var a, var index, var value) { | 310 void indexSet$slow(var a, var index, var value) { |
| 311 if (isJsArray(a)) { | 311 if (isJsArray(a)) { |
| 312 if (index is !int) { | 312 if (index is !int) { |
| 313 throw new ArgumentError(index); | 313 throw new ArgumentError(index); |
| 314 } | 314 } |
| 315 if (index < 0 || index >= a.length) { | 315 if (index < 0 || index >= a.length) { |
| 316 throw new RangeError.value(index); | 316 throw new RangeError.value(index); |
| 317 } | 317 } |
| 318 checkMutable(a, 'indexed set'); | 318 checkMutable(a, 'indexed set'); |
| 319 JS('Object', r'#[#] = #', a, index, value); | 319 JS('void', r'#[#] = #', a, index, value); |
| 320 return; | 320 return; |
| 321 } | 321 } |
| 322 UNINTERCEPTED(a[index] = value); | 322 UNINTERCEPTED(a[index] = value); |
| 323 } | 323 } |
| 324 | 324 |
| 325 checkMutable(list, reason) { | 325 checkMutable(list, reason) { |
| 326 if (JS('bool', r'!!(#.immutable$list)', list)) { | 326 if (JS('bool', r'!!(#.immutable$list)', list)) { |
| 327 throw new UnsupportedError(reason); | 327 throw new UnsupportedError(reason); |
| 328 } | 328 } |
| 329 } | 329 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 340 return res; | 340 return res; |
| 341 } | 341 } |
| 342 | 342 |
| 343 class ListIterator<T> implements Iterator<T> { | 343 class ListIterator<T> implements Iterator<T> { |
| 344 int i; | 344 int i; |
| 345 List<T> list; | 345 List<T> list; |
| 346 ListIterator(List<T> this.list) : i = 0; | 346 ListIterator(List<T> this.list) : i = 0; |
| 347 bool get hasNext => i < JS('int', r'#.length', list); | 347 bool get hasNext => i < JS('int', r'#.length', list); |
| 348 T next() { | 348 T next() { |
| 349 if (!hasNext) throw new StateError("No more elements"); | 349 if (!hasNext) throw new StateError("No more elements"); |
| 350 var value = JS('Object', r'#[#]', list, i); | 350 var value = JS('', r'#[#]', list, i); |
| 351 i += 1; | 351 i += 1; |
| 352 return value; | 352 return value; |
| 353 } | 353 } |
| 354 } | 354 } |
| 355 | 355 |
| 356 createInvocationMirror(name, internalName, type, arguments, argumentNames) => | 356 createInvocationMirror(name, internalName, type, arguments, argumentNames) => |
| 357 new JSInvocationMirror(name, internalName, type, arguments, argumentNames); | 357 new JSInvocationMirror(name, internalName, type, arguments, argumentNames); |
| 358 | 358 |
| 359 class JSInvocationMirror implements InvocationMirror { | 359 class JSInvocationMirror implements InvocationMirror { |
| 360 static const METHOD = 0; | 360 static const METHOD = 0; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 } | 457 } |
| 458 | 458 |
| 459 // This is somewhat nasty, but we don't want to drag in a bunch of | 459 // This is somewhat nasty, but we don't want to drag in a bunch of |
| 460 // dependencies to handle a situation that cannot happen. So we | 460 // dependencies to handle a situation that cannot happen. So we |
| 461 // avoid using Dart [:throw:] and Dart [toString]. | 461 // avoid using Dart [:throw:] and Dart [toString]. |
| 462 JS('void', "throw 'Unable to print message: ' + String(#)", string); | 462 JS('void', "throw 'Unable to print message: ' + String(#)", string); |
| 463 } | 463 } |
| 464 | 464 |
| 465 static int parseInt(String string) { | 465 static int parseInt(String string) { |
| 466 checkString(string); | 466 checkString(string); |
| 467 var match = JS('List', | 467 var match = JS('=List', |
| 468 r'/^\s*[+-]?(?:0(x)[a-f0-9]+|\d+)\s*$/i.exec(#)', | 468 r'/^\s*[+-]?(?:0(x)[a-f0-9]+|\d+)\s*$/i.exec(#)', |
| 469 string); | 469 string); |
| 470 if (match == null) { | 470 if (match == null) { |
| 471 throw new FormatException(string); | 471 throw new FormatException(string); |
| 472 } | 472 } |
| 473 var base = 10; | 473 var base = 10; |
| 474 if (match[1] != null) base = 16; | 474 if (match[1] != null) base = 16; |
| 475 var result = JS('num', r'parseInt(#, #)', string, base); | 475 var result = JS('num', r'parseInt(#, #)', string, base); |
| 476 if (result.isNaN) throw new FormatException(string); | 476 if (result.isNaN) throw new FormatException(string); |
| 477 return result; | 477 return result; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 if (identical(name.charCodeAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(
1); | 515 if (identical(name.charCodeAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(
1); |
| 516 return name; | 516 return name; |
| 517 } | 517 } |
| 518 | 518 |
| 519 static String objectToString(Object object) { | 519 static String objectToString(Object object) { |
| 520 String name = objectTypeName(object); | 520 String name = objectTypeName(object); |
| 521 return "Instance of '$name'"; | 521 return "Instance of '$name'"; |
| 522 } | 522 } |
| 523 | 523 |
| 524 static List newList(length) { | 524 static List newList(length) { |
| 525 if (length == null) return JS('Object', r'new Array()'); | 525 // TODO(sra): For good concrete type analysis we need the JS-type to |
| 526 // specifically name the JavaScript Array implementation. 'List' matches |
| 527 // all the dart:html types that implement List<T>. |
| 528 if (length == null) return JS('=List', r'new Array()'); |
| 526 if ((length is !int) || (length < 0)) { | 529 if ((length is !int) || (length < 0)) { |
| 527 throw new ArgumentError(length); | 530 throw new ArgumentError(length); |
| 528 } | 531 } |
| 529 var result = JS('Object', r'new Array(#)', length); | 532 var result = JS('=List', r'new Array(#)', length); |
| 530 JS('void', r'#.fixed$length = #', result, true); | 533 JS('void', r'#.fixed$length = #', result, true); |
| 531 return result; | 534 return result; |
| 532 } | 535 } |
| 533 | 536 |
| 534 static num dateNow() => JS('num', r'Date.now()'); | 537 static num dateNow() => JS('num', r'Date.now()'); |
| 535 | 538 |
| 536 static String stringFromCharCodes(charCodes) { | 539 static String stringFromCharCodes(charCodes) { |
| 537 for (var i in charCodes) { | 540 for (var i in charCodes) { |
| 538 if (i is !int) throw new ArgumentError(i); | 541 if (i is !int) throw new ArgumentError(i); |
| 539 } | 542 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 if (value.isNaN || | 579 if (value.isNaN || |
| 577 value < -MAX_MILLISECONDS_SINCE_EPOCH || | 580 value < -MAX_MILLISECONDS_SINCE_EPOCH || |
| 578 value > MAX_MILLISECONDS_SINCE_EPOCH) { | 581 value > MAX_MILLISECONDS_SINCE_EPOCH) { |
| 579 throw new ArgumentError(); | 582 throw new ArgumentError(); |
| 580 } | 583 } |
| 581 if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc); | 584 if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc); |
| 582 return value; | 585 return value; |
| 583 } | 586 } |
| 584 | 587 |
| 585 static patchUpY2K(value, years, isUtc) { | 588 static patchUpY2K(value, years, isUtc) { |
| 586 var date = JS('Object', r'new Date(#)', value); | 589 var date = JS('', r'new Date(#)', value); |
| 587 if (isUtc) { | 590 if (isUtc) { |
| 588 JS('num', r'#.setUTCFullYear(#)', date, years); | 591 JS('num', r'#.setUTCFullYear(#)', date, years); |
| 589 } else { | 592 } else { |
| 590 JS('num', r'#.setFullYear(#)', date, years); | 593 JS('num', r'#.setFullYear(#)', date, years); |
| 591 } | 594 } |
| 592 return JS('num', r'#.valueOf()', date); | 595 return JS('num', r'#.valueOf()', date); |
| 593 } | 596 } |
| 594 | 597 |
| 595 // Lazily keep a JS Date stored in the JS object. | 598 // Lazily keep a JS Date stored in the JS object. |
| 596 static lazyAsJsDate(receiver) { | 599 static lazyAsJsDate(receiver) { |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 | 891 |
| 889 /** | 892 /** |
| 890 * Throws the given Dart object as an exception by wrapping it in a | 893 * Throws the given Dart object as an exception by wrapping it in a |
| 891 * proper JavaScript error object and then throwing that. That gives | 894 * proper JavaScript error object and then throwing that. That gives |
| 892 * us a reasonable stack trace on most JavaScript implementations. The | 895 * us a reasonable stack trace on most JavaScript implementations. The |
| 893 * code in [unwrapException] deals with getting the original Dart | 896 * code in [unwrapException] deals with getting the original Dart |
| 894 * object out of the wrapper again. | 897 * object out of the wrapper again. |
| 895 */ | 898 */ |
| 896 $throw(ex) { | 899 $throw(ex) { |
| 897 if (ex == null) ex = const NullPointerException(); | 900 if (ex == null) ex = const NullPointerException(); |
| 898 var jsError = JS('Object', r'new Error()'); | 901 var jsError = JS('var', r'new Error()'); |
| 899 JS('void', r'#.name = #', jsError, ex); | 902 JS('void', r'#.name = #', jsError, ex); |
| 900 JS('void', r'#.description = #', jsError, ex); | 903 JS('void', r'#.description = #', jsError, ex); |
| 901 JS('void', r'#.dartException = #', jsError, ex); | 904 JS('void', r'#.dartException = #', jsError, ex); |
| 902 JS('void', r'#.toString = #', jsError, | 905 JS('void', r'#.toString = #', jsError, |
| 903 DART_CLOSURE_TO_JS(toStringWrapper)); | 906 DART_CLOSURE_TO_JS(toStringWrapper)); |
| 904 JS('void', r'throw #', jsError); | 907 JS('void', r'throw #', jsError); |
| 905 } | 908 } |
| 906 | 909 |
| 907 /** | 910 /** |
| 908 * This method is installed as JavaScript toString method on exception | 911 * This method is installed as JavaScript toString method on exception |
| 909 * objects in [$throw]. So JavaScript 'this' binds to an instance of | 912 * objects in [$throw]. So JavaScript 'this' binds to an instance of |
| 910 * JavaScript Error to which we have added a property 'dartException' | 913 * JavaScript Error to which we have added a property 'dartException' |
| 911 * which holds a Dart object. | 914 * which holds a Dart object. |
| 912 */ | 915 */ |
| 913 toStringWrapper() => JS('Object', r'this.dartException').toString(); | 916 toStringWrapper() => JS('', r'this.dartException').toString(); |
| 914 | 917 |
| 915 makeLiteralListConst(list) { | 918 makeLiteralListConst(list) { |
| 916 JS('bool', r'#.immutable$list = #', list, true); | 919 JS('bool', r'#.immutable$list = #', list, true); |
| 917 JS('bool', r'#.fixed$length = #', list, true); | 920 JS('bool', r'#.fixed$length = #', list, true); |
| 918 return list; | 921 return list; |
| 919 } | 922 } |
| 920 | 923 |
| 921 throwRuntimeError(message) { | 924 throwRuntimeError(message) { |
| 922 throw new RuntimeError(message); | 925 throw new RuntimeError(message); |
| 923 } | 926 } |
| 924 | 927 |
| 925 throwAbstractClassInstantiationError(className) { | 928 throwAbstractClassInstantiationError(className) { |
| 926 throw new AbstractClassInstantiationError(className); | 929 throw new AbstractClassInstantiationError(className); |
| 927 } | 930 } |
| 928 | 931 |
| 929 /** | 932 /** |
| 930 * Called from catch blocks in generated code to extract the Dart | 933 * Called from catch blocks in generated code to extract the Dart |
| 931 * exception from the thrown value. The thrown value may have been | 934 * exception from the thrown value. The thrown value may have been |
| 932 * created by [$throw] or it may be a 'native' JS exception. | 935 * created by [$throw] or it may be a 'native' JS exception. |
| 933 * | 936 * |
| 934 * Some native exceptions are mapped to new Dart instances, others are | 937 * Some native exceptions are mapped to new Dart instances, others are |
| 935 * returned unmodified. | 938 * returned unmodified. |
| 936 */ | 939 */ |
| 937 unwrapException(ex) { | 940 unwrapException(ex) { |
| 938 // Note that we are checking if the object has the property. If it | 941 // Note that we are checking if the object has the property. If it |
| 939 // has, it could be set to null if the thrown value is null. | 942 // has, it could be set to null if the thrown value is null. |
| 940 if (JS('bool', r'"dartException" in #', ex)) { | 943 if (JS('bool', r'"dartException" in #', ex)) { |
| 941 return JS('Object', r'#.dartException', ex); | 944 return JS('', r'#.dartException', ex); |
| 942 } | 945 } |
| 943 | 946 |
| 944 // Grab hold of the exception message. This field is available on | 947 // Grab hold of the exception message. This field is available on |
| 945 // all supported browsers. | 948 // all supported browsers. |
| 946 var message = JS('var', r'#.message', ex); | 949 var message = JS('var', r'#.message', ex); |
| 947 | 950 |
| 948 if (JS('bool', r'# instanceof TypeError', ex)) { | 951 if (JS('bool', r'# instanceof TypeError', ex)) { |
| 949 // The type and arguments fields are Chrome specific but they | 952 // The type and arguments fields are Chrome specific but they |
| 950 // allow us to get very detailed information about what kind of | 953 // allow us to get very detailed information about what kind of |
| 951 // exception occurred. | 954 // exception occurred. |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1103 */ | 1106 */ |
| 1104 getFallThroughError() => const FallThroughErrorImplementation(); | 1107 getFallThroughError() => const FallThroughErrorImplementation(); |
| 1105 | 1108 |
| 1106 /** | 1109 /** |
| 1107 * Represents the type Dynamic. The compiler treats this specially. | 1110 * Represents the type Dynamic. The compiler treats this specially. |
| 1108 */ | 1111 */ |
| 1109 abstract class Dynamic_ { | 1112 abstract class Dynamic_ { |
| 1110 } | 1113 } |
| 1111 | 1114 |
| 1112 /** | 1115 /** |
| 1116 * A metadata annotation describing the types instantiated by a native element. |
| 1117 */ |
| 1118 class Creates { |
| 1119 final String types; |
| 1120 const Creates(this.types); |
| 1121 } |
| 1122 |
| 1123 /** |
| 1124 * A metadata annotation describing the types returned or yielded by a native |
| 1125 * element. |
| 1126 */ |
| 1127 class Returns { |
| 1128 final String types; |
| 1129 const Returns(this.types); |
| 1130 } |
| 1131 |
| 1132 /** |
| 1113 * Represents the type of Null. The compiler treats this specially. | 1133 * Represents the type of Null. The compiler treats this specially. |
| 1114 * TODO(lrn): Null should be defined in core. It's a class, like int. | 1134 * TODO(lrn): Null should be defined in core. It's a class, like int. |
| 1115 * It just happens to act differently in assignability tests and, | 1135 * It just happens to act differently in assignability tests and, |
| 1116 * like int, can't be extended or implemented. | 1136 * like int, can't be extended or implemented. |
| 1117 */ | 1137 */ |
| 1118 class Null { | 1138 class Null { |
| 1119 factory Null() { | 1139 factory Null() { |
| 1120 throw new UnsupportedError('new Null()'); | 1140 throw new UnsupportedError('new Null()'); |
| 1121 } | 1141 } |
| 1122 } | 1142 } |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1473 Type getOrCreateCachedRuntimeType(String key) { | 1493 Type getOrCreateCachedRuntimeType(String key) { |
| 1474 Type result = JS('Type', r'#[#]', runtimeTypeCache, key); | 1494 Type result = JS('Type', r'#[#]', runtimeTypeCache, key); |
| 1475 if (result == null) { | 1495 if (result == null) { |
| 1476 result = new TypeImpl(key); | 1496 result = new TypeImpl(key); |
| 1477 JS('var', r'#[#] = #', runtimeTypeCache, key, result); | 1497 JS('var', r'#[#] = #', runtimeTypeCache, key, result); |
| 1478 } | 1498 } |
| 1479 return result; | 1499 return result; |
| 1480 } | 1500 } |
| 1481 | 1501 |
| 1482 String getRuntimeTypeString(var object) { | 1502 String getRuntimeTypeString(var object) { |
| 1483 var typeInfo = JS('Object', r'#.builtin$typeInfo', object); | 1503 var typeInfo = JS('var', r'#.builtin$typeInfo', object); |
| 1484 return JS('String', r'#.runtimeType', typeInfo); | 1504 return JS('String', r'#.runtimeType', typeInfo); |
| 1485 } | 1505 } |
| OLD | NEW |