Index: pkg/analyzer2dart/lib/src/cps_generator.dart |
diff --git a/pkg/analyzer2dart/lib/src/cps_generator.dart b/pkg/analyzer2dart/lib/src/cps_generator.dart |
index 8bd4c0ad66833a2c492c6af8d94bcaaa1677667e..1e5bb6dbf342c262e61e15bc67d7d7f170a3b289 100644 |
--- a/pkg/analyzer2dart/lib/src/cps_generator.dart |
+++ b/pkg/analyzer2dart/lib/src/cps_generator.dart |
@@ -1,589 +1,589 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library analyzer2dart.cps_generator; |
- |
-import 'package:analyzer/analyzer.dart'; |
- |
-import 'package:compiler/src/dart_types.dart' as dart2js; |
-import 'package:compiler/src/elements/elements.dart' as dart2js; |
-import 'package:analyzer/src/generated/source.dart'; |
-import 'package:analyzer/src/generated/element.dart' as analyzer; |
- |
-import 'package:compiler/src/constant_system_dart.dart' |
- show DART_CONSTANT_SYSTEM; |
-import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; |
-import 'package:compiler/src/cps_ir/cps_ir_builder.dart'; |
-import 'package:compiler/src/universe/universe.dart'; |
- |
-import 'semantic_visitor.dart'; |
-import 'element_converter.dart'; |
-import 'util.dart'; |
-import 'identifier_semantics.dart'; |
- |
-/// Visitor that converts the AST node of an analyzer element into a CPS ir |
-/// node. |
-class CpsElementVisitor extends analyzer.SimpleElementVisitor<ir.Node> { |
- final ElementConverter converter; |
- final AstNode node; |
- |
- CpsElementVisitor(this.converter, this.node); |
- |
- @override |
- ir.FunctionDefinition visitFunctionElement(analyzer.FunctionElement element) { |
- CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
- FunctionDeclaration functionDeclaration = node; |
- return visitor.handleFunctionDeclaration( |
- element, functionDeclaration.functionExpression.body); |
- } |
- |
- @override |
- ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) { |
- CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
- MethodDeclaration methodDeclaration = node; |
- return visitor.handleFunctionDeclaration(element, methodDeclaration.body); |
- } |
- |
- @override |
- ir.FieldDefinition visitTopLevelVariableElement( |
- analyzer.TopLevelVariableElement element) { |
- CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
- VariableDeclaration variableDeclaration = node; |
- return visitor.handleFieldDeclaration(element, variableDeclaration); |
- } |
- |
- @override |
- ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) { |
- CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
- if (!element.isFactory) { |
- ConstructorDeclaration constructorDeclaration = node; |
- FunctionBody body; |
- if (constructorDeclaration != null) { |
- body = constructorDeclaration.body; |
- } else { |
- assert(element.isSynthetic); |
- } |
- return visitor.handleConstructorDeclaration(element, body); |
- } |
- // TODO(johnniwinther): Support factory constructors. |
- return null; |
- } |
-} |
- |
-/// Visitor that converts analyzer AST nodes into CPS ir nodes. |
-class CpsGeneratingVisitor extends SemanticVisitor<ir.Node> |
- with IrBuilderMixin<AstNode> { |
- /// Promote the type of [irBuilder] to [DartIrBuilder]. |
- /// The JS backend requires closure conversion which we do not support yet. |
- DartIrBuilder get irBuilder => super.irBuilder; |
- final analyzer.Element element; |
- final ElementConverter converter; |
- |
- CpsGeneratingVisitor(this.converter, this.element); |
- |
- Source get currentSource => element.source; |
- |
- analyzer.LibraryElement get currentLibrary => element.library; |
- |
- ir.Node visit(AstNode node) => node.accept(this); |
- |
- ir.ConstructorDefinition handleConstructorDeclaration( |
- analyzer.ConstructorElement constructor, FunctionBody body) { |
- dart2js.ConstructorElement element = converter.convertElement(constructor); |
- return withBuilder( |
- new DartIrBuilder(DART_CONSTANT_SYSTEM, |
- element, |
- // TODO(johnniwinther): Support closure variables. |
- new Set<dart2js.Local>()), |
- () { |
- irBuilder.buildFunctionHeader( |
- constructor.parameters.map(converter.convertElement)); |
- // Visit the body directly to avoid processing the signature as |
- // expressions. |
- // Call to allow for `body == null` in case of synthesized constructors. |
- build(body); |
- return irBuilder.makeConstructorDefinition(const [], const []); |
- }); |
- } |
- |
- ir.FieldDefinition handleFieldDeclaration( |
- analyzer.PropertyInducingElement field, VariableDeclaration node) { |
- dart2js.FieldElement element = converter.convertElement(field); |
- return withBuilder( |
- new DartIrBuilder(DART_CONSTANT_SYSTEM, |
- element, |
- // TODO(johnniwinther): Support closure variables. |
- new Set<dart2js.Local>()), |
- () { |
- irBuilder.buildFieldInitializerHeader(); |
- ir.Primitive initializer = build(node.initializer); |
- return irBuilder.makeFieldDefinition(initializer); |
- }); |
- } |
- |
- ir.FunctionDefinition handleFunctionDeclaration( |
- analyzer.ExecutableElement function, FunctionBody body) { |
- dart2js.FunctionElement element = converter.convertElement(function); |
- return withBuilder( |
- new DartIrBuilder(DART_CONSTANT_SYSTEM, |
- element, |
- // TODO(johnniwinther): Support closure variables. |
- new Set<dart2js.Local>()), |
- () { |
- irBuilder.buildFunctionHeader( |
- function.parameters.map(converter.convertElement)); |
- // Visit the body directly to avoid processing the signature as |
- // expressions. |
- visit(body); |
- return irBuilder.makeFunctionDefinition(const []); |
- }); |
- } |
- |
- @override |
- ir.Primitive visitFunctionExpression(FunctionExpression node) { |
- return irBuilder.buildFunctionExpression( |
- handleFunctionDeclaration(node.element, node.body)); |
- } |
- |
- @override |
- ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { |
- return handleFunctionDeclaration( |
- node.element, node.functionExpression.body); |
- } |
- |
- @override |
- visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
- FunctionDeclaration functionDeclaration = node.functionDeclaration; |
- analyzer.FunctionElement function = functionDeclaration.element; |
- dart2js.FunctionElement element = converter.convertElement(function); |
- ir.FunctionDefinition definition = handleFunctionDeclaration( |
- function, functionDeclaration.functionExpression.body); |
- irBuilder.declareLocalFunction(element, definition); |
- } |
- |
- List<ir.Primitive> visitArguments(ArgumentList argumentList) { |
- List<ir.Primitive> arguments = <ir.Primitive>[]; |
- for (Expression argument in argumentList.arguments) { |
- ir.Primitive value = build(argument); |
- if (value == null) { |
- giveUp(argument, |
- 'Unsupported argument: $argument (${argument.runtimeType}).'); |
- } |
- arguments.add(value); |
- } |
- return arguments; |
- } |
- |
- @override |
- ir.Node visitMethodInvocation(MethodInvocation node) { |
- // Overridden to avoid eager visits of the receiver and arguments. |
- return handleMethodInvocation(node); |
- } |
- |
- @override |
- ir.Primitive visitDynamicInvocation(MethodInvocation node, |
- AccessSemantics semantics) { |
- // TODO(johnniwinther): Handle implicit `this`. |
- ir.Primitive receiver = build(semantics.target); |
- List<ir.Primitive> arguments = visitArguments(node.argumentList); |
- return irBuilder.buildDynamicInvocation( |
- receiver, |
- createSelectorFromMethodInvocation( |
- node.argumentList, node.methodName.name), |
- arguments); |
- } |
- |
- @override |
- ir.Primitive visitStaticMethodInvocation(MethodInvocation node, |
- AccessSemantics semantics) { |
- analyzer.Element staticElement = semantics.element; |
- dart2js.Element element = converter.convertElement(staticElement); |
- List<ir.Primitive> arguments = visitArguments(node.argumentList); |
- return irBuilder.buildStaticFunctionInvocation( |
- element, |
- createCallStructureFromMethodInvocation(node.argumentList), |
- arguments); |
- } |
- |
- @override |
- ir.Node visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { |
- return handleLocalAccess(node, semantics); |
- } |
- |
- ir.Primitive handleLocalInvocation(MethodInvocation node, |
- AccessSemantics semantics) { |
- analyzer.Element staticElement = semantics.element; |
- dart2js.Element element = converter.convertElement(staticElement); |
- List<ir.Definition> arguments = visitArguments(node.argumentList); |
- CallStructure callStructure = createCallStructureFromMethodInvocation( |
- node.argumentList); |
- if (semantics.kind == AccessKind.LOCAL_FUNCTION) { |
- return irBuilder.buildLocalFunctionInvocation( |
- element, callStructure, arguments); |
- } else { |
- return irBuilder.buildLocalVariableInvocation( |
- element, callStructure, arguments); |
- } |
- } |
- |
- @override |
- ir.Node visitLocalVariableInvocation(MethodInvocation node, |
- AccessSemantics semantics) { |
- return handleLocalInvocation(node, semantics); |
- } |
- |
- @override |
- ir.Primitive visitLocalFunctionInvocation(MethodInvocation node, |
- AccessSemantics semantics) { |
- return handleLocalInvocation(node, semantics); |
- } |
- |
- @override |
- ir.Primitive visitFunctionExpressionInvocation( |
- FunctionExpressionInvocation node) { |
- ir.Primitive target = build(node.function); |
- List<ir.Definition> arguments = visitArguments(node.argumentList); |
- return irBuilder.buildCallInvocation( |
- target, |
- createCallStructureFromMethodInvocation(node.argumentList), |
- arguments); |
- } |
- |
- @override |
- ir.Primitive visitInstanceCreationExpression( |
- InstanceCreationExpression node) { |
- analyzer.Element staticElement = node.staticElement; |
- if (staticElement != null) { |
- dart2js.Element element = converter.convertElement(staticElement); |
- dart2js.DartType type = converter.convertType(node.staticType); |
- List<ir.Primitive> arguments = visitArguments(node.argumentList); |
- return irBuilder.buildConstructorInvocation( |
- element, |
- createCallStructureFromMethodInvocation(node.argumentList), |
- type, |
- arguments); |
- } |
- return giveUp(node, "Unresolved constructor invocation."); |
- } |
- |
- @override |
- ir.Constant visitNullLiteral(NullLiteral node) { |
- return irBuilder.buildNullConstant(); |
- } |
- |
- @override |
- ir.Constant visitBooleanLiteral(BooleanLiteral node) { |
- return irBuilder.buildBooleanConstant(node.value); |
- } |
- |
- @override |
- ir.Constant visitDoubleLiteral(DoubleLiteral node) { |
- return irBuilder.buildDoubleConstant(node.value); |
- } |
- |
- @override |
- ir.Constant visitIntegerLiteral(IntegerLiteral node) { |
- return irBuilder.buildIntegerConstant(node.value); |
- } |
- |
- @override |
- visitAdjacentStrings(AdjacentStrings node) { |
- String value = node.stringValue; |
- if (value != null) { |
- return irBuilder.buildStringConstant(value); |
- } |
- giveUp(node, "Non constant adjacent strings."); |
- } |
- |
- @override |
- ir.Constant visitSimpleStringLiteral(SimpleStringLiteral node) { |
- return irBuilder.buildStringConstant(node.value); |
- } |
- |
- @override |
- visitStringInterpolation(StringInterpolation node) { |
- giveUp(node, "String interpolation."); |
- } |
- |
- @override |
- visitReturnStatement(ReturnStatement node) { |
- irBuilder.buildReturn(build(node.expression)); |
- } |
- |
- @override |
- ir.Node visitPropertyAccess(PropertyAccess node) { |
- // Overridden to avoid eager visits of the receiver. |
- return handlePropertyAccess(node); |
- } |
- |
- @override |
- ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { |
- return handleLocalAccess(node, semantics); |
- } |
- |
- @override |
- ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { |
- return handleLocalAccess(node, semantics); |
- } |
- |
- @override |
- visitVariableDeclaration(VariableDeclaration node) { |
- // TODO(johnniwinther): Handle constant local variables. |
- ir.Node initialValue = build(node.initializer); |
- irBuilder.declareLocalVariable( |
- converter.convertElement(node.element), |
- initialValue: initialValue); |
- } |
- |
- dart2js.Element getLocal(AstNode node, AccessSemantics semantics) { |
- analyzer.Element element = semantics.element; |
- dart2js.Element target = converter.convertElement(element); |
- assert(invariant(node, target.isLocal, '$target expected to be local.')); |
- return target; |
- } |
- |
- ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { |
- dart2js.Element local = getLocal(node, semantics); |
- if (semantics.kind == AccessKind.LOCAL_FUNCTION) { |
- return irBuilder.buildLocalFunctionGet(local); |
- } else { |
- return irBuilder.buildLocalVariableGet(local); |
- } |
- } |
- |
- ir.Primitive handleLocalAssignment(AssignmentExpression node, |
- AccessSemantics semantics) { |
- if (node.operator.lexeme != '=') { |
- return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); |
- } |
- return irBuilder.buildLocalVariableSet( |
- getLocal(node, semantics), |
- build(node.rightHandSide)); |
- } |
- |
- @override |
- ir.Node visitAssignmentExpression(AssignmentExpression node) { |
- // Avoid eager visiting of left and right hand side. |
- return handleAssignmentExpression(node); |
- } |
- |
- @override |
- ir.Node visitLocalVariableAssignment(AssignmentExpression node, |
- AccessSemantics semantics) { |
- return handleLocalAssignment(node, semantics); |
- } |
- |
- @override |
- ir.Node visitParameterAssignment(AssignmentExpression node, |
- AccessSemantics semantics) { |
- return handleLocalAssignment(node, semantics); |
- } |
- |
- @override |
- ir.Node visitStaticFieldAssignment(AssignmentExpression node, |
- AccessSemantics semantics) { |
- if (node.operator.lexeme != '=') { |
- return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); |
- } |
- analyzer.Element element = semantics.element; |
- dart2js.Element target = converter.convertElement(element); |
- // TODO(johnniwinther): Selector information should be computed in the |
- // [TreeShaker] and shared with the [CpsGeneratingVisitor]. |
- assert(invariant(node, target.isTopLevel || target.isStatic, |
- '$target expected to be top-level or static.')); |
- return irBuilder.buildStaticFieldSet(target, build(node.rightHandSide)); |
- } |
- |
- @override |
- ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { |
- // TODO(johnniwinther): Handle implicit `this`. |
- ir.Primitive receiver = build(semantics.target); |
- return irBuilder.buildDynamicGet(receiver, |
- new Selector.getter(semantics.identifier.name, |
- converter.convertElement(element.library))); |
- } |
- |
- @override |
- ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { |
- analyzer.Element element = semantics.element; |
- dart2js.Element target = converter.convertElement(element); |
- // TODO(johnniwinther): Selector information should be computed in the |
- // [TreeShaker] and shared with the [CpsGeneratingVisitor]. |
- assert(invariant(node, target.isTopLevel || target.isStatic, |
- '$target expected to be top-level or static.')); |
- return irBuilder.buildStaticFieldLazyGet(target, null); |
- } |
- |
- ir.Primitive handleBinaryExpression(BinaryExpression node, |
- String op) { |
- ir.Primitive left = build(node.leftOperand); |
- ir.Primitive right = build(node.rightOperand); |
- Selector selector = new Selector.binaryOperator(op); |
- return irBuilder.buildDynamicInvocation( |
- left, selector, <ir.Primitive>[right]); |
- } |
- |
- ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { |
- return irBuilder.buildLogicalOperator( |
- build(node.leftOperand), |
- subbuild(node.rightOperand), |
- isLazyOr: isLazyOr); |
- } |
- |
- @override |
- ir.Node visitBinaryExpression(BinaryExpression node) { |
- // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be |
- // available through an enum. |
- String op = node.operator.lexeme; |
- switch (op) { |
- case '||': |
- case '&&': |
- return handleLazyOperator(node, isLazyOr: op == '||'); |
- case '!=': |
- return irBuilder.buildNegation(handleBinaryExpression(node, '==')); |
- default: |
- return handleBinaryExpression(node, op); |
- } |
- } |
- |
- @override |
- ir.Node visitConditionalExpression(ConditionalExpression node) { |
- return irBuilder.buildConditional( |
- build(node.condition), |
- subbuild(node.thenExpression), |
- subbuild(node.elseExpression)); |
- } |
- |
- @override |
- visitIfStatement(IfStatement node) { |
- irBuilder.buildIf( |
- build(node.condition), |
- subbuild(node.thenStatement), |
- subbuild(node.elseStatement)); |
- } |
- |
- @override |
- visitBlock(Block node) { |
- irBuilder.buildBlock(node.statements, build); |
- } |
- |
- @override |
- ir.Node visitListLiteral(ListLiteral node) { |
- dart2js.InterfaceType type = converter.convertType(node.staticType); |
- // TODO(johnniwinther): Use `build` instead of `(e) => build(e)` when issue |
- // 18630 has been resolved. |
- Iterable<ir.Primitive> values = node.elements.map((e) => build(e)); |
- return irBuilder.buildListLiteral(type, values); |
- } |
- |
- @override |
- ir.Node visitMapLiteral(MapLiteral node) { |
- dart2js.InterfaceType type = converter.convertType(node.staticType); |
- return irBuilder.buildMapLiteral( |
- type, |
- node.entries.map((e) => e.key), |
- node.entries.map((e) => e.value), |
- build); |
- } |
- |
- @override |
- visitForStatement(ForStatement node) { |
- // TODO(johnniwinther): Support `for` as a jump target. |
- List<dart2js.LocalElement> loopVariables = <dart2js.LocalElement>[]; |
- SubbuildFunction buildInitializer; |
- if (node.variables != null) { |
- buildInitializer = subbuild(node.variables); |
- for (VariableDeclaration variable in node.variables.variables) { |
- loopVariables.add(converter.convertElement(variable.element)); |
- } |
- } else { |
- buildInitializer = subbuild(node.initialization); |
- } |
- irBuilder.buildFor(buildInitializer: buildInitializer, |
- buildCondition: subbuild(node.condition), |
- buildBody: subbuild(node.body), |
- buildUpdate: subbuildSequence(node.updaters), |
- loopVariables: loopVariables); |
- } |
- |
- @override |
- visitWhileStatement(WhileStatement node) { |
- // TODO(johnniwinther): Support `while` as a jump target. |
- irBuilder.buildWhile(buildCondition: subbuild(node.condition), |
- buildBody: subbuild(node.body)); |
- } |
- |
- @override |
- visitDeclaredIdentifier(DeclaredIdentifier node) { |
- giveUp(node, "Unexpected node: DeclaredIdentifier"); |
- } |
- |
- @override |
- visitForEachStatement(ForEachStatement node) { |
- SubbuildFunction buildVariableDeclaration; |
- dart2js.Element variableElement; |
- Selector variableSelector; |
- if (node.identifier != null) { |
- AccessSemantics accessSemantics = |
- node.identifier.accept(ACCESS_SEMANTICS_VISITOR); |
- if (accessSemantics.kind == AccessKind.DYNAMIC) { |
- variableSelector = new Selector.setter( |
- node.identifier.name, converter.convertElement(currentLibrary)); |
- } else if (accessSemantics.element != null) { |
- variableElement = converter.convertElement(accessSemantics.element); |
- variableSelector = new Selector.setter( |
- variableElement.name, |
- converter.convertElement(accessSemantics.element.library)); |
- } else { |
- giveUp(node, 'For-in of unresolved variable: $accessSemantics'); |
- } |
- } else { |
- assert(invariant( |
- node, node.loopVariable != null, "Loop variable expected")); |
- variableElement = converter.convertElement(node.loopVariable.element); |
- buildVariableDeclaration = (IrBuilder builder) { |
- builder.declareLocalVariable(variableElement); |
- }; |
- } |
- // TODO(johnniwinther): Support `for-in` as a jump target. |
- irBuilder.buildForIn( |
- buildExpression: subbuild(node.iterable), |
- buildVariableDeclaration: buildVariableDeclaration, |
- variableElement: variableElement, |
- variableSelector: variableSelector, |
- buildBody: subbuild(node.body)); |
- } |
- @override |
- ir.Primitive visitIsExpression(IsExpression node) { |
- return irBuilder.buildTypeOperator( |
- visit(node.expression), |
- converter.convertType(node.type.type), |
- isTypeTest: true, |
- isNotCheck: node.notOperator != null); |
- } |
- |
- @override |
- ir.Primitive visitAsExpression(AsExpression node) { |
- return irBuilder.buildTypeOperator( |
- visit(node.expression), |
- converter.convertType(node.type.type), |
- isTypeTest: false); |
- } |
- |
- @override |
- visitTryStatement(TryStatement node) { |
- List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; |
- for (CatchClause catchClause in node.catchClauses) { |
- catchClauseInfos.add(new CatchClauseInfo( |
- exceptionVariable: converter.convertElement( |
- catchClause.exceptionParameter.staticElement), |
- buildCatchBlock: subbuild(catchClause.body))); |
- |
- } |
- irBuilder.buildTry( |
- tryStatementInfo: new TryStatementInfo(), |
- buildTryBlock: subbuild(node.body), |
- catchClauseInfos: catchClauseInfos); |
- } |
-} |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library analyzer2dart.cps_generator; |
+ |
+import 'package:analyzer/analyzer.dart'; |
+ |
+import 'package:compiler/src/dart_types.dart' as dart2js; |
+import 'package:compiler/src/elements/elements.dart' as dart2js; |
+import 'package:analyzer/src/generated/source.dart'; |
+import 'package:analyzer/src/generated/element.dart' as analyzer; |
+ |
+import 'package:compiler/src/constant_system_dart.dart' |
+ show DART_CONSTANT_SYSTEM; |
+import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; |
+import 'package:compiler/src/cps_ir/cps_ir_builder.dart'; |
+import 'package:compiler/src/universe/universe.dart'; |
+ |
+import 'semantic_visitor.dart'; |
+import 'element_converter.dart'; |
+import 'util.dart'; |
+import 'identifier_semantics.dart'; |
+ |
+/// Visitor that converts the AST node of an analyzer element into a CPS ir |
+/// node. |
+class CpsElementVisitor extends analyzer.SimpleElementVisitor<ir.Node> { |
+ final ElementConverter converter; |
+ final AstNode node; |
+ |
+ CpsElementVisitor(this.converter, this.node); |
+ |
+ @override |
+ ir.FunctionDefinition visitFunctionElement(analyzer.FunctionElement element) { |
+ CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
+ FunctionDeclaration functionDeclaration = node; |
+ return visitor.handleFunctionDeclaration( |
+ element, functionDeclaration.functionExpression.body); |
+ } |
+ |
+ @override |
+ ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) { |
+ CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
+ MethodDeclaration methodDeclaration = node; |
+ return visitor.handleFunctionDeclaration(element, methodDeclaration.body); |
+ } |
+ |
+ @override |
+ ir.FieldDefinition visitTopLevelVariableElement( |
+ analyzer.TopLevelVariableElement element) { |
+ CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
+ VariableDeclaration variableDeclaration = node; |
+ return visitor.handleFieldDeclaration(element, variableDeclaration); |
+ } |
+ |
+ @override |
+ ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) { |
+ CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); |
+ if (!element.isFactory) { |
+ ConstructorDeclaration constructorDeclaration = node; |
+ FunctionBody body; |
+ if (constructorDeclaration != null) { |
+ body = constructorDeclaration.body; |
+ } else { |
+ assert(element.isSynthetic); |
+ } |
+ return visitor.handleConstructorDeclaration(element, body); |
+ } |
+ // TODO(johnniwinther): Support factory constructors. |
+ return null; |
+ } |
+} |
+ |
+/// Visitor that converts analyzer AST nodes into CPS ir nodes. |
+class CpsGeneratingVisitor extends SemanticVisitor<ir.Node> |
+ with IrBuilderMixin<AstNode> { |
+ /// Promote the type of [irBuilder] to [DartIrBuilder]. |
+ /// The JS backend requires closure conversion which we do not support yet. |
+ DartIrBuilder get irBuilder => super.irBuilder; |
+ final analyzer.Element element; |
+ final ElementConverter converter; |
+ |
+ CpsGeneratingVisitor(this.converter, this.element); |
+ |
+ Source get currentSource => element.source; |
+ |
+ analyzer.LibraryElement get currentLibrary => element.library; |
+ |
+ ir.Node visit(AstNode node) => node.accept(this); |
+ |
+ ir.ConstructorDefinition handleConstructorDeclaration( |
+ analyzer.ConstructorElement constructor, FunctionBody body) { |
+ dart2js.ConstructorElement element = converter.convertElement(constructor); |
+ return withBuilder( |
+ new DartIrBuilder(DART_CONSTANT_SYSTEM, |
+ element, |
+ // TODO(johnniwinther): Support closure variables. |
+ new Set<dart2js.Local>()), |
+ () { |
+ irBuilder.buildFunctionHeader( |
+ constructor.parameters.map(converter.convertElement)); |
+ // Visit the body directly to avoid processing the signature as |
+ // expressions. |
+ // Call to allow for `body == null` in case of synthesized constructors. |
+ build(body); |
+ return irBuilder.makeConstructorDefinition(const [], const []); |
+ }); |
+ } |
+ |
+ ir.FieldDefinition handleFieldDeclaration( |
+ analyzer.PropertyInducingElement field, VariableDeclaration node) { |
+ dart2js.FieldElement element = converter.convertElement(field); |
+ return withBuilder( |
+ new DartIrBuilder(DART_CONSTANT_SYSTEM, |
+ element, |
+ // TODO(johnniwinther): Support closure variables. |
+ new Set<dart2js.Local>()), |
+ () { |
+ irBuilder.buildFieldInitializerHeader(); |
+ ir.Primitive initializer = build(node.initializer); |
+ return irBuilder.makeFieldDefinition(initializer); |
+ }); |
+ } |
+ |
+ ir.FunctionDefinition handleFunctionDeclaration( |
+ analyzer.ExecutableElement function, FunctionBody body) { |
+ dart2js.FunctionElement element = converter.convertElement(function); |
+ return withBuilder( |
+ new DartIrBuilder(DART_CONSTANT_SYSTEM, |
+ element, |
+ // TODO(johnniwinther): Support closure variables. |
+ new Set<dart2js.Local>()), |
+ () { |
+ irBuilder.buildFunctionHeader( |
+ function.parameters.map(converter.convertElement)); |
+ // Visit the body directly to avoid processing the signature as |
+ // expressions. |
+ visit(body); |
+ return irBuilder.makeFunctionDefinition(const []); |
+ }); |
+ } |
+ |
+ @override |
+ ir.Primitive visitFunctionExpression(FunctionExpression node) { |
+ return irBuilder.buildFunctionExpression( |
+ handleFunctionDeclaration(node.element, node.body)); |
+ } |
+ |
+ @override |
+ ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { |
+ return handleFunctionDeclaration( |
+ node.element, node.functionExpression.body); |
+ } |
+ |
+ @override |
+ visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
+ FunctionDeclaration functionDeclaration = node.functionDeclaration; |
+ analyzer.FunctionElement function = functionDeclaration.element; |
+ dart2js.FunctionElement element = converter.convertElement(function); |
+ ir.FunctionDefinition definition = handleFunctionDeclaration( |
+ function, functionDeclaration.functionExpression.body); |
+ irBuilder.declareLocalFunction(element, definition); |
+ } |
+ |
+ List<ir.Primitive> visitArguments(ArgumentList argumentList) { |
+ List<ir.Primitive> arguments = <ir.Primitive>[]; |
+ for (Expression argument in argumentList.arguments) { |
+ ir.Primitive value = build(argument); |
+ if (value == null) { |
+ giveUp(argument, |
+ 'Unsupported argument: $argument (${argument.runtimeType}).'); |
+ } |
+ arguments.add(value); |
+ } |
+ return arguments; |
+ } |
+ |
+ @override |
+ ir.Node visitMethodInvocation(MethodInvocation node) { |
+ // Overridden to avoid eager visits of the receiver and arguments. |
+ return handleMethodInvocation(node); |
+ } |
+ |
+ @override |
+ ir.Primitive visitDynamicInvocation(MethodInvocation node, |
+ AccessSemantics semantics) { |
+ // TODO(johnniwinther): Handle implicit `this`. |
+ ir.Primitive receiver = build(semantics.target); |
+ List<ir.Primitive> arguments = visitArguments(node.argumentList); |
+ return irBuilder.buildDynamicInvocation( |
+ receiver, |
+ createSelectorFromMethodInvocation( |
+ node.argumentList, node.methodName.name), |
+ arguments); |
+ } |
+ |
+ @override |
+ ir.Primitive visitStaticMethodInvocation(MethodInvocation node, |
+ AccessSemantics semantics) { |
+ analyzer.Element staticElement = semantics.element; |
+ dart2js.Element element = converter.convertElement(staticElement); |
+ List<ir.Primitive> arguments = visitArguments(node.argumentList); |
+ return irBuilder.buildStaticFunctionInvocation( |
+ element, |
+ createCallStructureFromMethodInvocation(node.argumentList), |
+ arguments); |
+ } |
+ |
+ @override |
+ ir.Node visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { |
+ return handleLocalAccess(node, semantics); |
+ } |
+ |
+ ir.Primitive handleLocalInvocation(MethodInvocation node, |
+ AccessSemantics semantics) { |
+ analyzer.Element staticElement = semantics.element; |
+ dart2js.Element element = converter.convertElement(staticElement); |
+ List<ir.Definition> arguments = visitArguments(node.argumentList); |
+ CallStructure callStructure = createCallStructureFromMethodInvocation( |
+ node.argumentList); |
+ if (semantics.kind == AccessKind.LOCAL_FUNCTION) { |
+ return irBuilder.buildLocalFunctionInvocation( |
+ element, callStructure, arguments); |
+ } else { |
+ return irBuilder.buildLocalVariableInvocation( |
+ element, callStructure, arguments); |
+ } |
+ } |
+ |
+ @override |
+ ir.Node visitLocalVariableInvocation(MethodInvocation node, |
+ AccessSemantics semantics) { |
+ return handleLocalInvocation(node, semantics); |
+ } |
+ |
+ @override |
+ ir.Primitive visitLocalFunctionInvocation(MethodInvocation node, |
+ AccessSemantics semantics) { |
+ return handleLocalInvocation(node, semantics); |
+ } |
+ |
+ @override |
+ ir.Primitive visitFunctionExpressionInvocation( |
+ FunctionExpressionInvocation node) { |
+ ir.Primitive target = build(node.function); |
+ List<ir.Definition> arguments = visitArguments(node.argumentList); |
+ return irBuilder.buildCallInvocation( |
+ target, |
+ createCallStructureFromMethodInvocation(node.argumentList), |
+ arguments); |
+ } |
+ |
+ @override |
+ ir.Primitive visitInstanceCreationExpression( |
+ InstanceCreationExpression node) { |
+ analyzer.Element staticElement = node.staticElement; |
+ if (staticElement != null) { |
+ dart2js.Element element = converter.convertElement(staticElement); |
+ dart2js.DartType type = converter.convertType(node.staticType); |
+ List<ir.Primitive> arguments = visitArguments(node.argumentList); |
+ return irBuilder.buildConstructorInvocation( |
+ element, |
+ createCallStructureFromMethodInvocation(node.argumentList), |
+ type, |
+ arguments); |
+ } |
+ return giveUp(node, "Unresolved constructor invocation."); |
+ } |
+ |
+ @override |
+ ir.Constant visitNullLiteral(NullLiteral node) { |
+ return irBuilder.buildNullConstant(); |
+ } |
+ |
+ @override |
+ ir.Constant visitBooleanLiteral(BooleanLiteral node) { |
+ return irBuilder.buildBooleanConstant(node.value); |
+ } |
+ |
+ @override |
+ ir.Constant visitDoubleLiteral(DoubleLiteral node) { |
+ return irBuilder.buildDoubleConstant(node.value); |
+ } |
+ |
+ @override |
+ ir.Constant visitIntegerLiteral(IntegerLiteral node) { |
+ return irBuilder.buildIntegerConstant(node.value); |
+ } |
+ |
+ @override |
+ visitAdjacentStrings(AdjacentStrings node) { |
+ String value = node.stringValue; |
+ if (value != null) { |
+ return irBuilder.buildStringConstant(value); |
+ } |
+ giveUp(node, "Non constant adjacent strings."); |
+ } |
+ |
+ @override |
+ ir.Constant visitSimpleStringLiteral(SimpleStringLiteral node) { |
+ return irBuilder.buildStringConstant(node.value); |
+ } |
+ |
+ @override |
+ visitStringInterpolation(StringInterpolation node) { |
+ giveUp(node, "String interpolation."); |
+ } |
+ |
+ @override |
+ visitReturnStatement(ReturnStatement node) { |
+ irBuilder.buildReturn(build(node.expression)); |
+ } |
+ |
+ @override |
+ ir.Node visitPropertyAccess(PropertyAccess node) { |
+ // Overridden to avoid eager visits of the receiver. |
+ return handlePropertyAccess(node); |
+ } |
+ |
+ @override |
+ ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { |
+ return handleLocalAccess(node, semantics); |
+ } |
+ |
+ @override |
+ ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { |
+ return handleLocalAccess(node, semantics); |
+ } |
+ |
+ @override |
+ visitVariableDeclaration(VariableDeclaration node) { |
+ // TODO(johnniwinther): Handle constant local variables. |
+ ir.Node initialValue = build(node.initializer); |
+ irBuilder.declareLocalVariable( |
+ converter.convertElement(node.element), |
+ initialValue: initialValue); |
+ } |
+ |
+ dart2js.Element getLocal(AstNode node, AccessSemantics semantics) { |
+ analyzer.Element element = semantics.element; |
+ dart2js.Element target = converter.convertElement(element); |
+ assert(invariant(node, target.isLocal, '$target expected to be local.')); |
+ return target; |
+ } |
+ |
+ ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { |
+ dart2js.Element local = getLocal(node, semantics); |
+ if (semantics.kind == AccessKind.LOCAL_FUNCTION) { |
+ return irBuilder.buildLocalFunctionGet(local); |
+ } else { |
+ return irBuilder.buildLocalVariableGet(local); |
+ } |
+ } |
+ |
+ ir.Primitive handleLocalAssignment(AssignmentExpression node, |
+ AccessSemantics semantics) { |
+ if (node.operator.lexeme != '=') { |
+ return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); |
+ } |
+ return irBuilder.buildLocalVariableSet( |
+ getLocal(node, semantics), |
+ build(node.rightHandSide)); |
+ } |
+ |
+ @override |
+ ir.Node visitAssignmentExpression(AssignmentExpression node) { |
+ // Avoid eager visiting of left and right hand side. |
+ return handleAssignmentExpression(node); |
+ } |
+ |
+ @override |
+ ir.Node visitLocalVariableAssignment(AssignmentExpression node, |
+ AccessSemantics semantics) { |
+ return handleLocalAssignment(node, semantics); |
+ } |
+ |
+ @override |
+ ir.Node visitParameterAssignment(AssignmentExpression node, |
+ AccessSemantics semantics) { |
+ return handleLocalAssignment(node, semantics); |
+ } |
+ |
+ @override |
+ ir.Node visitStaticFieldAssignment(AssignmentExpression node, |
+ AccessSemantics semantics) { |
+ if (node.operator.lexeme != '=') { |
+ return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); |
+ } |
+ analyzer.Element element = semantics.element; |
+ dart2js.Element target = converter.convertElement(element); |
+ // TODO(johnniwinther): Selector information should be computed in the |
+ // [TreeShaker] and shared with the [CpsGeneratingVisitor]. |
+ assert(invariant(node, target.isTopLevel || target.isStatic, |
+ '$target expected to be top-level or static.')); |
+ return irBuilder.buildStaticFieldSet(target, build(node.rightHandSide)); |
+ } |
+ |
+ @override |
+ ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { |
+ // TODO(johnniwinther): Handle implicit `this`. |
+ ir.Primitive receiver = build(semantics.target); |
+ return irBuilder.buildDynamicGet(receiver, |
+ new Selector.getter(semantics.identifier.name, |
+ converter.convertElement(element.library))); |
+ } |
+ |
+ @override |
+ ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { |
+ analyzer.Element element = semantics.element; |
+ dart2js.Element target = converter.convertElement(element); |
+ // TODO(johnniwinther): Selector information should be computed in the |
+ // [TreeShaker] and shared with the [CpsGeneratingVisitor]. |
+ assert(invariant(node, target.isTopLevel || target.isStatic, |
+ '$target expected to be top-level or static.')); |
+ return irBuilder.buildStaticFieldLazyGet(target, null); |
+ } |
+ |
+ ir.Primitive handleBinaryExpression(BinaryExpression node, |
+ String op) { |
+ ir.Primitive left = build(node.leftOperand); |
+ ir.Primitive right = build(node.rightOperand); |
+ Selector selector = new Selector.binaryOperator(op); |
+ return irBuilder.buildDynamicInvocation( |
+ left, selector, <ir.Primitive>[right]); |
+ } |
+ |
+ ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { |
+ return irBuilder.buildLogicalOperator( |
+ build(node.leftOperand), |
+ subbuild(node.rightOperand), |
+ isLazyOr: isLazyOr); |
+ } |
+ |
+ @override |
+ ir.Node visitBinaryExpression(BinaryExpression node) { |
+ // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be |
+ // available through an enum. |
+ String op = node.operator.lexeme; |
+ switch (op) { |
+ case '||': |
+ case '&&': |
+ return handleLazyOperator(node, isLazyOr: op == '||'); |
+ case '!=': |
+ return irBuilder.buildNegation(handleBinaryExpression(node, '==')); |
+ default: |
+ return handleBinaryExpression(node, op); |
+ } |
+ } |
+ |
+ @override |
+ ir.Node visitConditionalExpression(ConditionalExpression node) { |
+ return irBuilder.buildConditional( |
+ build(node.condition), |
+ subbuild(node.thenExpression), |
+ subbuild(node.elseExpression)); |
+ } |
+ |
+ @override |
+ visitIfStatement(IfStatement node) { |
+ irBuilder.buildIf( |
+ build(node.condition), |
+ subbuild(node.thenStatement), |
+ subbuild(node.elseStatement)); |
+ } |
+ |
+ @override |
+ visitBlock(Block node) { |
+ irBuilder.buildBlock(node.statements, build); |
+ } |
+ |
+ @override |
+ ir.Node visitListLiteral(ListLiteral node) { |
+ dart2js.InterfaceType type = converter.convertType(node.staticType); |
+ // TODO(johnniwinther): Use `build` instead of `(e) => build(e)` when issue |
+ // 18630 has been resolved. |
+ Iterable<ir.Primitive> values = node.elements.map((e) => build(e)); |
+ return irBuilder.buildListLiteral(type, values); |
+ } |
+ |
+ @override |
+ ir.Node visitMapLiteral(MapLiteral node) { |
+ dart2js.InterfaceType type = converter.convertType(node.staticType); |
+ return irBuilder.buildMapLiteral( |
+ type, |
+ node.entries.map((e) => e.key), |
+ node.entries.map((e) => e.value), |
+ build); |
+ } |
+ |
+ @override |
+ visitForStatement(ForStatement node) { |
+ // TODO(johnniwinther): Support `for` as a jump target. |
+ List<dart2js.LocalElement> loopVariables = <dart2js.LocalElement>[]; |
+ SubbuildFunction buildInitializer; |
+ if (node.variables != null) { |
+ buildInitializer = subbuild(node.variables); |
+ for (VariableDeclaration variable in node.variables.variables) { |
+ loopVariables.add(converter.convertElement(variable.element)); |
+ } |
+ } else { |
+ buildInitializer = subbuild(node.initialization); |
+ } |
+ irBuilder.buildFor(buildInitializer: buildInitializer, |
+ buildCondition: subbuild(node.condition), |
+ buildBody: subbuild(node.body), |
+ buildUpdate: subbuildSequence(node.updaters), |
+ loopVariables: loopVariables); |
+ } |
+ |
+ @override |
+ visitWhileStatement(WhileStatement node) { |
+ // TODO(johnniwinther): Support `while` as a jump target. |
+ irBuilder.buildWhile(buildCondition: subbuild(node.condition), |
+ buildBody: subbuild(node.body)); |
+ } |
+ |
+ @override |
+ visitDeclaredIdentifier(DeclaredIdentifier node) { |
+ giveUp(node, "Unexpected node: DeclaredIdentifier"); |
+ } |
+ |
+ @override |
+ visitForEachStatement(ForEachStatement node) { |
+ SubbuildFunction buildVariableDeclaration; |
+ dart2js.Element variableElement; |
+ Selector variableSelector; |
+ if (node.identifier != null) { |
+ AccessSemantics accessSemantics = |
+ node.identifier.accept(ACCESS_SEMANTICS_VISITOR); |
+ if (accessSemantics.kind == AccessKind.DYNAMIC) { |
+ variableSelector = new Selector.setter( |
+ node.identifier.name, converter.convertElement(currentLibrary)); |
+ } else if (accessSemantics.element != null) { |
+ variableElement = converter.convertElement(accessSemantics.element); |
+ variableSelector = new Selector.setter( |
+ variableElement.name, |
+ converter.convertElement(accessSemantics.element.library)); |
+ } else { |
+ giveUp(node, 'For-in of unresolved variable: $accessSemantics'); |
+ } |
+ } else { |
+ assert(invariant( |
+ node, node.loopVariable != null, "Loop variable expected")); |
+ variableElement = converter.convertElement(node.loopVariable.element); |
+ buildVariableDeclaration = (IrBuilder builder) { |
+ builder.declareLocalVariable(variableElement); |
+ }; |
+ } |
+ // TODO(johnniwinther): Support `for-in` as a jump target. |
+ irBuilder.buildForIn( |
+ buildExpression: subbuild(node.iterable), |
+ buildVariableDeclaration: buildVariableDeclaration, |
+ variableElement: variableElement, |
+ variableSelector: variableSelector, |
+ buildBody: subbuild(node.body)); |
+ } |
+ @override |
+ ir.Primitive visitIsExpression(IsExpression node) { |
+ return irBuilder.buildTypeOperator( |
+ visit(node.expression), |
+ converter.convertType(node.type.type), |
+ isTypeTest: true, |
+ isNotCheck: node.notOperator != null); |
+ } |
+ |
+ @override |
+ ir.Primitive visitAsExpression(AsExpression node) { |
+ return irBuilder.buildTypeOperator( |
+ visit(node.expression), |
+ converter.convertType(node.type.type), |
+ isTypeTest: false); |
+ } |
+ |
+ @override |
+ visitTryStatement(TryStatement node) { |
+ List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; |
+ for (CatchClause catchClause in node.catchClauses) { |
+ catchClauseInfos.add(new CatchClauseInfo( |
+ exceptionVariable: converter.convertElement( |
+ catchClause.exceptionParameter.staticElement), |
+ buildCatchBlock: subbuild(catchClause.body))); |
+ |
+ } |
+ irBuilder.buildTry( |
+ tryStatementInfo: new TryStatementInfo(), |
+ buildTryBlock: subbuild(node.body), |
+ catchClauseInfos: catchClauseInfos); |
+ } |
+} |