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 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 5 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
6 | 6 |
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
8 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/src/generated/constant.dart'; | 9 import 'package:analyzer/src/generated/constant.dart'; |
10 import 'package:analyzer/src/generated/element.dart'; | 10 import 'package:analyzer/src/generated/element.dart'; |
(...skipping 945 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
956 var params = | 956 var params = |
957 _emitFormalParameterList(node.parameters, allowDestructuring: false); | 957 _emitFormalParameterList(node.parameters, allowDestructuring: false); |
958 | 958 |
959 var fun = js.call('function(#) { return $newKeyword #(#); }', | 959 var fun = js.call('function(#) { return $newKeyword #(#); }', |
960 [params, _visit(redirect), params]) as JS.Fun; | 960 [params, _visit(redirect), params]) as JS.Fun; |
961 return annotate( | 961 return annotate( |
962 new JS.Method(name, fun, isStatic: true)..sourceInformation = node, | 962 new JS.Method(name, fun, isStatic: true)..sourceInformation = node, |
963 node.element); | 963 node.element); |
964 } | 964 } |
965 | 965 |
| 966 // For const constructors we need to ensure default values are |
| 967 // available for use by top-level constant initializers. |
| 968 ClassDeclaration cls = node.parent; |
| 969 if (node.constKeyword != null) _loader.startTopLevel(cls.element); |
| 970 var params = _emitFormalParameterList(node.parameters); |
| 971 if (node.constKeyword != null) _loader.finishTopLevel(cls.element); |
| 972 |
966 // Factory constructors are essentially static methods. | 973 // Factory constructors are essentially static methods. |
967 if (node.factoryKeyword != null) { | 974 if (node.factoryKeyword != null) { |
968 var body = <JS.Statement>[]; | 975 var body = <JS.Statement>[]; |
969 var init = _emitArgumentInitializers(node, constructor: true); | 976 var init = _emitArgumentInitializers(node, constructor: true); |
970 if (init != null) body.add(init); | 977 if (init != null) body.add(init); |
971 body.add(_visit(node.body)); | 978 body.add(_visit(node.body)); |
972 var fun = new JS.Fun( | 979 var fun = new JS.Fun(params, new JS.Block(body)); |
973 _visit(node.parameters) as List<JS.Parameter>, new JS.Block(body)); | |
974 return annotate( | 980 return annotate( |
975 new JS.Method(name, fun, isStatic: true)..sourceInformation = node, | 981 new JS.Method(name, fun, isStatic: true)..sourceInformation = node, |
976 node.element); | 982 node.element); |
977 } | 983 } |
978 | 984 |
979 // Code generation for Object's constructor. | 985 // Code generation for Object's constructor. |
980 JS.Block body; | 986 JS.Block body; |
981 if (isObject && | 987 if (isObject && |
982 node.body is EmptyFunctionBody && | 988 node.body is EmptyFunctionBody && |
983 node.constKeyword != null && | 989 node.constKeyword != null && |
(...skipping 18 matching lines...) Expand all Loading... |
1002 return result === void 0 ? this : result; | 1008 return result === void 0 ? this : result; |
1003 }''') as JS.Block; | 1009 }''') as JS.Block; |
1004 } else { | 1010 } else { |
1005 body = _emitConstructorBody(node, fields); | 1011 body = _emitConstructorBody(node, fields); |
1006 } | 1012 } |
1007 | 1013 |
1008 // We generate constructors as initializer methods in the class; | 1014 // We generate constructors as initializer methods in the class; |
1009 // this allows use of `super` for instance methods/properties. | 1015 // this allows use of `super` for instance methods/properties. |
1010 // It also avoids V8 restrictions on `super` in default constructors. | 1016 // It also avoids V8 restrictions on `super` in default constructors. |
1011 return annotate( | 1017 return annotate( |
1012 new JS.Method(name, | 1018 new JS.Method(name, new JS.Fun(params, body))..sourceInformation = node, |
1013 new JS.Fun(_visit(node.parameters) as List<JS.Parameter>, body)) | |
1014 ..sourceInformation = node, | |
1015 node.element); | 1019 node.element); |
1016 } | 1020 } |
1017 | 1021 |
1018 JS.Expression _constructorName(ConstructorElement ctor) { | 1022 JS.Expression _constructorName(ConstructorElement ctor) { |
1019 var name = ctor.name; | 1023 var name = ctor.name; |
1020 if (name != '') { | 1024 if (name != '') { |
1021 return _emitMemberName(name, isStatic: true); | 1025 return _emitMemberName(name, isStatic: true); |
1022 } | 1026 } |
1023 | 1027 |
1024 // Factory default constructors use `new` as their name, for readability | 1028 // Factory default constructors use `new` as their name, for readability |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 if (node is ConstructorDeclaration != constructor) return null; | 1218 if (node is ConstructorDeclaration != constructor) return null; |
1215 | 1219 |
1216 var parameters = _parametersOf(node); | 1220 var parameters = _parametersOf(node); |
1217 if (parameters == null) return null; | 1221 if (parameters == null) return null; |
1218 | 1222 |
1219 var body = <JS.Statement>[]; | 1223 var body = <JS.Statement>[]; |
1220 for (var param in parameters.parameters) { | 1224 for (var param in parameters.parameters) { |
1221 var jsParam = _visit(param.identifier); | 1225 var jsParam = _visit(param.identifier); |
1222 | 1226 |
1223 if (param.kind == ParameterKind.NAMED) { | 1227 if (param.kind == ParameterKind.NAMED) { |
1224 if (!_isDestructurableNamedParam(param)) { | 1228 if (!options.destructureNamedParams) { |
1225 // Parameters will be passed using their real names, not the (possibly | 1229 // Parameters will be passed using their real names, not the (possibly |
1226 // renamed) local variable. | 1230 // renamed) local variable. |
1227 var paramName = js.string(param.identifier.name, "'"); | 1231 var paramName = js.string(param.identifier.name, "'"); |
1228 | 1232 |
1229 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. | 1233 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. |
1230 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 1234 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
1231 jsParam, | 1235 jsParam, |
1232 _namedArgTemp, | 1236 _namedArgTemp, |
1233 paramName, | 1237 paramName, |
1234 _namedArgTemp, | 1238 _namedArgTemp, |
1235 _namedArgTemp, | 1239 _namedArgTemp, |
1236 paramName, | 1240 paramName, |
1237 _defaultParamValue(param), | 1241 _defaultParamValue(param), |
1238 ])); | 1242 ])); |
1239 } | 1243 } |
1240 } else if (param.kind == ParameterKind.POSITIONAL) { | 1244 } else if (param.kind == ParameterKind.POSITIONAL && |
| 1245 !options.destructureNamedParams) { |
1241 body.add(js.statement('if (# === void 0) # = #;', | 1246 body.add(js.statement('if (# === void 0) # = #;', |
1242 [jsParam, jsParam, _defaultParamValue(param)])); | 1247 [jsParam, jsParam, _defaultParamValue(param)])); |
1243 } | 1248 } |
1244 | 1249 |
1245 // TODO(jmesserly): various problems here, see: | 1250 // TODO(jmesserly): various problems here, see: |
1246 // https://github.com/dart-lang/dev_compiler/issues/161 | 1251 // https://github.com/dart-lang/dev_compiler/issues/161 |
1247 var paramType = param.element.type; | 1252 var paramType = param.element.type; |
1248 if (!constructor && _hasUnsoundTypeParameter(paramType)) { | 1253 if (!constructor && _hasUnsoundTypeParameter(paramType)) { |
1249 body.add(js | 1254 body.add(js |
1250 .statement('dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); | 1255 .statement('dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2037 @override | 2042 @override |
2038 JS.Property visitNamedExpression(NamedExpression node) { | 2043 JS.Property visitNamedExpression(NamedExpression node) { |
2039 assert(node.parent is ArgumentList); | 2044 assert(node.parent is ArgumentList); |
2040 return new JS.Property( | 2045 return new JS.Property( |
2041 _propertyName(node.name.label.name), _visit(node.expression)); | 2046 _propertyName(node.name.label.name), _visit(node.expression)); |
2042 } | 2047 } |
2043 | 2048 |
2044 bool _isNamedParam(FormalParameter param) => | 2049 bool _isNamedParam(FormalParameter param) => |
2045 param.kind == ParameterKind.NAMED; | 2050 param.kind == ParameterKind.NAMED; |
2046 | 2051 |
2047 /// We cannot destructure named params that clash with JS reserved names: | |
2048 /// see discussion in https://github.com/dart-lang/dev_compiler/issues/392. | |
2049 bool _isDestructurableNamedParam(FormalParameter param) => | |
2050 _isNamedParam(param) && | |
2051 !invalidVariableName(param.identifier.name) && | |
2052 options.destructureNamedParams; | |
2053 | |
2054 @override | 2052 @override |
2055 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) => | 2053 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) => |
2056 _emitFormalParameterList(node); | 2054 _emitFormalParameterList(node); |
2057 | 2055 |
2058 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, | 2056 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, |
2059 {bool allowDestructuring: true}) { | 2057 {bool allowDestructuring: true}) { |
2060 var result = <JS.Parameter>[]; | 2058 var result = <JS.Parameter>[]; |
2061 | 2059 |
2062 var namedVars = <JS.DestructuredVariable>[]; | 2060 var namedVars = <JS.DestructuredVariable>[]; |
2063 var destructure = allowDestructuring && | 2061 var destructure = allowDestructuring && options.destructureNamedParams; |
2064 node.parameters.where(_isNamedParam).every(_isDestructurableNamedParam); | |
2065 var hasNamedArgsConflictingWithObjectProperties = false; | 2062 var hasNamedArgsConflictingWithObjectProperties = false; |
2066 var needsOpts = false; | 2063 var needsOpts = false; |
2067 | 2064 |
2068 for (FormalParameter param in node.parameters) { | 2065 for (FormalParameter param in node.parameters) { |
2069 if (param.kind == ParameterKind.NAMED) { | 2066 if (param.kind == ParameterKind.NAMED) { |
2070 if (destructure) { | 2067 if (destructure) { |
2071 if (_jsObjectProperties.contains(param.identifier.name)) { | 2068 if (_jsObjectProperties.contains(param.identifier.name)) { |
2072 hasNamedArgsConflictingWithObjectProperties = true; | 2069 hasNamedArgsConflictingWithObjectProperties = true; |
2073 } | 2070 } |
| 2071 JS.Expression name; |
| 2072 JS.SimpleBindingPattern structure = null; |
| 2073 String paramName = param.identifier.name; |
| 2074 if (invalidVariableName(paramName)) { |
| 2075 name = js.string(paramName); |
| 2076 structure = new JS.SimpleBindingPattern(_visit(param.identifier)); |
| 2077 } else { |
| 2078 name = _visit(param.identifier); |
| 2079 } |
2074 namedVars.add(new JS.DestructuredVariable( | 2080 namedVars.add(new JS.DestructuredVariable( |
2075 name: _visit(param.identifier), | 2081 name: name, |
| 2082 structure: structure, |
2076 defaultValue: _defaultParamValue(param))); | 2083 defaultValue: _defaultParamValue(param))); |
2077 } else { | 2084 } else { |
2078 needsOpts = true; | 2085 needsOpts = true; |
2079 } | 2086 } |
2080 } else { | 2087 } else { |
2081 result.add(_visit(param)); | 2088 var jsParam = _visit(param); |
| 2089 result.add( |
| 2090 param is DefaultFormalParameter && options.destructureNamedParams |
| 2091 ? new JS.DestructuredVariable( |
| 2092 name: jsParam, |
| 2093 defaultValue: _defaultParamValue(param)) |
| 2094 : jsParam); |
2082 } | 2095 } |
2083 } | 2096 } |
2084 | 2097 |
2085 if (needsOpts) { | 2098 if (needsOpts) { |
2086 result.add(_namedArgTemp); | 2099 result.add(_namedArgTemp); |
2087 } else if (namedVars.isNotEmpty) { | 2100 } else if (namedVars.isNotEmpty) { |
2088 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so | 2101 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so |
2089 // in case there are conflicting names we create an object without | 2102 // in case there are conflicting names we create an object without |
2090 // any prototype. | 2103 // any prototype. |
2091 var defaultOpts = hasNamedArgsConflictingWithObjectProperties | 2104 var defaultOpts = hasNamedArgsConflictingWithObjectProperties |
(...skipping 1520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3612 | 3625 |
3613 /// A special kind of element created by the compiler, signifying a temporary | 3626 /// A special kind of element created by the compiler, signifying a temporary |
3614 /// variable. These objects use instance equality, and should be shared | 3627 /// variable. These objects use instance equality, and should be shared |
3615 /// everywhere in the tree where they are treated as the same variable. | 3628 /// everywhere in the tree where they are treated as the same variable. |
3616 class TemporaryVariableElement extends LocalVariableElementImpl { | 3629 class TemporaryVariableElement extends LocalVariableElementImpl { |
3617 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3630 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
3618 | 3631 |
3619 int get hashCode => identityHashCode(this); | 3632 int get hashCode => identityHashCode(this); |
3620 bool operator ==(Object other) => identical(this, other); | 3633 bool operator ==(Object other) => identical(this, other); |
3621 } | 3634 } |
OLD | NEW |