Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(512)

Unified Diff: lib/src/codegen/js_codegen.dart

Issue 1484263002: Use destructuring assignments for named parameters (#180) (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Destructure function params directly (no more opts in most cases) Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 0dd62fd6d66a560036728d90a15671685a87c050..723102570e699d9dd93854eae83186da7a8f3c06 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -926,9 +926,11 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
// Pass along all arguments verbatim, and let the callee handle them.
// TODO(jmesserly): we'll need something different once we have
// rest/spread support, but this should work for now.
- var params = _visit(node.parameters);
+ var params = _visitFormalParameterList(
+ node.parameters, allowDestructuring: false);
Jennifer Messerly 2015/12/01 02:10:27 yeah, FYI, this makes total sense.
ochafik 2015/12/02 20:05:46 Acknowledged.
+
var fun = js.call('function(#) { return $newKeyword #(#); }',
- [params, _visit(redirect), params,]) as JS.Fun;
+ [params, _visit(redirect), params]) as JS.Fun;
return annotate(
new JS.Method(name, fun, isStatic: true)..sourceInformation = node,
node.element);
@@ -1185,25 +1187,31 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
if (parameters == null) return null;
var body = <JS.Statement>[];
+
+ Map<FormalParameter, JS.Identifier> paramNames =
Jennifer Messerly 2015/12/01 02:10:27 is this change still needed? the map doesn't seem
ochafik 2015/12/02 20:05:46 Indeed, removed :-)
+ new Map.fromIterable(parameters.parameters,
+ value: (param) => _visit(param.identifier));
+
for (var param in parameters.parameters) {
- var jsParam = _visit(param.identifier);
+ var jsParam = paramNames[param];
if (param.kind == ParameterKind.NAMED) {
- // Parameters will be passed using their real names, not the (possibly
- // renamed) local variable.
- var paramName = js.string(param.identifier.name, "'");
-
- // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming
- // (either test if `obj.prop !== void 0`, or use JSCompiler_renameProperty).
- body.add(js.statement('let # = # && # in # ? #.# : #;', [
- jsParam,
- _namedArgTemp,
- paramName,
- _namedArgTemp,
- _namedArgTemp,
- paramName,
- _defaultParamValue(param),
- ]));
+ if (!_isDestructurableNamedParam(param)) {
+ // Parameters will be passed using their real names, not the (possibly
+ // renamed) local variable.
+ var paramName = js.string(param.identifier.name, "'");
+
+ // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming.
+ body.add(js.statement('let # = # && # in # ? #.# : #;', [
+ jsParam,
+ _namedArgTemp,
+ paramName,
+ _namedArgTemp,
+ _namedArgTemp,
+ paramName,
+ _defaultParamValue(param),
+ ]));
+ }
} else if (param.kind == ParameterKind.POSITIONAL) {
body.add(js.statement('if (# === void 0) # = #;',
[jsParam, jsParam, _defaultParamValue(param)]));
@@ -1354,17 +1362,22 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
if (parent is FunctionDeclaration) {
return _emitFunctionBody(params, node.body);
} else {
- String code;
+ // Chrome Canary does not accept default values with destructuring in
+ // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them
+ // with regular functions (e.g. `function({a} = {}) { return 1 }`).
+ // Note that Firefox accepts both syntaxes just fine.
+ // TODO(ochafik): Simplify this code when Chrome Canary catches up.
+ var canUseArrowFun = !node.parameters.parameters.any(_isNamedParam);
+
+ String code = canUseArrowFun ? '(#) => #' : 'function(#) { return # }';
JS.Node jsBody;
var body = node.body;
if (body.isGenerator || body.isAsynchronous) {
- code = '(#) => #';
jsBody = _emitGeneratorFunctionBody(params, body);
} else if (body is ExpressionFunctionBody) {
- code = '(#) => #';
jsBody = _visit(body.expression);
} else {
- code = '(#) => { #; }';
+ code = canUseArrowFun ? '(#) => { #; }' : 'function(#) { #; }';
jsBody = _visit(body);
}
var clos = js.call(code, [params, jsBody]);
@@ -1905,15 +1918,71 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
_propertyName(node.name.label.name), _visit(node.expression));
}
+ static final Set<String> _jsObjectProperties = new Set<String>()..addAll([
Jennifer Messerly 2015/12/01 02:10:27 it'd be good to cite where this list comes from.
ochafik 2015/12/02 20:05:46 Done.
+ "constructor",
+ "toString",
+ "toLocaleString",
+ "valueOf",
+ "hasOwnProperty",
+ "isPrototypeOf",
+ "propertyIsEnumerable",
+ "__defineGetter__",
+ "__lookupGetter__",
+ "__defineSetter__",
+ "__lookupSetter__",
+ "__proto__"
+ ]);
+
+ bool _isNamedParam(FormalParameter param) =>
+ param.kind == ParameterKind.NAMED;
+
+ bool _isDestructurableNamedParam(FormalParameter param) {
Jennifer Messerly 2015/12/01 02:10:27 I think we can allow destructing always and just u
ochafik 2015/12/02 20:05:46 Oh sweet, thanks! Done. (removes lots of nonsense!
+ var name = param.identifier.name;
+ return _isNamedParam(param) &&
+ !_jsObjectProperties.contains(name) &&
+ name != 'super';
+ }
+
+ _namedParams(FormalParameterList list) =>
+ list.parameters.where(_isNamedParam);
+
+ bool _willDestructureNamedParams(FormalParameterList list) {
+ var named = _namedParams(list).toList(growable: false);
+ return named.isNotEmpty && named.every(_isDestructurableNamedParam);
+ }
+
@override
- List<JS.Parameter> visitFormalParameterList(FormalParameterList node) {
+ List<JS.Parameter> visitFormalParameterList(FormalParameterList node) =>
+ _visitFormalParameterList(node, allowDestructuring: true);
+
+ List<JS.Parameter> _visitFormalParameterList(
Jennifer Messerly 2015/12/01 02:10:27 for better or worse, we have an "_emit" naming con
ochafik 2015/12/02 20:05:46 Done.
+ FormalParameterList node, {bool allowDestructuring}) {
+
var result = <JS.Parameter>[];
+
+ var namedVars = <JS.DestructuredVariable>[];
+ var canDestructure = allowDestructuring && _willDestructureNamedParams(node);
Jennifer Messerly 2015/12/01 02:10:27 long line
ochafik 2015/12/02 20:05:46 Acknowledged.
+ var needsOpts = false;
+
for (FormalParameter param in node.parameters) {
if (param.kind == ParameterKind.NAMED) {
- result.add(_namedArgTemp);
- break;
+ if (canDestructure) {
+ namedVars.add(new JS.DestructuredVariable(
+ name: _visit(param.identifier),
+ defaultValue: _defaultParamValue(param)));
+ } else {
+ needsOpts = true;
+ }
+ } else {
+ result.add(_visit(param));
}
- result.add(_visit(param));
+ }
+ if (canDestructure) {
+ result.add(new JS.DestructuredVariable(
+ structure: new JS.ObjectDestructuring(namedVars),
+ defaultValue: js.call('{}')));
+ } else if (needsOpts) {
+ result.add(_namedArgTemp);
}
return result;
}
« no previous file with comments | « lib/runtime/dart/mirrors.js ('k') | lib/src/js/builder.dart » ('j') | lib/src/js/builder.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698