Chromium Code Reviews| 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 import 'dart:io' show Directory, File; | 8 import 'dart:io' show Directory, File; |
| 9 | 9 |
| 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| (...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 JS.Statement _finishClassMembers(String name, JS.ClassExpression cls, | 549 JS.Statement _finishClassMembers(String name, JS.ClassExpression cls, |
| 550 List<ConstructorDeclaration> ctors, List<FieldDeclaration> staticFields) { | 550 List<ConstructorDeclaration> ctors, List<FieldDeclaration> staticFields) { |
| 551 var body = <JS.Statement>[]; | 551 var body = <JS.Statement>[]; |
| 552 body.add(new JS.ClassDeclaration(cls)); | 552 body.add(new JS.ClassDeclaration(cls)); |
| 553 | 553 |
| 554 // Named constructors | 554 // Named constructors |
| 555 for (ConstructorDeclaration member in ctors) { | 555 for (ConstructorDeclaration member in ctors) { |
| 556 if (member.name != null) { | 556 if (member.name != null) { |
| 557 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ | 557 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ |
| 558 name, | 558 name, |
| 559 js.string(member.name.name, "'") | 559 _jsMemberName(member.name.name, isStatic: true) |
| 560 ])); | 560 ])); |
| 561 } | 561 } |
| 562 } | 562 } |
| 563 | 563 |
| 564 // Static fields | 564 // Static fields |
| 565 var lazyStatics = <VariableDeclaration>[]; | 565 var lazyStatics = <VariableDeclaration>[]; |
| 566 for (FieldDeclaration member in staticFields) { | 566 for (FieldDeclaration member in staticFields) { |
| 567 for (VariableDeclaration field in member.fields.variables) { | 567 for (VariableDeclaration field in member.fields.variables) { |
| 568 var fieldName = field.name.name; | 568 var fieldName = field.name.name; |
| 569 if (field.isConst || _isFieldInitConstant(field)) { | 569 if (field.isConst || _isFieldInitConstant(field)) { |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 845 | 845 |
| 846 @override | 846 @override |
| 847 JS.Method visitMethodDeclaration(MethodDeclaration node) { | 847 JS.Method visitMethodDeclaration(MethodDeclaration node) { |
| 848 if (node.isAbstract || _externalOrNative(node)) { | 848 if (node.isAbstract || _externalOrNative(node)) { |
| 849 return null; | 849 return null; |
| 850 } | 850 } |
| 851 | 851 |
| 852 var params = _visit(node.parameters); | 852 var params = _visit(node.parameters); |
| 853 if (params == null) params = []; | 853 if (params == null) params = []; |
| 854 | 854 |
| 855 return new JS.Method( | 855 return new JS.Method(_jsMemberName(node.name.name, isStatic: node.isStatic), |
| 856 _jsMemberName(node.name.name), new JS.Fun(params, _visit(node.body)), | 856 new JS.Fun(params, _visit(node.body)), |
| 857 isGetter: node.isGetter, | 857 isGetter: node.isGetter, |
| 858 isSetter: node.isSetter, | 858 isSetter: node.isSetter, |
| 859 isStatic: node.isStatic); | 859 isStatic: node.isStatic); |
| 860 } | 860 } |
| 861 | 861 |
| 862 @override | 862 @override |
| 863 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { | 863 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 864 assert(node.parent is CompilationUnit); | 864 assert(node.parent is CompilationUnit); |
| 865 | 865 |
| 866 if (_externalOrNative(node)) return null; | 866 if (_externalOrNative(node)) return null; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 935 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { | 935 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { |
| 936 var e = node.staticElement; | 936 var e = node.staticElement; |
| 937 if (e == null) { | 937 if (e == null) { |
| 938 return js.commentExpression( | 938 return js.commentExpression( |
| 939 'Unimplemented unknown name', new JS.Identifier(node.name)); | 939 'Unimplemented unknown name', new JS.Identifier(node.name)); |
| 940 } | 940 } |
| 941 | 941 |
| 942 var name = node.name; | 942 var name = node.name; |
| 943 var variable = e is PropertyAccessorElement ? e.variable : e; | 943 var variable = e is PropertyAccessorElement ? e.variable : e; |
| 944 | 944 |
| 945 // library member | |
| 945 if (e.enclosingElement is CompilationUnitElement && | 946 if (e.enclosingElement is CompilationUnitElement && |
| 946 (e.library != libraryInfo.library || | 947 (e.library != libraryInfo.library || |
| 947 variable is TopLevelVariableElement && !variable.isConst)) { | 948 variable is TopLevelVariableElement && !variable.isConst)) { |
| 948 return js.call('#.#', [_libraryName(e.library), name]); | 949 return js.call('#.#', [_libraryName(e.library), name]); |
| 949 } else if (currentClass != null && _needsImplicitThis(e)) { | 950 } |
| 951 | |
| 952 // instance member | |
| 953 if (currentClass != null && _needsImplicitThis(e)) { | |
| 950 return js.call('this.#', _jsMemberName(name)); | 954 return js.call('this.#', _jsMemberName(name)); |
| 951 } else if (variable is ConstFieldElementImpl) { | 955 } |
| 956 | |
| 957 // static member | |
| 958 if (e is ExecutableElement && | |
| 959 e.isStatic && | |
| 960 variable.enclosingElement is ClassElement) { | |
| 952 var className = (variable.enclosingElement as ClassElement).name; | 961 var className = (variable.enclosingElement as ClassElement).name; |
| 953 return js.call('#.#', [className, name]); | 962 return js.call('#.#', [className, _jsMemberName(name, isStatic: true)]); |
| 954 } else if (e is ParameterElement && e.isInitializingFormal && e.isPrivate) { | 963 } |
| 964 | |
| 965 // initializing formal parameter, e.g. `Point(this.x)` | |
| 966 if (e is ParameterElement && e.isInitializingFormal && e.isPrivate) { | |
| 955 /// Rename private names so they don't shadow the private field symbol. | 967 /// Rename private names so they don't shadow the private field symbol. |
| 956 /// The renamer would handle this, but it would prefer to rename the | 968 /// The renamer would handle this, but it would prefer to rename the |
| 957 /// temporary used for the private symbol. Instead rename the parameter. | 969 /// temporary used for the private symbol. Instead rename the parameter. |
| 958 return new JSTemporary('${name.substring(1)}'); | 970 return new JSTemporary('${name.substring(1)}'); |
| 959 } else if (_isTemporary(e)) { | |
| 960 return new JSTemporary(e.name); | |
| 961 } | 971 } |
| 972 | |
| 973 if (_isTemporary(e)) return new JSTemporary(e.name); | |
| 974 | |
| 962 return new JS.Identifier(name); | 975 return new JS.Identifier(name); |
| 963 } | 976 } |
| 964 | 977 |
| 965 JS.Expression _emitTypeName(DartType type) { | 978 JS.Expression _emitTypeName(DartType type) { |
| 966 var name = type.name; | 979 var name = type.name; |
| 967 var element = type.element; | 980 var element = type.element; |
| 968 if (name == '') { | 981 if (name == '') { |
| 969 // TODO(jmesserly): remove when we're using coercion reifier. | 982 // TODO(jmesserly): remove when we're using coercion reifier. |
| 970 return _unimplementedCall('Unimplemented type $type'); | 983 return _unimplementedCall('Unimplemented type $type'); |
| 971 } | 984 } |
| (...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1687 @override | 1700 @override |
| 1688 visitPropertyAccess(PropertyAccess node) => | 1701 visitPropertyAccess(PropertyAccess node) => |
| 1689 _visitGet(_getTarget(node), node.propertyName); | 1702 _visitGet(_getTarget(node), node.propertyName); |
| 1690 | 1703 |
| 1691 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 1704 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
| 1692 _visitGet(Expression target, SimpleIdentifier name) { | 1705 _visitGet(Expression target, SimpleIdentifier name) { |
| 1693 if (rules.isDynamicTarget(target)) { | 1706 if (rules.isDynamicTarget(target)) { |
| 1694 return js.call( | 1707 return js.call( |
| 1695 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]); | 1708 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]); |
| 1696 } else { | 1709 } else { |
| 1697 return js.call('#.#', [_visit(target), _jsMemberName(name.name)]); | 1710 var e = name.staticElement; |
| 1711 return js.call('#.#', [ | |
| 1712 _visit(target), | |
| 1713 _jsMemberName(name.name, isStatic: e is ExecutableElement && e.isStatic) | |
| 1714 ]); | |
| 1698 } | 1715 } |
| 1699 } | 1716 } |
| 1700 | 1717 |
| 1701 @override | 1718 @override |
| 1702 visitIndexExpression(IndexExpression node) { | 1719 visitIndexExpression(IndexExpression node) { |
| 1703 var target = _getTarget(node); | 1720 var target = _getTarget(node); |
| 1704 var code; | 1721 var code; |
| 1705 if (rules.isDynamicTarget(target)) { | 1722 if (rules.isDynamicTarget(target)) { |
| 1706 code = 'dart.dindex(#, #)'; | 1723 code = 'dart.dindex(#, #)'; |
| 1707 } else { | 1724 } else { |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2087 /// | 2104 /// |
| 2088 /// This follows the same pattern as EcmaScript 6 Map: | 2105 /// This follows the same pattern as EcmaScript 6 Map: |
| 2089 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> | 2106 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> |
| 2090 /// | 2107 /// |
| 2091 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed | 2108 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed |
| 2092 /// for this transformation to happen, otherwise binary minus is assumed. | 2109 /// for this transformation to happen, otherwise binary minus is assumed. |
| 2093 /// | 2110 /// |
| 2094 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 2111 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
| 2095 /// helper, that checks for null. The user defined method is called '=='. | 2112 /// helper, that checks for null. The user defined method is called '=='. |
| 2096 /// | 2113 /// |
| 2097 JS.Expression _jsMemberName(String name, {bool unary: false}) { | 2114 JS.Expression _jsMemberName(String name, |
| 2115 {bool unary: false, bool isStatic: false}) { | |
| 2098 if (name.startsWith('_')) { | 2116 if (name.startsWith('_')) { |
| 2099 if (_privateNames.add(name)) _pendingPrivateNames.add(name); | 2117 if (_privateNames.add(name)) _pendingPrivateNames.add(name); |
| 2100 return new JSTemporary(name); | 2118 return new JSTemporary(name); |
| 2101 } | 2119 } |
| 2102 if (name == '[]') { | 2120 if (name == '[]') { |
| 2103 name = 'get'; | 2121 name = 'get'; |
| 2104 } else if (name == '[]=') { | 2122 } else if (name == '[]=') { |
| 2105 name = 'set'; | 2123 name = 'set'; |
| 2106 } else if (unary && name == '-') { | 2124 } else if (unary && name == '-') { |
| 2107 name = 'unary-'; | 2125 name = 'unary-'; |
| 2126 } else if (isStatic && invalidJSStaticMethodName(name)) { | |
| 2127 // Choose an string name. Use an invalid identifier so it won't conflict | |
| 2128 // with any valid member names. | |
| 2129 name = '::$name'; | |
|
Jacob
2015/03/27 21:18:25
FIXME: we should pick something more sane than ::$
| |
| 2108 } | 2130 } |
| 2109 return _propertyName(name); | 2131 return _propertyName(name); |
| 2110 } | 2132 } |
| 2111 | 2133 |
| 2112 bool _externalOrNative(node) => | 2134 bool _externalOrNative(node) => |
| 2113 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 2135 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 2114 | 2136 |
| 2115 FunctionBody _functionBody(node) => | 2137 FunctionBody _functionBody(node) => |
| 2116 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 2138 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| 2117 | 2139 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2180 if (parent is Label) return; | 2202 if (parent is Label) return; |
| 2181 | 2203 |
| 2182 if (node.inSetterContext() && node.staticElement == _variable) { | 2204 if (node.inSetterContext() && node.staticElement == _variable) { |
| 2183 _potentiallyMutated = true; | 2205 _potentiallyMutated = true; |
| 2184 } | 2206 } |
| 2185 } | 2207 } |
| 2186 } | 2208 } |
| 2187 | 2209 |
| 2188 /// This is a workaround for V8 arrow function bindings being not yet | 2210 /// This is a workaround for V8 arrow function bindings being not yet |
| 2189 /// implemented. See issue #43 | 2211 /// implemented. See issue #43 |
| 2212 // TODO(jmesserly): cleaner to handle this workaround on the JS side. | |
| 2190 class _BindThisVisitor extends RecursiveAstVisitor { | 2213 class _BindThisVisitor extends RecursiveAstVisitor { |
| 2191 static _BindThisVisitor _instance = new _BindThisVisitor(); | 2214 static _BindThisVisitor _instance = new _BindThisVisitor(); |
| 2192 bool _bindThis = false; | 2215 bool _bindThis = false; |
| 2193 | 2216 |
| 2194 @override | 2217 @override |
| 2195 visitSimpleIdentifier(SimpleIdentifier node) { | 2218 visitSimpleIdentifier(SimpleIdentifier node) { |
| 2196 if (JSCodegenVisitor._needsImplicitThis(node.staticElement)) { | 2219 if (JSCodegenVisitor._needsImplicitThis(node.staticElement)) { |
| 2197 _bindThis = true; | 2220 _bindThis = true; |
| 2198 } | 2221 } |
| 2199 } | 2222 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2329 | 2352 |
| 2330 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2353 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2331 printer.mark(_location(node.end)); | 2354 printer.mark(_location(node.end)); |
| 2332 } | 2355 } |
| 2333 | 2356 |
| 2334 String _getIdentifier(AstNode node) { | 2357 String _getIdentifier(AstNode node) { |
| 2335 if (node is SimpleIdentifier) return node.name; | 2358 if (node is SimpleIdentifier) return node.name; |
| 2336 return null; | 2359 return null; |
| 2337 } | 2360 } |
| 2338 } | 2361 } |
| OLD | NEW |