OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
6 | 6 |
7 import 'dart:collection' show HashSet, HashMap; | 7 import 'dart:collection' show HashSet, HashMap; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
(...skipping 1259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 code = 'dart.$DCALL(#, #)'; | 1270 code = 'dart.$DCALL(#, #)'; |
1271 } else { | 1271 } else { |
1272 code = '#(#)'; | 1272 code = '#(#)'; |
1273 } | 1273 } |
1274 return js.call( | 1274 return js.call( |
1275 code, [_visit(node.methodName), _visit(node.argumentList)]); | 1275 code, [_visit(node.methodName), _visit(node.argumentList)]); |
1276 } | 1276 } |
1277 | 1277 |
1278 var type = getStaticType(target); | 1278 var type = getStaticType(target); |
1279 var name = node.methodName.name; | 1279 var name = node.methodName.name; |
1280 var memberName = _emitMemberName(name, type: type); | 1280 var element = node.methodName.staticElement; |
| 1281 bool isStatic = element is ExecutableElement && element.isStatic; |
| 1282 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); |
1281 | 1283 |
1282 if (rules.isDynamicTarget(target)) { | 1284 if (rules.isDynamicTarget(target)) { |
1283 code = 'dart.$DSEND(#, #, #)'; | 1285 code = 'dart.$DSEND(#, #, #)'; |
1284 } else if (rules.isDynamicCall(node.methodName)) { | 1286 } else if (rules.isDynamicCall(node.methodName)) { |
1285 // This is a dynamic call to a statically know target. For example: | 1287 // This is a dynamic call to a statically know target. For example: |
1286 // class Foo { Function bar; } | 1288 // class Foo { Function bar; } |
1287 // new Foo().bar(); // dynamic call | 1289 // new Foo().bar(); // dynamic call |
1288 code = 'dart.$DCALL(#.#, #)'; | 1290 code = 'dart.$DCALL(#.#, #)'; |
1289 } else if (_requiresStaticDispatch(target, name)) { | 1291 } else if (_requiresStaticDispatch(target, name)) { |
1290 assert(rules.objectMembers[name] is FunctionType); | 1292 assert(rules.objectMembers[name] is FunctionType); |
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1897 if (!type.isObject && | 1899 if (!type.isObject && |
1898 !_isJSBuiltinType(type) && | 1900 !_isJSBuiltinType(type) && |
1899 _isNonNullableExpression(target)) { | 1901 _isNonNullableExpression(target)) { |
1900 return false; | 1902 return false; |
1901 } | 1903 } |
1902 return true; | 1904 return true; |
1903 } | 1905 } |
1904 | 1906 |
1905 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 1907 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
1906 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { | 1908 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { |
1907 var name = _emitMemberName(memberId.name, type: getStaticType(target)); | 1909 var member = memberId.staticElement; |
| 1910 bool isStatic = member is ExecutableElement && member.isStatic; |
| 1911 var name = _emitMemberName(memberId.name, |
| 1912 type: getStaticType(target), isStatic: isStatic); |
1908 if (rules.isDynamicTarget(target)) { | 1913 if (rules.isDynamicTarget(target)) { |
1909 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]); | 1914 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]); |
1910 } | 1915 } |
1911 | 1916 |
1912 String code; | 1917 String code; |
1913 var member = memberId.staticElement; | |
1914 if (member != null && member is MethodElement) { | 1918 if (member != null && member is MethodElement) { |
1915 // Tear-off methods: explicitly bind it. | 1919 // Tear-off methods: explicitly bind it. |
1916 if (_requiresStaticDispatch(target, memberId.name)) { | 1920 if (_requiresStaticDispatch(target, memberId.name)) { |
1917 return js.call('dart.#.bind(#)', [name, _visit(target)]); | 1921 return js.call('dart.#.bind(#)', [name, _visit(target)]); |
1918 } | 1922 } |
1919 if (isStateless(target, target)) { | 1923 if (isStateless(target, target)) { |
1920 return js.call('#.#.bind(#)', [_visit(target), name, _visit(target)]); | 1924 return js.call('#.#.bind(#)', [_visit(target), name, _visit(target)]); |
1921 } | 1925 } |
1922 code = 'dart.bind(#, #)'; | 1926 code = 'dart.bind(#, #)'; |
1923 } else if (_requiresStaticDispatch(target, memberId.name)) { | 1927 } else if (_requiresStaticDispatch(target, memberId.name)) { |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2351 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/Map> | 2355 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/Map> |
2352 /// | 2356 /// |
2353 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed | 2357 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed |
2354 /// for this transformation to happen, otherwise binary minus is assumed. | 2358 /// for this transformation to happen, otherwise binary minus is assumed. |
2355 /// | 2359 /// |
2356 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 2360 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
2357 /// helper, that checks for null. The user defined method is called '=='. | 2361 /// helper, that checks for null. The user defined method is called '=='. |
2358 /// | 2362 /// |
2359 JS.Expression _emitMemberName(String name, | 2363 JS.Expression _emitMemberName(String name, |
2360 {DartType type, bool unary: false, bool isStatic: false}) { | 2364 {DartType type, bool unary: false, bool isStatic: false}) { |
| 2365 |
| 2366 // Static methods skip most of the rename steps. |
| 2367 if (isStatic) { |
| 2368 if (invalidJSStaticMethodName(name)) { |
| 2369 // Choose an string name. Use an invalid identifier so it won't conflict |
| 2370 // with any valid member names. |
| 2371 // TODO(jmesserly): this works around the problem, but I'm pretty sure w
e |
| 2372 // don't need it, as static methods seemed to work. The only concrete |
| 2373 // issue we saw was in the defineNamedConstructor helper function. |
| 2374 name = '$name*'; |
| 2375 } |
| 2376 return _propertyName(name); |
| 2377 } |
| 2378 |
2361 if (name.startsWith('_')) { | 2379 if (name.startsWith('_')) { |
2362 return _privateNames.putIfAbsent( | 2380 return _privateNames.putIfAbsent( |
2363 name, () => _initSymbol(new JSTemporary(name))); | 2381 name, () => _initSymbol(new JSTemporary(name))); |
2364 } | 2382 } |
2365 | 2383 |
2366 // Check for extension method: | 2384 // Check for extension method: |
2367 var extLibrary = _findExtensionLibrary(name, type); | 2385 var extLibrary = _findExtensionLibrary(name, type); |
2368 | 2386 |
2369 if (name == '[]') { | 2387 if (name == '[]') { |
2370 name = 'get'; | 2388 name = 'get'; |
2371 } else if (name == '[]=') { | 2389 } else if (name == '[]=') { |
2372 name = 'set'; | 2390 name = 'set'; |
2373 } else if (name == '-' && unary) { | 2391 } else if (name == '-' && unary) { |
2374 name = 'unary-'; | 2392 name = 'unary-'; |
2375 } | 2393 } |
2376 | 2394 |
2377 if (isStatic && invalidJSStaticMethodName(name)) { | |
2378 // Choose an string name. Use an invalid identifier so it won't conflict | |
2379 // with any valid member names. | |
2380 // TODO(jmesserly): this works around the problem, but I'm pretty sure we | |
2381 // don't need it, as static methods seemed to work. The only concrete | |
2382 // issue we saw was in the defineNamedConstructor helper function. | |
2383 name = '$name*'; | |
2384 } | |
2385 | |
2386 if (extLibrary != null) { | 2395 if (extLibrary != null) { |
2387 return _extensionMethodName(name, extLibrary); | 2396 return _extensionMethodName(name, extLibrary); |
2388 } | 2397 } |
2389 | 2398 |
2390 return _propertyName(name); | 2399 return _propertyName(name); |
2391 } | 2400 } |
2392 | 2401 |
2393 LibraryElement _findExtensionLibrary(String name, DartType type) { | 2402 LibraryElement _findExtensionLibrary(String name, DartType type) { |
2394 if (type is! InterfaceType) return null; | 2403 if (type is! InterfaceType) return null; |
2395 | 2404 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2511 // TODO(jmesserly): validate the library. See issue #135. | 2520 // TODO(jmesserly): validate the library. See issue #135. |
2512 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 2521 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; |
2513 | 2522 |
2514 bool _isJsPeerInterface(DartObjectImpl value) => | 2523 bool _isJsPeerInterface(DartObjectImpl value) => |
2515 value.type.name == 'JsPeerInterface'; | 2524 value.type.name == 'JsPeerInterface'; |
2516 | 2525 |
2517 // TODO(jacobr): we would like to do something like the following | 2526 // TODO(jacobr): we would like to do something like the following |
2518 // but we don't have summary support yet. | 2527 // but we don't have summary support yet. |
2519 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 2528 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
2520 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 2529 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
OLD | NEW |