| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library analyzer2dart.cps_generator; | |
| 6 | |
| 7 import 'package:analyzer/analyzer.dart'; | |
| 8 | |
| 9 import 'package:compiler/src/dart_types.dart' as dart2js; | |
| 10 import 'package:compiler/src/elements/elements.dart' as dart2js; | |
| 11 import 'package:analyzer/src/generated/source.dart'; | |
| 12 import 'package:analyzer/src/generated/element.dart' as analyzer; | |
| 13 | |
| 14 import 'package:compiler/src/constant_system_dart.dart' | |
| 15 show DART_CONSTANT_SYSTEM; | |
| 16 import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; | |
| 17 import 'package:compiler/src/cps_ir/cps_ir_builder.dart'; | |
| 18 import 'package:compiler/src/universe/universe.dart'; | |
| 19 | |
| 20 import 'semantic_visitor.dart'; | |
| 21 import 'element_converter.dart'; | |
| 22 import 'util.dart'; | |
| 23 import 'identifier_semantics.dart'; | |
| 24 | |
| 25 /// Visitor that converts the AST node of an analyzer element into a CPS ir | |
| 26 /// node. | |
| 27 class CpsElementVisitor extends analyzer.SimpleElementVisitor<ir.Node> { | |
| 28 final ElementConverter converter; | |
| 29 final AstNode node; | |
| 30 | |
| 31 CpsElementVisitor(this.converter, this.node); | |
| 32 | |
| 33 @override | |
| 34 ir.FunctionDefinition visitFunctionElement(analyzer.FunctionElement element) { | |
| 35 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
| 36 FunctionDeclaration functionDeclaration = node; | |
| 37 return visitor.handleFunctionDeclaration( | |
| 38 element, functionDeclaration.functionExpression.body); | |
| 39 } | |
| 40 | |
| 41 @override | |
| 42 ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) { | |
| 43 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
| 44 MethodDeclaration methodDeclaration = node; | |
| 45 return visitor.handleFunctionDeclaration(element, methodDeclaration.body); | |
| 46 } | |
| 47 | |
| 48 @override | |
| 49 ir.FieldDefinition visitTopLevelVariableElement( | |
| 50 analyzer.TopLevelVariableElement element) { | |
| 51 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
| 52 VariableDeclaration variableDeclaration = node; | |
| 53 return visitor.handleFieldDeclaration(element, variableDeclaration); | |
| 54 } | |
| 55 | |
| 56 @override | |
| 57 ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) { | |
| 58 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
| 59 if (!element.isFactory) { | |
| 60 ConstructorDeclaration constructorDeclaration = node; | |
| 61 FunctionBody body; | |
| 62 if (constructorDeclaration != null) { | |
| 63 body = constructorDeclaration.body; | |
| 64 } else { | |
| 65 assert(element.isSynthetic); | |
| 66 } | |
| 67 return visitor.handleConstructorDeclaration(element, body); | |
| 68 } | |
| 69 // TODO(johnniwinther): Support factory constructors. | |
| 70 return null; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 /// Visitor that converts analyzer AST nodes into CPS ir nodes. | |
| 75 class CpsGeneratingVisitor extends SemanticVisitor<ir.Node> | |
| 76 with IrBuilderMixin<AstNode> { | |
| 77 /// Promote the type of [irBuilder] to [DartIrBuilder]. | |
| 78 /// The JS backend requires closure conversion which we do not support yet. | |
| 79 DartIrBuilder get irBuilder => super.irBuilder; | |
| 80 final analyzer.Element element; | |
| 81 final ElementConverter converter; | |
| 82 | |
| 83 CpsGeneratingVisitor(this.converter, this.element); | |
| 84 | |
| 85 Source get currentSource => element.source; | |
| 86 | |
| 87 analyzer.LibraryElement get currentLibrary => element.library; | |
| 88 | |
| 89 ir.Node visit(AstNode node) => node.accept(this); | |
| 90 | |
| 91 ir.ConstructorDefinition handleConstructorDeclaration( | |
| 92 analyzer.ConstructorElement constructor, FunctionBody body) { | |
| 93 dart2js.ConstructorElement element = converter.convertElement(constructor); | |
| 94 return withBuilder( | |
| 95 new DartIrBuilder(DART_CONSTANT_SYSTEM, | |
| 96 element, | |
| 97 // TODO(johnniwinther): Support closure variables. | |
| 98 new Set<dart2js.Local>()), | |
| 99 () { | |
| 100 irBuilder.buildFunctionHeader( | |
| 101 constructor.parameters.map(converter.convertElement)); | |
| 102 // Visit the body directly to avoid processing the signature as | |
| 103 // expressions. | |
| 104 // Call to allow for `body == null` in case of synthesized constructors. | |
| 105 build(body); | |
| 106 return irBuilder.makeConstructorDefinition(const [], const []); | |
| 107 }); | |
| 108 } | |
| 109 | |
| 110 ir.FieldDefinition handleFieldDeclaration( | |
| 111 analyzer.PropertyInducingElement field, VariableDeclaration node) { | |
| 112 dart2js.FieldElement element = converter.convertElement(field); | |
| 113 return withBuilder( | |
| 114 new DartIrBuilder(DART_CONSTANT_SYSTEM, | |
| 115 element, | |
| 116 // TODO(johnniwinther): Support closure variables. | |
| 117 new Set<dart2js.Local>()), | |
| 118 () { | |
| 119 irBuilder.buildFieldInitializerHeader(); | |
| 120 ir.Primitive initializer = build(node.initializer); | |
| 121 return irBuilder.makeFieldDefinition(initializer); | |
| 122 }); | |
| 123 } | |
| 124 | |
| 125 ir.FunctionDefinition handleFunctionDeclaration( | |
| 126 analyzer.ExecutableElement function, FunctionBody body) { | |
| 127 dart2js.FunctionElement element = converter.convertElement(function); | |
| 128 return withBuilder( | |
| 129 new DartIrBuilder(DART_CONSTANT_SYSTEM, | |
| 130 element, | |
| 131 // TODO(johnniwinther): Support closure variables. | |
| 132 new Set<dart2js.Local>()), | |
| 133 () { | |
| 134 irBuilder.buildFunctionHeader( | |
| 135 function.parameters.map(converter.convertElement)); | |
| 136 // Visit the body directly to avoid processing the signature as | |
| 137 // expressions. | |
| 138 visit(body); | |
| 139 return irBuilder.makeFunctionDefinition(const []); | |
| 140 }); | |
| 141 } | |
| 142 | |
| 143 @override | |
| 144 ir.Primitive visitFunctionExpression(FunctionExpression node) { | |
| 145 return irBuilder.buildFunctionExpression( | |
| 146 handleFunctionDeclaration(node.element, node.body)); | |
| 147 } | |
| 148 | |
| 149 @override | |
| 150 ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { | |
| 151 return handleFunctionDeclaration( | |
| 152 node.element, node.functionExpression.body); | |
| 153 } | |
| 154 | |
| 155 @override | |
| 156 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | |
| 157 FunctionDeclaration functionDeclaration = node.functionDeclaration; | |
| 158 analyzer.FunctionElement function = functionDeclaration.element; | |
| 159 dart2js.FunctionElement element = converter.convertElement(function); | |
| 160 ir.FunctionDefinition definition = handleFunctionDeclaration( | |
| 161 function, functionDeclaration.functionExpression.body); | |
| 162 irBuilder.declareLocalFunction(element, definition); | |
| 163 } | |
| 164 | |
| 165 List<ir.Primitive> visitArguments(ArgumentList argumentList) { | |
| 166 List<ir.Primitive> arguments = <ir.Primitive>[]; | |
| 167 for (Expression argument in argumentList.arguments) { | |
| 168 ir.Primitive value = build(argument); | |
| 169 if (value == null) { | |
| 170 giveUp(argument, | |
| 171 'Unsupported argument: $argument (${argument.runtimeType}).'); | |
| 172 } | |
| 173 arguments.add(value); | |
| 174 } | |
| 175 return arguments; | |
| 176 } | |
| 177 | |
| 178 @override | |
| 179 ir.Node visitMethodInvocation(MethodInvocation node) { | |
| 180 // Overridden to avoid eager visits of the receiver and arguments. | |
| 181 return handleMethodInvocation(node); | |
| 182 } | |
| 183 | |
| 184 @override | |
| 185 ir.Primitive visitDynamicInvocation(MethodInvocation node, | |
| 186 AccessSemantics semantics) { | |
| 187 // TODO(johnniwinther): Handle implicit `this`. | |
| 188 ir.Primitive receiver = build(semantics.target); | |
| 189 List<ir.Primitive> arguments = visitArguments(node.argumentList); | |
| 190 return irBuilder.buildDynamicInvocation( | |
| 191 receiver, | |
| 192 createSelectorFromMethodInvocation( | |
| 193 node.argumentList, node.methodName.name), | |
| 194 arguments); | |
| 195 } | |
| 196 | |
| 197 @override | |
| 198 ir.Primitive visitStaticMethodInvocation(MethodInvocation node, | |
| 199 AccessSemantics semantics) { | |
| 200 analyzer.Element staticElement = semantics.element; | |
| 201 dart2js.Element element = converter.convertElement(staticElement); | |
| 202 List<ir.Primitive> arguments = visitArguments(node.argumentList); | |
| 203 return irBuilder.buildStaticFunctionInvocation( | |
| 204 element, | |
| 205 createCallStructureFromMethodInvocation(node.argumentList), | |
| 206 arguments); | |
| 207 } | |
| 208 | |
| 209 @override | |
| 210 ir.Node visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { | |
| 211 return handleLocalAccess(node, semantics); | |
| 212 } | |
| 213 | |
| 214 ir.Primitive handleLocalInvocation(MethodInvocation node, | |
| 215 AccessSemantics semantics) { | |
| 216 analyzer.Element staticElement = semantics.element; | |
| 217 dart2js.Element element = converter.convertElement(staticElement); | |
| 218 List<ir.Definition> arguments = visitArguments(node.argumentList); | |
| 219 CallStructure callStructure = createCallStructureFromMethodInvocation( | |
| 220 node.argumentList); | |
| 221 if (semantics.kind == AccessKind.LOCAL_FUNCTION) { | |
| 222 return irBuilder.buildLocalFunctionInvocation( | |
| 223 element, callStructure, arguments); | |
| 224 } else { | |
| 225 return irBuilder.buildLocalVariableInvocation( | |
| 226 element, callStructure, arguments); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 @override | |
| 231 ir.Node visitLocalVariableInvocation(MethodInvocation node, | |
| 232 AccessSemantics semantics) { | |
| 233 return handleLocalInvocation(node, semantics); | |
| 234 } | |
| 235 | |
| 236 @override | |
| 237 ir.Primitive visitLocalFunctionInvocation(MethodInvocation node, | |
| 238 AccessSemantics semantics) { | |
| 239 return handleLocalInvocation(node, semantics); | |
| 240 } | |
| 241 | |
| 242 @override | |
| 243 ir.Primitive visitFunctionExpressionInvocation( | |
| 244 FunctionExpressionInvocation node) { | |
| 245 ir.Primitive target = build(node.function); | |
| 246 List<ir.Definition> arguments = visitArguments(node.argumentList); | |
| 247 return irBuilder.buildCallInvocation( | |
| 248 target, | |
| 249 createCallStructureFromMethodInvocation(node.argumentList), | |
| 250 arguments); | |
| 251 } | |
| 252 | |
| 253 @override | |
| 254 ir.Primitive visitInstanceCreationExpression( | |
| 255 InstanceCreationExpression node) { | |
| 256 analyzer.Element staticElement = node.staticElement; | |
| 257 if (staticElement != null) { | |
| 258 dart2js.Element element = converter.convertElement(staticElement); | |
| 259 dart2js.DartType type = converter.convertType(node.staticType); | |
| 260 List<ir.Primitive> arguments = visitArguments(node.argumentList); | |
| 261 return irBuilder.buildConstructorInvocation( | |
| 262 element, | |
| 263 createCallStructureFromMethodInvocation(node.argumentList), | |
| 264 type, | |
| 265 arguments); | |
| 266 } | |
| 267 return giveUp(node, "Unresolved constructor invocation."); | |
| 268 } | |
| 269 | |
| 270 @override | |
| 271 ir.Constant visitNullLiteral(NullLiteral node) { | |
| 272 return irBuilder.buildNullConstant(); | |
| 273 } | |
| 274 | |
| 275 @override | |
| 276 ir.Constant visitBooleanLiteral(BooleanLiteral node) { | |
| 277 return irBuilder.buildBooleanConstant(node.value); | |
| 278 } | |
| 279 | |
| 280 @override | |
| 281 ir.Constant visitDoubleLiteral(DoubleLiteral node) { | |
| 282 return irBuilder.buildDoubleConstant(node.value); | |
| 283 } | |
| 284 | |
| 285 @override | |
| 286 ir.Constant visitIntegerLiteral(IntegerLiteral node) { | |
| 287 return irBuilder.buildIntegerConstant(node.value); | |
| 288 } | |
| 289 | |
| 290 @override | |
| 291 visitAdjacentStrings(AdjacentStrings node) { | |
| 292 String value = node.stringValue; | |
| 293 if (value != null) { | |
| 294 return irBuilder.buildStringConstant(value); | |
| 295 } | |
| 296 giveUp(node, "Non constant adjacent strings."); | |
| 297 } | |
| 298 | |
| 299 @override | |
| 300 ir.Constant visitSimpleStringLiteral(SimpleStringLiteral node) { | |
| 301 return irBuilder.buildStringConstant(node.value); | |
| 302 } | |
| 303 | |
| 304 @override | |
| 305 visitStringInterpolation(StringInterpolation node) { | |
| 306 giveUp(node, "String interpolation."); | |
| 307 } | |
| 308 | |
| 309 @override | |
| 310 visitReturnStatement(ReturnStatement node) { | |
| 311 irBuilder.buildReturn(build(node.expression)); | |
| 312 } | |
| 313 | |
| 314 @override | |
| 315 ir.Node visitPropertyAccess(PropertyAccess node) { | |
| 316 // Overridden to avoid eager visits of the receiver. | |
| 317 return handlePropertyAccess(node); | |
| 318 } | |
| 319 | |
| 320 @override | |
| 321 ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { | |
| 322 return handleLocalAccess(node, semantics); | |
| 323 } | |
| 324 | |
| 325 @override | |
| 326 ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { | |
| 327 return handleLocalAccess(node, semantics); | |
| 328 } | |
| 329 | |
| 330 @override | |
| 331 visitVariableDeclaration(VariableDeclaration node) { | |
| 332 // TODO(johnniwinther): Handle constant local variables. | |
| 333 ir.Node initialValue = build(node.initializer); | |
| 334 irBuilder.declareLocalVariable( | |
| 335 converter.convertElement(node.element), | |
| 336 initialValue: initialValue); | |
| 337 } | |
| 338 | |
| 339 dart2js.Element getLocal(AstNode node, AccessSemantics semantics) { | |
| 340 analyzer.Element element = semantics.element; | |
| 341 dart2js.Element target = converter.convertElement(element); | |
| 342 assert(invariant(node, target.isLocal, '$target expected to be local.')); | |
| 343 return target; | |
| 344 } | |
| 345 | |
| 346 ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { | |
| 347 dart2js.Element local = getLocal(node, semantics); | |
| 348 if (semantics.kind == AccessKind.LOCAL_FUNCTION) { | |
| 349 return irBuilder.buildLocalFunctionGet(local); | |
| 350 } else { | |
| 351 return irBuilder.buildLocalVariableGet(local); | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 ir.Primitive handleLocalAssignment(AssignmentExpression node, | |
| 356 AccessSemantics semantics) { | |
| 357 if (node.operator.lexeme != '=') { | |
| 358 return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); | |
| 359 } | |
| 360 return irBuilder.buildLocalVariableSet( | |
| 361 getLocal(node, semantics), | |
| 362 build(node.rightHandSide)); | |
| 363 } | |
| 364 | |
| 365 @override | |
| 366 ir.Node visitAssignmentExpression(AssignmentExpression node) { | |
| 367 // Avoid eager visiting of left and right hand side. | |
| 368 return handleAssignmentExpression(node); | |
| 369 } | |
| 370 | |
| 371 @override | |
| 372 ir.Node visitLocalVariableAssignment(AssignmentExpression node, | |
| 373 AccessSemantics semantics) { | |
| 374 return handleLocalAssignment(node, semantics); | |
| 375 } | |
| 376 | |
| 377 @override | |
| 378 ir.Node visitParameterAssignment(AssignmentExpression node, | |
| 379 AccessSemantics semantics) { | |
| 380 return handleLocalAssignment(node, semantics); | |
| 381 } | |
| 382 | |
| 383 @override | |
| 384 ir.Node visitStaticFieldAssignment(AssignmentExpression node, | |
| 385 AccessSemantics semantics) { | |
| 386 if (node.operator.lexeme != '=') { | |
| 387 return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); | |
| 388 } | |
| 389 analyzer.Element element = semantics.element; | |
| 390 dart2js.Element target = converter.convertElement(element); | |
| 391 // TODO(johnniwinther): Selector information should be computed in the | |
| 392 // [TreeShaker] and shared with the [CpsGeneratingVisitor]. | |
| 393 assert(invariant(node, target.isTopLevel || target.isStatic, | |
| 394 '$target expected to be top-level or static.')); | |
| 395 return irBuilder.buildStaticFieldSet(target, build(node.rightHandSide)); | |
| 396 } | |
| 397 | |
| 398 @override | |
| 399 ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { | |
| 400 // TODO(johnniwinther): Handle implicit `this`. | |
| 401 ir.Primitive receiver = build(semantics.target); | |
| 402 return irBuilder.buildDynamicGet(receiver, | |
| 403 new Selector.getter(semantics.identifier.name, | |
| 404 converter.convertElement(element.library))); | |
| 405 } | |
| 406 | |
| 407 @override | |
| 408 ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { | |
| 409 analyzer.Element element = semantics.element; | |
| 410 dart2js.Element target = converter.convertElement(element); | |
| 411 // TODO(johnniwinther): Selector information should be computed in the | |
| 412 // [TreeShaker] and shared with the [CpsGeneratingVisitor]. | |
| 413 assert(invariant(node, target.isTopLevel || target.isStatic, | |
| 414 '$target expected to be top-level or static.')); | |
| 415 return irBuilder.buildStaticFieldLazyGet(target, null); | |
| 416 } | |
| 417 | |
| 418 ir.Primitive handleBinaryExpression(BinaryExpression node, | |
| 419 String op) { | |
| 420 ir.Primitive left = build(node.leftOperand); | |
| 421 ir.Primitive right = build(node.rightOperand); | |
| 422 Selector selector = new Selector.binaryOperator(op); | |
| 423 return irBuilder.buildDynamicInvocation( | |
| 424 left, selector, <ir.Primitive>[right]); | |
| 425 } | |
| 426 | |
| 427 ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { | |
| 428 return irBuilder.buildLogicalOperator( | |
| 429 build(node.leftOperand), | |
| 430 subbuild(node.rightOperand), | |
| 431 isLazyOr: isLazyOr); | |
| 432 } | |
| 433 | |
| 434 @override | |
| 435 ir.Node visitBinaryExpression(BinaryExpression node) { | |
| 436 // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be | |
| 437 // available through an enum. | |
| 438 String op = node.operator.lexeme; | |
| 439 switch (op) { | |
| 440 case '||': | |
| 441 case '&&': | |
| 442 return handleLazyOperator(node, isLazyOr: op == '||'); | |
| 443 case '!=': | |
| 444 return irBuilder.buildNegation(handleBinaryExpression(node, '==')); | |
| 445 default: | |
| 446 return handleBinaryExpression(node, op); | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 @override | |
| 451 ir.Node visitConditionalExpression(ConditionalExpression node) { | |
| 452 return irBuilder.buildConditional( | |
| 453 build(node.condition), | |
| 454 subbuild(node.thenExpression), | |
| 455 subbuild(node.elseExpression)); | |
| 456 } | |
| 457 | |
| 458 @override | |
| 459 visitIfStatement(IfStatement node) { | |
| 460 irBuilder.buildIf( | |
| 461 build(node.condition), | |
| 462 subbuild(node.thenStatement), | |
| 463 subbuild(node.elseStatement)); | |
| 464 } | |
| 465 | |
| 466 @override | |
| 467 visitBlock(Block node) { | |
| 468 irBuilder.buildBlock(node.statements, build); | |
| 469 } | |
| 470 | |
| 471 @override | |
| 472 ir.Node visitListLiteral(ListLiteral node) { | |
| 473 dart2js.InterfaceType type = converter.convertType(node.staticType); | |
| 474 // TODO(johnniwinther): Use `build` instead of `(e) => build(e)` when issue | |
| 475 // 18630 has been resolved. | |
| 476 Iterable<ir.Primitive> values = node.elements.map((e) => build(e)); | |
| 477 return irBuilder.buildListLiteral(type, values); | |
| 478 } | |
| 479 | |
| 480 @override | |
| 481 ir.Node visitMapLiteral(MapLiteral node) { | |
| 482 dart2js.InterfaceType type = converter.convertType(node.staticType); | |
| 483 return irBuilder.buildMapLiteral( | |
| 484 type, | |
| 485 node.entries.map((e) => e.key), | |
| 486 node.entries.map((e) => e.value), | |
| 487 build); | |
| 488 } | |
| 489 | |
| 490 @override | |
| 491 visitForStatement(ForStatement node) { | |
| 492 // TODO(johnniwinther): Support `for` as a jump target. | |
| 493 List<dart2js.LocalElement> loopVariables = <dart2js.LocalElement>[]; | |
| 494 SubbuildFunction buildInitializer; | |
| 495 if (node.variables != null) { | |
| 496 buildInitializer = subbuild(node.variables); | |
| 497 for (VariableDeclaration variable in node.variables.variables) { | |
| 498 loopVariables.add(converter.convertElement(variable.element)); | |
| 499 } | |
| 500 } else { | |
| 501 buildInitializer = subbuild(node.initialization); | |
| 502 } | |
| 503 irBuilder.buildFor(buildInitializer: buildInitializer, | |
| 504 buildCondition: subbuild(node.condition), | |
| 505 buildBody: subbuild(node.body), | |
| 506 buildUpdate: subbuildSequence(node.updaters), | |
| 507 loopVariables: loopVariables); | |
| 508 } | |
| 509 | |
| 510 @override | |
| 511 visitWhileStatement(WhileStatement node) { | |
| 512 // TODO(johnniwinther): Support `while` as a jump target. | |
| 513 irBuilder.buildWhile(buildCondition: subbuild(node.condition), | |
| 514 buildBody: subbuild(node.body)); | |
| 515 } | |
| 516 | |
| 517 @override | |
| 518 visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 519 giveUp(node, "Unexpected node: DeclaredIdentifier"); | |
| 520 } | |
| 521 | |
| 522 @override | |
| 523 visitForEachStatement(ForEachStatement node) { | |
| 524 SubbuildFunction buildVariableDeclaration; | |
| 525 dart2js.Element variableElement; | |
| 526 Selector variableSelector; | |
| 527 if (node.identifier != null) { | |
| 528 AccessSemantics accessSemantics = | |
| 529 node.identifier.accept(ACCESS_SEMANTICS_VISITOR); | |
| 530 if (accessSemantics.kind == AccessKind.DYNAMIC) { | |
| 531 variableSelector = new Selector.setter( | |
| 532 node.identifier.name, converter.convertElement(currentLibrary)); | |
| 533 } else if (accessSemantics.element != null) { | |
| 534 variableElement = converter.convertElement(accessSemantics.element); | |
| 535 variableSelector = new Selector.setter( | |
| 536 variableElement.name, | |
| 537 converter.convertElement(accessSemantics.element.library)); | |
| 538 } else { | |
| 539 giveUp(node, 'For-in of unresolved variable: $accessSemantics'); | |
| 540 } | |
| 541 } else { | |
| 542 assert(invariant( | |
| 543 node, node.loopVariable != null, "Loop variable expected")); | |
| 544 variableElement = converter.convertElement(node.loopVariable.element); | |
| 545 buildVariableDeclaration = (IrBuilder builder) { | |
| 546 builder.declareLocalVariable(variableElement); | |
| 547 }; | |
| 548 } | |
| 549 // TODO(johnniwinther): Support `for-in` as a jump target. | |
| 550 irBuilder.buildForIn( | |
| 551 buildExpression: subbuild(node.iterable), | |
| 552 buildVariableDeclaration: buildVariableDeclaration, | |
| 553 variableElement: variableElement, | |
| 554 variableSelector: variableSelector, | |
| 555 buildBody: subbuild(node.body)); | |
| 556 } | |
| 557 @override | |
| 558 ir.Primitive visitIsExpression(IsExpression node) { | |
| 559 return irBuilder.buildTypeOperator( | |
| 560 visit(node.expression), | |
| 561 converter.convertType(node.type.type), | |
| 562 isTypeTest: true, | |
| 563 isNotCheck: node.notOperator != null); | |
| 564 } | |
| 565 | |
| 566 @override | |
| 567 ir.Primitive visitAsExpression(AsExpression node) { | |
| 568 return irBuilder.buildTypeOperator( | |
| 569 visit(node.expression), | |
| 570 converter.convertType(node.type.type), | |
| 571 isTypeTest: false); | |
| 572 } | |
| 573 | |
| 574 @override | |
| 575 visitTryStatement(TryStatement node) { | |
| 576 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; | |
| 577 for (CatchClause catchClause in node.catchClauses) { | |
| 578 catchClauseInfos.add(new CatchClauseInfo( | |
| 579 exceptionVariable: converter.convertElement( | |
| 580 catchClause.exceptionParameter.staticElement), | |
| 581 buildCatchBlock: subbuild(catchClause.body))); | |
| 582 | |
| 583 } | |
| 584 irBuilder.buildTry( | |
| 585 tryStatementInfo: new TryStatementInfo(), | |
| 586 buildTryBlock: subbuild(node.body), | |
| 587 catchClauseInfos: catchClauseInfos); | |
| 588 } | |
| 589 } | |
| OLD | NEW |