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

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1736723002: more function refactoring (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 9 months 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 unified diff | Download patch
« no previous file with comments | « no previous file | test/codegen/expect/language-all.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/dart/ast/token.dart'; 8 import 'package:analyzer/dart/ast/token.dart';
9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/constant.dart'; 10 import 'package:analyzer/src/generated/constant.dart';
(...skipping 1451 matching lines...) Expand 10 before | Expand all | Expand 10 after
1462 if (node.isGetter || node.isSetter) { 1462 if (node.isGetter || node.isSetter) {
1463 // Add these later so we can use getter/setter syntax. 1463 // Add these later so we can use getter/setter syntax.
1464 _properties.add(node); 1464 _properties.add(node);
1465 return null; 1465 return null;
1466 } 1466 }
1467 1467
1468 var body = <JS.Statement>[]; 1468 var body = <JS.Statement>[];
1469 _flushLibraryProperties(body); 1469 _flushLibraryProperties(body);
1470 1470
1471 var name = node.name.name; 1471 var name = node.name.name;
1472 1472 var fn = _emitFunction(node.functionExpression);
1473 var fn = _visit(node.functionExpression);
1474 1473
1475 if (currentLibrary.source.isInSystemLibrary && 1474 if (currentLibrary.source.isInSystemLibrary &&
1476 _isInlineJSFunction(node.functionExpression)) { 1475 _isInlineJSFunction(node.functionExpression)) {
1477 fn = _simplifyPassThroughArrowFunCallBody(fn); 1476 fn = _simplifyPassThroughArrowFunCallBody(fn);
1478 } 1477 }
1479 1478
1480 var id = new JS.Identifier(name); 1479 var id = new JS.Identifier(name);
1481 body.add(annotate(new JS.FunctionDeclaration(id, fn), node, node.element)); 1480 body.add(annotate(new JS.FunctionDeclaration(id, fn), node, node.element));
1482 if (!_isDartRuntime) { 1481 if (!_isDartRuntime) {
1483 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) 1482 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1524 } 1523 }
1525 } 1524 }
1526 } 1525 }
1527 } 1526 }
1528 return fn; 1527 return fn;
1529 } 1528 }
1530 1529
1531 JS.Method _emitTopLevelProperty(FunctionDeclaration node) { 1530 JS.Method _emitTopLevelProperty(FunctionDeclaration node) {
1532 var name = node.name.name; 1531 var name = node.name.name;
1533 return annotate( 1532 return annotate(
1534 new JS.Method(_propertyName(name), _visit(node.functionExpression), 1533 new JS.Method(
1534 _propertyName(name), _emitFunction(node.functionExpression),
1535 isGetter: node.isGetter, isSetter: node.isSetter), 1535 isGetter: node.isGetter, isSetter: node.isSetter),
1536 node, 1536 node,
1537 node.element); 1537 node.element);
1538 } 1538 }
1539 1539
1540 bool _executesAtTopLevel(AstNode node) { 1540 bool _executesAtTopLevel(AstNode node) {
1541 var ancestor = node.getAncestor((n) => 1541 var ancestor = node.getAncestor((n) =>
1542 n is FunctionBody || 1542 n is FunctionBody ||
1543 (n is FieldDeclaration && n.staticKeyword == null) || 1543 (n is FieldDeclaration && n.staticKeyword == null) ||
1544 (n is ConstructorDeclaration && n.constKeyword == null)); 1544 (n is ConstructorDeclaration && n.constKeyword == null));
1545 return ancestor == null; 1545 return ancestor == null;
1546 } 1546 }
1547 1547
1548 bool _typeIsLoaded(DartType type) { 1548 bool _typeIsLoaded(DartType type) {
1549 if (type is FunctionType && (type.name == '' || type.name == null)) { 1549 if (type is FunctionType && (type.name == '' || type.name == null)) {
1550 return (_typeIsLoaded(type.returnType) && 1550 return (_typeIsLoaded(type.returnType) &&
1551 type.optionalParameterTypes.every(_typeIsLoaded) && 1551 type.optionalParameterTypes.every(_typeIsLoaded) &&
1552 type.namedParameterTypes.values.every(_typeIsLoaded) && 1552 type.namedParameterTypes.values.every(_typeIsLoaded) &&
1553 type.normalParameterTypes.every(_typeIsLoaded)); 1553 type.normalParameterTypes.every(_typeIsLoaded));
1554 } 1554 }
1555 if (type.isDynamic || type.isVoid || type.isBottom) return true; 1555 if (type.isDynamic || type.isVoid || type.isBottom) return true;
1556 if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) { 1556 if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) {
1557 return false; 1557 return false;
1558 } 1558 }
1559 return _loader.isLoaded(type.element); 1559 return _loader.isLoaded(type.element);
1560 } 1560 }
1561 1561
1562 JS.Expression _emitFunctionTagged(JS.Expression clos, DartType type, 1562 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type,
1563 {topLevel: false}) { 1563 {topLevel: false}) {
1564 var name = type.name; 1564 var name = type.name;
1565 var lazy = topLevel && !_typeIsLoaded(type); 1565 var lazy = topLevel && !_typeIsLoaded(type);
1566 1566
1567 if (type is FunctionType && (name == '' || name == null)) { 1567 if (type is FunctionType && (name == '' || name == null)) {
1568 if (type.returnType.isDynamic && 1568 if (type.returnType.isDynamic &&
1569 type.optionalParameterTypes.isEmpty && 1569 type.optionalParameterTypes.isEmpty &&
1570 type.namedParameterTypes.isEmpty && 1570 type.namedParameterTypes.isEmpty &&
1571 type.normalParameterTypes.every((t) => t.isDynamic)) { 1571 type.normalParameterTypes.every((t) => t.isDynamic)) {
1572 return js.call('dart.fn(#)', [clos]); 1572 return js.call('dart.fn(#)', [fn]);
1573 } 1573 }
1574 if (lazy) { 1574 if (lazy) {
1575 return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]); 1575 return js.call('dart.fn(#, () => #)', [fn, _emitFunctionRTTI(type)]);
1576 } 1576 }
1577 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); 1577 return js.call('dart.fn(#, #)', [fn, _emitFunctionTypeParts(type)]);
1578 } 1578 }
1579 throw 'Function has non function type: $type'; 1579 throw 'Function has non function type: $type';
1580 } 1580 }
1581 1581
1582 /// Emits an arrow FunctionExpression node.
1583 ///
1584 /// This should be used for all places in Dart's AST where FunctionExpression
1585 /// appears and the function is actually in an Expression context. These
1586 /// correspond to arrow functions in Dart.
1587 ///
1588 /// Contrast with [_emitFunction].
1582 @override 1589 @override
1583 JS.Expression visitFunctionExpression(FunctionExpression node) { 1590 JS.Expression visitFunctionExpression(FunctionExpression node) {
1584 var params = visitFormalParameterList(node.parameters); 1591 assert(node.parent is! FunctionDeclaration &&
1592 node.parent is! MethodDeclaration);
1593 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node),
1594 topLevel: _executesAtTopLevel(node));
1595 }
1596
1597 JS.ArrowFun _emitArrowFunction(FunctionExpression node) {
1598 List<JS.Parameter> params;
1585 1599
1586 var body = node.body; 1600 var body = node.body;
1587 var parent = node.parent;
1588 var inStmt = parent.parent is FunctionDeclarationStatement;
1589 if (parent is FunctionDeclaration) {
1590 return _emitFunctionBody(node.element, node.parameters, body);
1591 }
1592
1593 JS.Node jsBody; 1601 JS.Node jsBody;
1594 if (body.isGenerator || body.isAsynchronous) { 1602 if (body.isGenerator || body.isAsynchronous) {
1603 params = visitFormalParameterList(node.parameters, destructure: false);
1595 jsBody = _emitGeneratorFunctionBody(node.element, node.parameters, body); 1604 jsBody = _emitGeneratorFunctionBody(node.element, node.parameters, body);
1596 } else if (body is ExpressionFunctionBody) {
1597 jsBody = _visit(body.expression);
1598 } else {
1599 jsBody = _visit(body);
1600 }
1601
1602 var type = node.element.type;
1603 var typeFormals = _emitTypeFormals(type.typeFormals);
1604 var returnType = emitTypeRef(type.returnType);
1605
1606 JS.FunctionExpression fn;
1607 if (node.parameters.parameters
1608 .every((p) => p.kind != ParameterKind.NAMED)) {
1609 fn = new JS.ArrowFun(params, jsBody,
1610 typeParams: typeFormals, returnType: returnType);
1611 } else { 1605 } else {
1612 // Chrome Canary does not accept default values with destructuring in 1606 // Chrome Canary does not accept default values with destructuring in
1613 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them 1607 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them
1614 // with regular functions (e.g. `function({a} = {}) { return 1 }`). 1608 // with regular functions (e.g. `function({a} = {}) { return 1 }`).
1615 // Note that Firefox accepts both syntaxes just fine. 1609 // Note that Firefox accepts both syntaxes just fine.
1616 // TODO(ochafik): Simplify this code when Chrome Canary catches up. 1610 // TODO(ochafik): Simplify this code when Chrome Canary catches up.
1611 bool hasNamedParams =
1612 node.parameters.parameters.any((p) => p.kind == ParameterKind.NAMED);
1617 1613
1618 if (jsBody is JS.Expression) { 1614 params = visitFormalParameterList(node.parameters,
1619 jsBody = js.statement("{ return #; }", [jsBody]); 1615 destructure: !hasNamedParams);
1616
1617 if (body is ExpressionFunctionBody) {
1618 // An arrow function can use the expression directly.
1619 jsBody = _visit(body.expression);
1620 } else {
1621 jsBody = _visit(body);
1620 } 1622 }
1621 fn = new JS.Fun(params, jsBody,
1622 typeParams: typeFormals, returnType: returnType);
1623 } 1623 }
1624 1624
1625 if (!inStmt) { 1625 var type = node.element.type;
1626 var type = getStaticType(node); 1626 var fn = new JS.ArrowFun(params, jsBody,
1627 return _emitFunctionTagged(fn, type, topLevel: _executesAtTopLevel(node)); 1627 typeParams: _emitTypeFormals(type.typeFormals),
1628 } 1628 returnType: emitTypeRef(type.returnType));
1629 return fn; 1629 return annotate(fn, node);
1630 }
1631
1632 /// Emits a non-arrow FunctionExpression node.
1633 ///
1634 /// This should be used for all places in Dart's AST where FunctionExpression
1635 /// appears but the function is not actually in an Expression context, such
1636 /// as methods, properties, and top-level functions.
1637 ///
1638 /// Contrast with [visitFunctionExpression].
1639 JS.Fun _emitFunction(FunctionExpression node) {
1640 var fn = _emitFunctionBody(node.element, node.parameters, node.body);
1641 return annotate(fn, node);
1630 } 1642 }
1631 1643
1632 JS.Fun _emitFunctionBody(ExecutableElement element, 1644 JS.Fun _emitFunctionBody(ExecutableElement element,
1633 FormalParameterList parameters, FunctionBody body) { 1645 FormalParameterList parameters, FunctionBody body) {
1634 var returnType = emitTypeRef(element.returnType); 1646 var returnType = emitTypeRef(element.returnType);
1635 1647
1636 // sync*, async, async* 1648 // sync*, async, async*
1637 if (element.isAsynchronous || element.isGenerator) { 1649 if (element.isAsynchronous || element.isGenerator) {
1638 return new JS.Fun( 1650 return new JS.Fun(
1639 visitFormalParameterList(parameters, destructure: false), 1651 visitFormalParameterList(parameters, destructure: false),
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1710 } 1722 }
1711 1723
1712 @override 1724 @override
1713 JS.Statement visitFunctionDeclarationStatement( 1725 JS.Statement visitFunctionDeclarationStatement(
1714 FunctionDeclarationStatement node) { 1726 FunctionDeclarationStatement node) {
1715 var func = node.functionDeclaration; 1727 var func = node.functionDeclaration;
1716 if (func.isGetter || func.isSetter) { 1728 if (func.isGetter || func.isSetter) {
1717 return js.comment('Unimplemented function get/set statement: $node'); 1729 return js.comment('Unimplemented function get/set statement: $node');
1718 } 1730 }
1719 1731
1720 var fn = _visit(func.functionExpression); 1732 var fn = _emitFunction(func.functionExpression);
1721 1733
1722 var name = new JS.Identifier(func.name.name); 1734 var name = new JS.Identifier(func.name.name);
1723 JS.Statement declareFn; 1735 JS.Statement declareFn;
1724 if (JS.This.foundIn(fn)) { 1736 if (JS.This.foundIn(fn)) {
1725 declareFn = js.statement('const # = #.bind(this);', [name, fn]); 1737 declareFn = js.statement('const # = #.bind(this);', [name, fn]);
1726 } else { 1738 } else {
1727 declareFn = new JS.FunctionDeclaration(name, fn); 1739 declareFn = new JS.FunctionDeclaration(name, fn);
1728 } 1740 }
1729 declareFn = annotate(declareFn, node, node.functionDeclaration.element); 1741 declareFn = annotate(declareFn, node, node.functionDeclaration.element);
1730 1742
(...skipping 1760 matching lines...) Expand 10 before | Expand all | Expand 10 after
3491 } 3503 }
3492 3504
3493 _visit(AstNode node) { 3505 _visit(AstNode node) {
3494 if (node == null) return null; 3506 if (node == null) return null;
3495 var result = node.accept(this); 3507 var result = node.accept(this);
3496 if (result is JS.Node) result = annotate(result, node); 3508 if (result is JS.Node) result = annotate(result, node);
3497 return result; 3509 return result;
3498 } 3510 }
3499 3511
3500 // TODO(jmesserly): this will need to be a generic method, if we ever want to 3512 // TODO(jmesserly): this will need to be a generic method, if we ever want to
3501 // self-host strong mode. 3513 // self-host strong mode.
vsm 2016/02/25 00:48:04 Probably don't need the TODO anymore. :-)
Jennifer Messerly 2016/02/25 00:53:45 Yup! Have this fixed in a follow up CL I'm working
3502 List/*<T>*/ _visitList/*<T>*/(Iterable<AstNode> nodes) { 3514 List /*<T>*/ _visitList /*<T>*/ (Iterable<AstNode> nodes) {
3503 if (nodes == null) return null; 3515 if (nodes == null) return null;
3504 var result = /*<T>*/ []; 3516 var result = /*<T>*/ [];
3505 for (var node in nodes) result.add(_visit(node)); 3517 for (var node in nodes) result.add(_visit(node));
3506 return result; 3518 return result;
3507 } 3519 }
3508 3520
3509 /// Visits a list of expressions, creating a comma expression if needed in JS. 3521 /// Visits a list of expressions, creating a comma expression if needed in JS.
3510 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 3522 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
3511 if (nodes == null || nodes.isEmpty) return null; 3523 if (nodes == null || nodes.isEmpty) return null;
3512 return new JS.Expression.binary( 3524 return new JS.Expression.binary(
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
3802 3814
3803 /// A special kind of element created by the compiler, signifying a temporary 3815 /// A special kind of element created by the compiler, signifying a temporary
3804 /// variable. These objects use instance equality, and should be shared 3816 /// variable. These objects use instance equality, and should be shared
3805 /// everywhere in the tree where they are treated as the same variable. 3817 /// everywhere in the tree where they are treated as the same variable.
3806 class TemporaryVariableElement extends LocalVariableElementImpl { 3818 class TemporaryVariableElement extends LocalVariableElementImpl {
3807 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3819 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3808 3820
3809 int get hashCode => identityHashCode(this); 3821 int get hashCode => identityHashCode(this);
3810 bool operator ==(Object other) => identical(this, other); 3822 bool operator ==(Object other) => identical(this, other);
3811 } 3823 }
OLDNEW
« no previous file with comments | « no previous file | test/codegen/expect/language-all.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698