| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 analyzer2dart.cps_generator; | 5 library analyzer2dart.cps_generator; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
| 8 | 8 |
| 9 import 'package:compiler/implementation/elements/elements.dart' as dart2js; | 9 import 'package:compiler/implementation/elements/elements.dart' as dart2js; |
| 10 import 'package:analyzer/src/generated/source.dart'; | 10 import 'package:analyzer/src/generated/source.dart'; |
| 11 import 'package:analyzer/src/generated/element.dart' as analyzer; | 11 import 'package:analyzer/src/generated/element.dart' as analyzer; |
| 12 | 12 |
| 13 import 'package:compiler/implementation/dart2jslib.dart' | 13 import 'package:compiler/implementation/dart2jslib.dart' |
| 14 show DART_CONSTANT_SYSTEM; | 14 show DART_CONSTANT_SYSTEM; |
| 15 import 'package:compiler/implementation/cps_ir/cps_ir_nodes.dart' as ir; | 15 import 'package:compiler/implementation/cps_ir/cps_ir_nodes.dart' as ir; |
| 16 import 'package:compiler/implementation/cps_ir/cps_ir_builder.dart'; | 16 import 'package:compiler/implementation/cps_ir/cps_ir_builder.dart'; |
| 17 import 'package:compiler/implementation/universe/universe.dart'; | 17 import 'package:compiler/implementation/universe/universe.dart'; |
| 18 | 18 |
| 19 import 'semantic_visitor.dart'; | 19 import 'semantic_visitor.dart'; |
| 20 import 'element_converter.dart'; | 20 import 'element_converter.dart'; |
| 21 import 'util.dart'; | 21 import 'util.dart'; |
| 22 import 'identifier_semantics.dart'; | 22 import 'identifier_semantics.dart'; |
| 23 | 23 |
| 24 class CpsGeneratingVisitor extends SemanticVisitor<ir.Node> | 24 class CpsGeneratingVisitor extends SemanticVisitor<ir.Node> |
| 25 with IrBuilderMixin { | 25 with IrBuilderMixin<AstNode> { |
| 26 final analyzer.Element element; | 26 final analyzer.Element element; |
| 27 final ElementConverter converter; | 27 final ElementConverter converter; |
| 28 | 28 |
| 29 CpsGeneratingVisitor(this.converter, this.element); | 29 CpsGeneratingVisitor(this.converter, this.element); |
| 30 | 30 |
| 31 Source get currentSource => element.source; | 31 Source get currentSource => element.source; |
| 32 | 32 |
| 33 ir.Node visit(AstNode node) => node.accept(this); |
| 34 |
| 33 @override | 35 @override |
| 34 ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { | 36 ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { |
| 35 analyzer.FunctionElement function = node.element; | 37 analyzer.FunctionElement function = node.element; |
| 36 dart2js.FunctionElement element = converter.convertElement(function); | 38 dart2js.FunctionElement element = converter.convertElement(function); |
| 37 return withBuilder( | 39 return withBuilder( |
| 38 new IrBuilder(DART_CONSTANT_SYSTEM, | 40 new IrBuilder(DART_CONSTANT_SYSTEM, |
| 39 element, | 41 element, |
| 40 // TODO(johnniwinther): Supported closure variables. | 42 // TODO(johnniwinther): Supported closure variables. |
| 41 const <dart2js.Local>[]), | 43 const <dart2js.Local>[]), |
| 42 () { | 44 () { |
| 43 function.parameters.forEach((analyzer.ParameterElement parameter) { | 45 function.parameters.forEach((analyzer.ParameterElement parameter) { |
| 44 // TODO(johnniwinther): Support "closure variables", that is variables | 46 // TODO(johnniwinther): Support "closure variables", that is variables |
| 45 // accessed from an inner function. | 47 // accessed from an inner function. |
| 46 irBuilder.createParameter(converter.convertElement(parameter), | 48 irBuilder.createParameter(converter.convertElement(parameter), |
| 47 isClosureVariable: false); | 49 isClosureVariable: false); |
| 48 }); | 50 }); |
| 49 // Visit the body directly to avoid processing the signature as | 51 // Visit the body directly to avoid processing the signature as |
| 50 // expressions. | 52 // expressions. |
| 51 node.functionExpression.body.accept(this); | 53 visit(node.functionExpression.body); |
| 52 return irBuilder.buildFunctionDefinition(element, const []); | 54 return irBuilder.buildFunctionDefinition(element, const []); |
| 53 }); | 55 }); |
| 54 } | 56 } |
| 55 | 57 |
| 56 List<ir.Definition> visitArguments(ArgumentList argumentList) { | 58 List<ir.Definition> visitArguments(ArgumentList argumentList) { |
| 57 List<ir.Definition> arguments = <ir.Definition>[]; | 59 List<ir.Definition> arguments = <ir.Definition>[]; |
| 58 for (Expression argument in argumentList.arguments) { | 60 for (Expression argument in argumentList.arguments) { |
| 59 ir.Definition value = argument.accept(this); | 61 ir.Definition value = build(argument); |
| 60 if (value == null) { | 62 if (value == null) { |
| 61 giveUp(argument, | 63 giveUp(argument, |
| 62 'Unsupported argument: $argument (${argument.runtimeType}).'); | 64 'Unsupported argument: $argument (${argument.runtimeType}).'); |
| 63 } | 65 } |
| 64 arguments.add(value); | 66 arguments.add(value); |
| 65 } | 67 } |
| 66 return arguments; | 68 return arguments; |
| 67 } | 69 } |
| 68 | 70 |
| 69 @override | 71 @override |
| 70 ir.Primitive visitDynamicInvocation(MethodInvocation node, | 72 ir.Primitive visitDynamicInvocation(MethodInvocation node, |
| 71 AccessSemantics semantics) { | 73 AccessSemantics semantics) { |
| 72 // TODO(johnniwinther): Handle implicit `this`. | 74 // TODO(johnniwinther): Handle implicit `this`. |
| 73 ir.Primitive receiver = semantics.target.accept(this); | 75 ir.Primitive receiver = build(semantics.target); |
| 74 List<ir.Definition> arguments = visitArguments(node.argumentList); | 76 List<ir.Definition> arguments = visitArguments(node.argumentList); |
| 75 return irBuilder.buildDynamicInvocation( | 77 return irBuilder.buildDynamicInvocation( |
| 76 receiver, | 78 receiver, |
| 77 createSelectorFromMethodInvocation(node, node.methodName.name), | 79 createSelectorFromMethodInvocation(node, node.methodName.name), |
| 78 arguments); | 80 arguments); |
| 79 } | 81 } |
| 80 | 82 |
| 81 @override | 83 @override |
| 82 ir.Primitive visitStaticMethodInvocation(MethodInvocation node, | 84 ir.Primitive visitStaticMethodInvocation(MethodInvocation node, |
| 83 AccessSemantics semantics) { | 85 AccessSemantics semantics) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 return irBuilder.buildStringLiteral(node.value); | 126 return irBuilder.buildStringLiteral(node.value); |
| 125 } | 127 } |
| 126 | 128 |
| 127 @override | 129 @override |
| 128 visitStringInterpolation(StringInterpolation node) { | 130 visitStringInterpolation(StringInterpolation node) { |
| 129 giveUp(node, "String interpolation."); | 131 giveUp(node, "String interpolation."); |
| 130 } | 132 } |
| 131 | 133 |
| 132 @override | 134 @override |
| 133 visitReturnStatement(ReturnStatement node) { | 135 visitReturnStatement(ReturnStatement node) { |
| 134 if (node.expression != null) { | 136 irBuilder.buildReturn(build(node.expression)); |
| 135 irBuilder.buildReturn(node.expression.accept(this)); | |
| 136 } else { | |
| 137 irBuilder.buildReturn(); | |
| 138 } | |
| 139 } | 137 } |
| 140 | 138 |
| 141 @override | 139 @override |
| 142 ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { | 140 ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { |
| 143 return handleLocalAccess(node, semantics); | 141 return handleLocalAccess(node, semantics); |
| 144 } | 142 } |
| 145 | 143 |
| 146 @override | 144 @override |
| 147 ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { | 145 ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { |
| 148 return handleLocalAccess(node, semantics); | 146 return handleLocalAccess(node, semantics); |
| 149 } | 147 } |
| 150 | 148 |
| 151 @override | 149 @override |
| 152 visitVariableDeclaration(VariableDeclaration node) { | 150 visitVariableDeclaration(VariableDeclaration node) { |
| 153 // TODO(johnniwinther): Handle constant local variables. | 151 // TODO(johnniwinther): Handle constant local variables. |
| 154 ir.Node initialValue; | 152 ir.Node initialValue = build(node.initializer); |
| 155 if (node.initializer != null) { | |
| 156 initialValue = node.initializer.accept(this); | |
| 157 } | |
| 158 irBuilder.declareLocalVariable( | 153 irBuilder.declareLocalVariable( |
| 159 converter.convertElement(node.element), | 154 converter.convertElement(node.element), |
| 160 initialValue: initialValue); | 155 initialValue: initialValue); |
| 161 } | 156 } |
| 162 | 157 |
| 163 ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { | 158 ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { |
| 164 analyzer.Element element = semantics.element; | 159 analyzer.Element element = semantics.element; |
| 165 dart2js.Element target = converter.convertElement(element); | 160 dart2js.Element target = converter.convertElement(element); |
| 166 assert(invariant(node, target.isLocal, '$target expected to be local.')); | 161 assert(invariant(node, target.isLocal, '$target expected to be local.')); |
| 167 return irBuilder.buildLocalGet(target); | 162 return irBuilder.buildLocalGet(target); |
| 168 } | 163 } |
| 169 | 164 |
| 170 @override | 165 @override |
| 171 ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { | 166 ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { |
| 172 // TODO(johnniwinther): Handle implicit `this`. | 167 // TODO(johnniwinther): Handle implicit `this`. |
| 173 ir.Primitive receiver = semantics.target.accept(this); | 168 ir.Primitive receiver = build(semantics.target); |
| 174 return irBuilder.buildDynamicGet(receiver, | 169 return irBuilder.buildDynamicGet(receiver, |
| 175 new Selector.getter(semantics.identifier.name, | 170 new Selector.getter(semantics.identifier.name, |
| 176 converter.convertElement(element.library))); | 171 converter.convertElement(element.library))); |
| 177 } | 172 } |
| 178 | 173 |
| 179 @override | 174 @override |
| 180 ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { | 175 ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { |
| 181 analyzer.Element element = semantics.element; | 176 analyzer.Element element = semantics.element; |
| 182 dart2js.Element target = converter.convertElement(element); | 177 dart2js.Element target = converter.convertElement(element); |
| 183 // TODO(johnniwinther): Selector information should be computed in the | 178 // TODO(johnniwinther): Selector information should be computed in the |
| 184 // [TreeShaker] and shared with the [CpsGeneratingVisitor]. | 179 // [TreeShaker] and shared with the [CpsGeneratingVisitor]. |
| 185 assert(invariant(node, target.isTopLevel || target.isStatic, | 180 assert(invariant(node, target.isTopLevel || target.isStatic, |
| 186 '$target expected to be top-level or static.')); | 181 '$target expected to be top-level or static.')); |
| 187 return irBuilder.buildStaticGet(target, | 182 return irBuilder.buildStaticGet(target, |
| 188 new Selector.getter(target.name, target.library)); | 183 new Selector.getter(target.name, target.library)); |
| 189 } | 184 } |
| 190 | 185 |
| 191 ir.Primitive handleBinaryExpression(BinaryExpression node, | 186 ir.Primitive handleBinaryExpression(BinaryExpression node, |
| 192 String op) { | 187 String op) { |
| 193 ir.Primitive left = node.leftOperand.accept(this); | 188 ir.Primitive left = build(node.leftOperand); |
| 194 ir.Primitive right = node.rightOperand.accept(this); | 189 ir.Primitive right = build(node.rightOperand); |
| 195 Selector selector = new Selector.binaryOperator(op); | 190 Selector selector = new Selector.binaryOperator(op); |
| 196 return irBuilder.buildDynamicInvocation( | 191 return irBuilder.buildDynamicInvocation( |
| 197 left, selector, <ir.Definition>[right]); | 192 left, selector, <ir.Definition>[right]); |
| 198 } | 193 } |
| 199 | 194 |
| 200 ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { | 195 ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { |
| 201 ir.Primitive left = node.leftOperand.accept(this); | |
| 202 ir.Primitive buildRightValue(IrBuilder builder) { | |
| 203 return withBuilder(builder, () => node.rightOperand.accept(this)); | |
| 204 } | |
| 205 return irBuilder.buildLogicalOperator( | 196 return irBuilder.buildLogicalOperator( |
| 206 left, buildRightValue, isLazyOr: isLazyOr); | 197 build(node.leftOperand), |
| 198 subbuild(node.rightOperand), |
| 199 isLazyOr: isLazyOr); |
| 207 } | 200 } |
| 208 | 201 |
| 209 @override | 202 @override |
| 210 ir.Node visitBinaryExpression(BinaryExpression node) { | 203 ir.Node visitBinaryExpression(BinaryExpression node) { |
| 211 // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be | 204 // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be |
| 212 // available through an enum. | 205 // available through an enum. |
| 213 String op = node.operator.lexeme; | 206 String op = node.operator.lexeme; |
| 214 switch (op) { | 207 switch (op) { |
| 215 case '||': | 208 case '||': |
| 216 case '&&': | 209 case '&&': |
| 217 return handleLazyOperator(node, isLazyOr: op == '||'); | 210 return handleLazyOperator(node, isLazyOr: op == '||'); |
| 218 case '!=': | 211 case '!=': |
| 219 return irBuilder.buildNegation(handleBinaryExpression(node, '==')); | 212 return irBuilder.buildNegation(handleBinaryExpression(node, '==')); |
| 220 default: | 213 default: |
| 221 return handleBinaryExpression(node, op); | 214 return handleBinaryExpression(node, op); |
| 222 } | 215 } |
| 223 } | 216 } |
| 224 | 217 |
| 225 @override | 218 @override |
| 219 ir.Node visitConditionalExpression(ConditionalExpression node) { |
| 220 return irBuilder.buildConditional( |
| 221 build(node.condition), |
| 222 subbuild(node.thenExpression), |
| 223 subbuild(node.elseExpression)); |
| 224 } |
| 225 |
| 226 @override |
| 226 visitIfStatement(IfStatement node) { | 227 visitIfStatement(IfStatement node) { |
| 227 ir.Primitive condition = node.condition.accept(this); | 228 irBuilder.buildIf( |
| 228 | 229 build(node.condition), |
| 229 void buildThenPart(IrBuilder thenBuilder) { | 230 subbuild(node.thenStatement), |
| 230 withBuilder(thenBuilder, () => node.thenStatement.accept(this)); | 231 subbuild(node.elseStatement)); |
| 231 } | |
| 232 | |
| 233 void buildElsePart(IrBuilder elseBuilder) { | |
| 234 if (node.elseStatement != null) { | |
| 235 withBuilder(elseBuilder, () => node.elseStatement.accept(this)); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 irBuilder.buildIf(condition, buildThenPart, buildElsePart); | |
| 240 } | 232 } |
| 241 } | 233 } |
| OLD | NEW |