| 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 _js_helper; | 5 library _js_helper; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 part 'constant_map.dart'; | 9 part 'constant_map.dart'; |
| 10 part 'native_helper.dart'; | 10 part 'native_helper.dart'; |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 throw new UnsupportedError(reason); | 332 throw new UnsupportedError(reason); |
| 333 } | 333 } |
| 334 } | 334 } |
| 335 | 335 |
| 336 String S(value) { | 336 String S(value) { |
| 337 var res = value.toString(); | 337 var res = value.toString(); |
| 338 if (res is !String) throw new ArgumentError(value); | 338 if (res is !String) throw new ArgumentError(value); |
| 339 return res; | 339 return res; |
| 340 } | 340 } |
| 341 | 341 |
| 342 class ListIterator<T> implements Iterator<T> { | |
| 343 int i; | |
| 344 List<T> list; | |
| 345 ListIterator(List<T> this.list) : i = 0; | |
| 346 bool get hasNext => i < JS('int', r'#.length', list); | |
| 347 T next() { | |
| 348 if (!hasNext) throw new StateError("No more elements"); | |
| 349 var value = JS('', r'#[#]', list, i); | |
| 350 i += 1; | |
| 351 return value; | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 createInvocationMirror(name, internalName, type, arguments, argumentNames) => | 342 createInvocationMirror(name, internalName, type, arguments, argumentNames) => |
| 356 new JSInvocationMirror(name, internalName, type, arguments, argumentNames); | 343 new JSInvocationMirror(name, internalName, type, arguments, argumentNames); |
| 357 | 344 |
| 358 class JSInvocationMirror implements InvocationMirror { | 345 class JSInvocationMirror implements InvocationMirror { |
| 359 static const METHOD = 0; | 346 static const METHOD = 0; |
| 360 static const GETTER = 1; | 347 static const GETTER = 1; |
| 361 static const SETTER = 2; | 348 static const SETTER = 2; |
| 362 | 349 |
| 363 final String memberName; | 350 final String memberName; |
| 364 final String _internalName; | 351 final String _internalName; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 JS('void', r'print(#)', string); | 441 JS('void', r'print(#)', string); |
| 455 return; | 442 return; |
| 456 } | 443 } |
| 457 | 444 |
| 458 // This is somewhat nasty, but we don't want to drag in a bunch of | 445 // This is somewhat nasty, but we don't want to drag in a bunch of |
| 459 // dependencies to handle a situation that cannot happen. So we | 446 // dependencies to handle a situation that cannot happen. So we |
| 460 // avoid using Dart [:throw:] and Dart [toString]. | 447 // avoid using Dart [:throw:] and Dart [toString]. |
| 461 JS('void', "throw 'Unable to print message: ' + String(#)", string); | 448 JS('void', "throw 'Unable to print message: ' + String(#)", string); |
| 462 } | 449 } |
| 463 | 450 |
| 464 static int parseInt(String string) { | 451 static void _throwFormatException(String string) { |
| 465 checkString(string); | 452 throw new FormatException(string); |
| 466 var match = JS('=List|Null', | |
| 467 r'/^\s*[+-]?(?:0(x)[a-f0-9]+|\d+)\s*$/i.exec(#)', | |
| 468 string); | |
| 469 if (match == null) { | |
| 470 throw new FormatException(string); | |
| 471 } | |
| 472 var base = 10; | |
| 473 if (match[1] != null) base = 16; | |
| 474 var result = JS('num', r'parseInt(#, #)', string, base); | |
| 475 if (result.isNaN) throw new FormatException(string); | |
| 476 return result; | |
| 477 } | 453 } |
| 478 | 454 |
| 479 static double parseDouble(String string) { | 455 static int parseInt(String source, |
| 480 checkString(string); | 456 int radix, |
| 457 int handleError(String source)) { |
| 458 if (handleError == null) handleError = _throwFormatException; |
| 459 |
| 460 checkString(source); |
| 461 var match = JS('=List|Null', |
| 462 r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(#)', |
| 463 source); |
| 464 int digitsIndex = 1; |
| 465 int hexIndex = 2; |
| 466 int decimalIndex = 3; |
| 467 int nonDecimalHexIndex = 4; |
| 468 if (radix == null) { |
| 469 radix = 10; |
| 470 if (match != null) { |
| 471 if (match[hexIndex] != null) { |
| 472 // Cannot fail because we know that the digits are all hex. |
| 473 return JS('num', r'parseInt(#, 16)', source); |
| 474 } |
| 475 if (match[decimalIndex] != null) { |
| 476 // Cannot fail because we know that the digits are all decimal. |
| 477 return JS('num', r'parseInt(#, 10)', source); |
| 478 } |
| 479 return handleError(source); |
| 480 } |
| 481 } else { |
| 482 if (radix is! int) throw new ArgumentError("Radix is not an integer"); |
| 483 if (radix < 2 || radix > 36) { |
| 484 throw new RangeError("Radix $radix not in range 2..36"); |
| 485 } |
| 486 if (match != null) { |
| 487 if (radix == 10 && match[decimalIndex] != null) { |
| 488 // Cannot fail because we know that the digits are all decimal. |
| 489 return JS('num', r'parseInt(#, 10)', source); |
| 490 } |
| 491 if (radix < 10 || match[decimalIndex] == null) { |
| 492 // We know that the characters must be ASCII as otherwise the |
| 493 // regexp wouldn't have matched. Calling toLowerCase is thus |
| 494 // guaranteed to be a safe operation. If it wasn't ASCII, then |
| 495 // "İ" would become "i", and we would accept it for radices greater |
| 496 // than 18. |
| 497 int maxCharCode; |
| 498 if (radix <= 10) { |
| 499 // Allow all digits less than the radix. For example 0, 1, 2 for |
| 500 // radix 3. |
| 501 // "0".charCodeAt(0) + radix - 1; |
| 502 maxCharCode = 0x30 + radix - 1; |
| 503 } else { |
| 504 // Characters are located after the digits in ASCII. Therefore we |
| 505 // only check for the character code. The regexp above made already |
| 506 // sure that the string does not contain anything but digits or |
| 507 // characters. |
| 508 // "0".charCodeAt(0) + radix - 1; |
| 509 maxCharCode = 0x61 + radix - 10 - 1; |
| 510 } |
| 511 String digitsPart = match[digitsIndex].toLowerCase(); |
| 512 for (int i = 0; i < digitsPart.length; i++) { |
| 513 if (digitsPart.charCodeAt(i) > maxCharCode) { |
| 514 return handleError(source); |
| 515 } |
| 516 } |
| 517 } |
| 518 } |
| 519 } |
| 520 if (match == null) return handleError(source); |
| 521 return JS('num', r'parseInt(#, #)', source, radix); |
| 522 } |
| 523 |
| 524 static double parseDouble(String source, int handleError(String source)) { |
| 525 checkString(source); |
| 526 if (handleError == null) handleError = _throwFormatException; |
| 481 // Notice that JS parseFloat accepts garbage at the end of the string. | 527 // Notice that JS parseFloat accepts garbage at the end of the string. |
| 482 // Accept, ignoring leading and trailing whitespace: | 528 // Accept only: |
| 483 // - NaN | 529 // - NaN |
| 484 // - [+/-]Infinity | 530 // - [+/-]Infinity |
| 485 // - a Dart double literal | 531 // - a Dart double literal |
| 532 // We do not allow leading or trailing whitespace. |
| 486 if (!JS('bool', | 533 if (!JS('bool', |
| 487 r'/^\s*(?:NaN|[+-]?(?:Infinity|' | 534 r'/^\s*(?:NaN|[+-]?(?:Infinity|' |
| 488 r'(?:\.\d+|\d+(?:\.\d+)?)(?:[eE][+-]?\d+)?))\s*$/.test(#)', | 535 r'(?:\.\d+|\d+(?:\.\d+)?)(?:[eE][+-]?\d+)?))\s*$/.test(#)', |
| 489 string)) { | 536 source)) { |
| 490 throw new FormatException(string); | 537 return handleError(source); |
| 491 } | 538 } |
| 492 var result = JS('num', r'parseFloat(#)', string); | 539 var result = JS('num', r'parseFloat(#)', source); |
| 493 if (result.isNaN && string != 'NaN') { | 540 if (result.isNaN && source != 'NaN') { |
| 494 throw new FormatException(string); | 541 return handleError(source); |
| 495 } | 542 } |
| 496 return result; | 543 return result; |
| 497 } | 544 } |
| 498 | 545 |
| 499 /** [: r"$".charCodeAt(0) :] */ | 546 /** [: r"$".charCodeAt(0) :] */ |
| 500 static const int DOLLAR_CHAR_VALUE = 36; | 547 static const int DOLLAR_CHAR_VALUE = 36; |
| 501 | 548 |
| 502 static String objectTypeName(Object object) { | 549 static String objectTypeName(Object object) { |
| 503 String name = constructorNameFallback(object); | 550 String name = constructorNameFallback(object); |
| 504 if (name == 'Object') { | 551 if (name == 'Object') { |
| 505 // Try to decompile the constructor by turning it into a string | 552 // Try to decompile the constructor by turning it into a string |
| 506 // and get the name out of that. If the decompiled name is a | 553 // and get the name out of that. If the decompiled name is a |
| 507 // string, we use that instead of the very generic 'Object'. | 554 // string, we use that instead of the very generic 'Object'. |
| 508 var decompiled = JS('var', r'#.match(/^\s*function\s*(\S*)\s*\(/)[1]', | 555 var decompiled = JS('var', r'#.match(/^\s*function\s*(\S*)\s*\(/)[1]', |
| 509 JS('var', r'String(#.constructor)', object)); | 556 JS('var', r'String(#.constructor)', object)); |
| 510 if (decompiled is String) name = decompiled; | 557 if (decompiled is String) name = decompiled; |
| 511 } | 558 } |
| 512 // TODO(kasperl): If the namer gave us a fresh global name, we may | 559 // TODO(kasperl): If the namer gave us a fresh global name, we may |
| 513 // want to remove the numeric suffix that makes it unique too. | 560 // want to remove the numeric suffix that makes it unique too. |
| 514 if (identical(name.charCodeAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(
1); | 561 if (identical(name.charCodeAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(
1); |
| 515 return name; | 562 return name; |
| 516 } | 563 } |
| 517 | 564 |
| 518 static String objectToString(Object object) { | 565 static String objectToString(Object object) { |
| 519 String name = objectTypeName(object); | 566 String name = objectTypeName(object); |
| 520 return "Instance of '$name'"; | 567 return "Instance of '$name'"; |
| 521 } | 568 } |
| 522 | 569 |
| 523 static List newList(length) { | 570 static List newGrowableList(length) { |
| 524 // TODO(sra): For good concrete type analysis we need the JS-type to | 571 // TODO(sra): For good concrete type analysis we need the JS-type to |
| 525 // specifically name the JavaScript Array implementation. 'List' matches | 572 // specifically name the JavaScript Array implementation. 'List' matches |
| 526 // all the dart:html types that implement List<T>. | 573 // all the dart:html types that implement List<T>. |
| 527 if (length == null) return JS('=List', r'new Array()'); | 574 return JS('Object', r'new Array(#)', length); |
| 528 if ((length is !int) || (length < 0)) { | 575 } |
| 529 throw new ArgumentError(length); | 576 |
| 530 } | 577 static List newFixedList(length) { |
| 578 // TODO(sra): For good concrete type analysis we need the JS-type to |
| 579 // specifically name the JavaScript Array implementation. 'List' matches |
| 580 // all the dart:html types that implement List<T>. |
| 531 var result = JS('=List', r'new Array(#)', length); | 581 var result = JS('=List', r'new Array(#)', length); |
| 532 JS('void', r'#.fixed$length = #', result, true); | 582 JS('void', r'#.fixed$length = #', result, true); |
| 533 return result; | 583 return result; |
| 534 } | 584 } |
| 535 | 585 |
| 536 static num dateNow() => JS('num', r'Date.now()'); | 586 static num dateNow() => JS('num', r'Date.now()'); |
| 537 | 587 |
| 538 static num numMicroseconds() { | 588 static num numMicroseconds() { |
| 539 if (JS('bool', 'typeof window != "undefined" && window !== null')) { | 589 if (JS('bool', 'typeof window != "undefined" && window !== null')) { |
| 540 var performance = JS('var', 'window.performance'); | 590 var performance = JS('var', 'window.performance'); |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 } | 898 } |
| 849 | 899 |
| 850 checkString(value) { | 900 checkString(value) { |
| 851 if (value is !String) { | 901 if (value is !String) { |
| 852 throw new ArgumentError(value); | 902 throw new ArgumentError(value); |
| 853 } | 903 } |
| 854 return value; | 904 return value; |
| 855 } | 905 } |
| 856 | 906 |
| 857 class MathNatives { | 907 class MathNatives { |
| 858 static int parseInt(str) { | |
| 859 checkString(str); | |
| 860 if (!JS('bool', | |
| 861 r'/^\s*[+-]?(?:0[xX][abcdefABCDEF0-9]+|\d+)\s*$/.test(#)', | |
| 862 str)) { | |
| 863 throw new FormatException(str); | |
| 864 } | |
| 865 var trimmed = str.trim(); | |
| 866 var base = 10;; | |
| 867 if ((trimmed.length > 2 && (trimmed[1] == 'x' || trimmed[1] == 'X')) || | |
| 868 (trimmed.length > 3 && (trimmed[2] == 'x' || trimmed[2] == 'X'))) { | |
| 869 base = 16; | |
| 870 } | |
| 871 var ret = JS('num', r'parseInt(#, #)', trimmed, base); | |
| 872 if (ret.isNaN) throw new FormatException(str); | |
| 873 return ret; | |
| 874 } | |
| 875 | |
| 876 static double parseDouble(String str) { | |
| 877 checkString(str); | |
| 878 var ret = JS('num', r'parseFloat(#)', str); | |
| 879 if (ret == 0 && (str.startsWith("0x") || str.startsWith("0X"))) { | |
| 880 // TODO(ahe): This is unspecified, but tested by co19. | |
| 881 ret = JS('num', r'parseInt(#)', str); | |
| 882 } | |
| 883 if (ret.isNaN && str != 'NaN' && str != '-NaN') { | |
| 884 throw new FormatException(str); | |
| 885 } | |
| 886 return ret; | |
| 887 } | |
| 888 | |
| 889 static double sqrt(num value) | 908 static double sqrt(num value) |
| 890 => JS('double', r'Math.sqrt(#)', checkNum(value)); | 909 => JS('double', r'Math.sqrt(#)', checkNum(value)); |
| 891 | 910 |
| 892 static double sin(num value) | 911 static double sin(num value) |
| 893 => JS('double', r'Math.sin(#)', checkNum(value)); | 912 => JS('double', r'Math.sin(#)', checkNum(value)); |
| 894 | 913 |
| 895 static double cos(num value) | 914 static double cos(num value) |
| 896 => JS('double', r'Math.cos(#)', checkNum(value)); | 915 => JS('double', r'Math.cos(#)', checkNum(value)); |
| 897 | 916 |
| 898 static double tan(num value) | 917 static double tan(num value) |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1077 StackTrace(this.stack); | 1096 StackTrace(this.stack); |
| 1078 String toString() => stack != null ? stack : ''; | 1097 String toString() => stack != null ? stack : ''; |
| 1079 } | 1098 } |
| 1080 | 1099 |
| 1081 | 1100 |
| 1082 /** | 1101 /** |
| 1083 * Called by generated code to build a map literal. [keyValuePairs] is | 1102 * Called by generated code to build a map literal. [keyValuePairs] is |
| 1084 * a list of key, value, key, value, ..., etc. | 1103 * a list of key, value, key, value, ..., etc. |
| 1085 */ | 1104 */ |
| 1086 makeLiteralMap(List keyValuePairs) { | 1105 makeLiteralMap(List keyValuePairs) { |
| 1087 Iterator iterator = keyValuePairs.iterator(); | 1106 Iterator iterator = keyValuePairs.iterator; |
| 1088 Map result = new LinkedHashMap(); | 1107 Map result = new LinkedHashMap(); |
| 1089 while (iterator.hasNext) { | 1108 while (iterator.moveNext()) { |
| 1090 String key = iterator.next(); | 1109 String key = iterator.current; |
| 1091 var value = iterator.next(); | 1110 iterator.moveNext(); |
| 1111 var value = iterator.current; |
| 1092 result[key] = value; | 1112 result[key] = value; |
| 1093 } | 1113 } |
| 1094 return result; | 1114 return result; |
| 1095 } | 1115 } |
| 1096 | 1116 |
| 1097 invokeClosure(Function closure, | 1117 invokeClosure(Function closure, |
| 1098 var isolate, | 1118 var isolate, |
| 1099 int numberOfArguments, | 1119 int numberOfArguments, |
| 1100 var arg1, | 1120 var arg1, |
| 1101 var arg2) { | 1121 var arg2) { |
| (...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1708 if (len != t.length) return false; | 1728 if (len != t.length) return false; |
| 1709 for (int i = 1; i < len; i++) { | 1729 for (int i = 1; i < len; i++) { |
| 1710 if (!isSubtype(s[i], t[i])) { | 1730 if (!isSubtype(s[i], t[i])) { |
| 1711 return false; | 1731 return false; |
| 1712 } | 1732 } |
| 1713 } | 1733 } |
| 1714 return true; | 1734 return true; |
| 1715 } | 1735 } |
| 1716 | 1736 |
| 1717 createRuntimeType(String name) => new TypeImpl(name); | 1737 createRuntimeType(String name) => new TypeImpl(name); |
| OLD | NEW |