001 /* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.lang.cfg; 018 019 import com.google.common.collect.ImmutableSet; 020 import com.google.common.collect.Lists; 021 import com.intellij.psi.PsiElement; 022 import com.intellij.psi.tree.IElementType; 023 import com.intellij.psi.util.PsiTreeUtil; 024 import org.jetbrains.annotations.NotNull; 025 import org.jetbrains.annotations.Nullable; 026 import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator; 027 import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; 028 import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; 029 import org.jetbrains.jet.lang.descriptors.*; 030 import org.jetbrains.jet.lang.psi.*; 031 import org.jetbrains.jet.lang.resolve.BindingContext; 032 import org.jetbrains.jet.lang.resolve.BindingContextUtils; 033 import org.jetbrains.jet.lang.resolve.BindingTrace; 034 import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; 035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 036 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; 037 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; 038 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 039 import org.jetbrains.jet.lang.resolve.name.Name; 040 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 041 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 042 import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver; 043 import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; 044 import org.jetbrains.jet.lang.types.JetType; 045 import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 046 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 047 import org.jetbrains.jet.lexer.JetToken; 048 import org.jetbrains.jet.lexer.JetTokens; 049 050 import java.util.Iterator; 051 import java.util.LinkedList; 052 import java.util.List; 053 054 import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*; 055 import static org.jetbrains.jet.lang.cfg.JetControlFlowProcessor.CFPContext.IN_CONDITION; 056 import static org.jetbrains.jet.lang.cfg.JetControlFlowProcessor.CFPContext.NOT_IN_CONDITION; 057 import static org.jetbrains.jet.lang.diagnostics.Errors.*; 058 import static org.jetbrains.jet.lexer.JetTokens.*; 059 060 public class JetControlFlowProcessor { 061 062 private final JetControlFlowBuilder builder; 063 private final BindingTrace trace; 064 065 public JetControlFlowProcessor(BindingTrace trace) { 066 this.builder = new JetControlFlowInstructionsGenerator(); 067 this.trace = trace; 068 } 069 070 @NotNull 071 public Pseudocode generatePseudocode(@NotNull JetElement subroutine) { 072 Pseudocode pseudocode = generate(subroutine); 073 ((PseudocodeImpl) pseudocode).postProcess(); 074 return pseudocode; 075 } 076 077 @NotNull 078 private Pseudocode generate(@NotNull JetElement subroutine) { 079 builder.enterSubroutine(subroutine); 080 CFPVisitor cfpVisitor = new CFPVisitor(builder); 081 if (subroutine instanceof JetDeclarationWithBody) { 082 JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine; 083 List<JetParameter> valueParameters = declarationWithBody.getValueParameters(); 084 for (JetParameter valueParameter : valueParameters) { 085 cfpVisitor.generateInstructions(valueParameter, NOT_IN_CONDITION); 086 } 087 JetExpression bodyExpression = declarationWithBody.getBodyExpression(); 088 if (bodyExpression != null) { 089 cfpVisitor.generateInstructions(bodyExpression, NOT_IN_CONDITION); 090 } 091 } else { 092 cfpVisitor.generateInstructions(subroutine, NOT_IN_CONDITION); 093 } 094 return builder.exitSubroutine(subroutine); 095 } 096 097 private void processLocalDeclaration(@NotNull JetDeclaration subroutine) { 098 JetElement parent = PsiTreeUtil.getParentOfType(subroutine, JetElement.class); 099 assert parent != null; 100 101 Label afterDeclaration = builder.createUnboundLabel(); 102 103 builder.nondeterministicJump(afterDeclaration, parent); 104 generate(subroutine); 105 builder.bindLabel(afterDeclaration); 106 } 107 108 /*package*/ enum CFPContext { 109 IN_CONDITION(true), 110 NOT_IN_CONDITION(false); 111 112 private final boolean inCondition; 113 114 private CFPContext(boolean inCondition) { 115 this.inCondition = inCondition; 116 } 117 118 public boolean inCondition() { 119 return inCondition; 120 } 121 } 122 123 private class CFPVisitor extends JetVisitorVoidWithParameter<CFPContext> { 124 private final JetControlFlowBuilder builder; 125 126 private final JetVisitorVoidWithParameter<CFPContext> conditionVisitor = new JetVisitorVoidWithParameter<CFPContext>() { 127 128 @Override 129 public void visitWhenConditionInRangeVoid(@NotNull JetWhenConditionInRange condition, CFPContext context) { 130 generateInstructions(condition.getRangeExpression(), context); 131 generateInstructions(condition.getOperationReference(), context); 132 // TODO : read the call to contains()... 133 } 134 135 @Override 136 public void visitWhenConditionIsPatternVoid(@NotNull JetWhenConditionIsPattern condition, CFPContext context) { 137 // TODO: types in CF? 138 } 139 140 @Override 141 public void visitWhenConditionWithExpressionVoid(@NotNull JetWhenConditionWithExpression condition, CFPContext context) { 142 generateInstructions(condition.getExpression(), context); 143 } 144 145 @Override 146 public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { 147 throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString()); 148 } 149 }; 150 151 private CFPVisitor(@NotNull JetControlFlowBuilder builder) { 152 this.builder = builder; 153 } 154 155 private void mark(JetElement element) { 156 builder.mark(element); 157 } 158 159 public void generateInstructions(@Nullable JetElement element, CFPContext context) { 160 if (element == null) return; 161 element.accept(this, context); 162 checkNothingType(element); 163 } 164 165 private void checkNothingType(JetElement element) { 166 if (!(element instanceof JetExpression)) return; 167 168 JetExpression expression = JetPsiUtil.deparenthesize((JetExpression) element); 169 if (expression == null) return; 170 171 if (expression instanceof JetStatementExpression || expression instanceof JetTryExpression 172 || expression instanceof JetIfExpression || expression instanceof JetWhenExpression) { 173 return; 174 } 175 176 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); 177 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) { 178 builder.jumpToError(expression); 179 } 180 } 181 182 @Override 183 public void visitParenthesizedExpressionVoid(@NotNull JetParenthesizedExpression expression, CFPContext context) { 184 mark(expression); 185 JetExpression innerExpression = expression.getExpression(); 186 if (innerExpression != null) { 187 generateInstructions(innerExpression, context); 188 } 189 } 190 191 @Override 192 public void visitAnnotatedExpressionVoid(@NotNull JetAnnotatedExpression expression, CFPContext context) { 193 JetExpression baseExpression = expression.getBaseExpression(); 194 if (baseExpression != null) { 195 generateInstructions(baseExpression, context); 196 } 197 } 198 199 @Override 200 public void visitThisExpressionVoid(@NotNull JetThisExpression expression, CFPContext context) { 201 ResolvedCall<?> resolvedCall = getResolvedCall(expression); 202 if (resolvedCall == null) { 203 builder.readThis(expression, null); 204 return; 205 } 206 207 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 208 if (resultingDescriptor instanceof ReceiverParameterDescriptor) { 209 builder.readThis(expression, (ReceiverParameterDescriptor) resultingDescriptor); 210 } 211 } 212 213 @Override 214 public void visitConstantExpressionVoid(@NotNull JetConstantExpression expression, CFPContext context) { 215 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression); 216 builder.loadConstant(expression, constant); 217 } 218 219 @Override 220 public void visitSimpleNameExpressionVoid(@NotNull JetSimpleNameExpression expression, CFPContext context) { 221 ResolvedCall<?> resolvedCall = getResolvedCall(expression); 222 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 223 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 224 generateCall(expression, variableAsFunctionResolvedCall.getVariableCall()); 225 } 226 else { 227 generateCall(expression); 228 } 229 } 230 231 @Override 232 public void visitLabelQualifiedExpressionVoid(@NotNull JetLabelQualifiedExpression expression, CFPContext context) { 233 String labelName = expression.getLabelName(); 234 JetExpression labeledExpression = expression.getLabeledExpression(); 235 if (labelName != null && labeledExpression != null) { 236 visitLabeledExpression(labelName, labeledExpression, context); 237 } 238 } 239 240 private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression, CFPContext context) { 241 JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression); 242 if (deparenthesized != null) { 243 generateInstructions(labeledExpression, context); 244 } 245 } 246 247 @SuppressWarnings("SuspiciousMethodCalls") @Override 248 public void visitBinaryExpressionVoid(@NotNull JetBinaryExpression expression, CFPContext context) { 249 JetSimpleNameExpression operationReference = expression.getOperationReference(); 250 IElementType operationType = operationReference.getReferencedNameElementType(); 251 if (!ImmutableSet.of(ANDAND, OROR, EQ, ELVIS).contains(operationType)) { 252 mark(expression); 253 } 254 JetExpression right = expression.getRight(); 255 if (operationType == ANDAND) { 256 generateInstructions(expression.getLeft(), IN_CONDITION); 257 Label resultLabel = builder.createUnboundLabel(); 258 builder.jumpOnFalse(resultLabel, expression); 259 if (right != null) { 260 generateInstructions(right, IN_CONDITION); 261 } 262 builder.bindLabel(resultLabel); 263 if (!context.inCondition()) { 264 builder.predefinedOperation(expression, AND); 265 } 266 } 267 else if (operationType == OROR) { 268 generateInstructions(expression.getLeft(), IN_CONDITION); 269 Label resultLabel = builder.createUnboundLabel(); 270 builder.jumpOnTrue(resultLabel, expression); 271 if (right != null) { 272 generateInstructions(right, IN_CONDITION); 273 } 274 builder.bindLabel(resultLabel); 275 if (!context.inCondition()) { 276 builder.predefinedOperation(expression, OR); 277 } 278 } 279 else if (operationType == EQ) { 280 visitAssignment(expression.getLeft(), right, expression); 281 } 282 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { 283 if (generateCall(operationReference)) { 284 ResolvedCall<?> resolvedCall = getResolvedCall(operationReference); 285 assert resolvedCall != null : "Generation succeeded, but no call is found: " + expression.getText(); 286 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 287 Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken()); 288 if (!descriptor.getName().equals(assignMethodName)) { 289 // plus() called, assignment needed 290 visitAssignment(expression.getLeft(), null, expression); 291 } 292 } 293 else { 294 generateBothArguments(expression); 295 } 296 } 297 else if (operationType == ELVIS) { 298 generateInstructions(expression.getLeft(), NOT_IN_CONDITION); 299 Label afterElvis = builder.createUnboundLabel(); 300 builder.jumpOnTrue(afterElvis, expression); 301 if (right != null) { 302 generateInstructions(right, NOT_IN_CONDITION); 303 } 304 builder.bindLabel(afterElvis); 305 } 306 else { 307 if (!generateCall(operationReference)) { 308 generateBothArguments(expression); 309 } 310 } 311 } 312 313 private void generateBothArguments(JetBinaryExpression expression) { 314 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); 315 if (left != null) { 316 generateInstructions(left, NOT_IN_CONDITION); 317 } 318 JetExpression right = expression.getRight(); 319 if (right != null) { 320 generateInstructions(right, NOT_IN_CONDITION); 321 } 322 } 323 324 private void visitAssignment(JetExpression lhs, @Nullable JetExpression rhs, JetExpression parentExpression) { 325 JetExpression left = JetPsiUtil.deparenthesize(lhs); 326 if (left == null) { 327 builder.compilationError(lhs, "No lValue in assignment"); 328 return; 329 } 330 331 if (left instanceof JetArrayAccessExpression) { 332 ResolvedCall<FunctionDescriptor> setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, left); 333 generateArrayAccess((JetArrayAccessExpression) left, setResolvedCall); 334 recordWrite(left, parentExpression); 335 return; 336 } 337 338 generateInstructions(rhs, NOT_IN_CONDITION); 339 if (left instanceof JetSimpleNameExpression || left instanceof JetProperty) { 340 // Do nothing, just record write below 341 } 342 else if (left instanceof JetQualifiedExpression) { 343 generateInstructions(((JetQualifiedExpression) left).getReceiverExpression(), NOT_IN_CONDITION); 344 } 345 else { 346 builder.unsupported(parentExpression); // TODO 347 } 348 349 recordWrite(left, parentExpression); 350 } 351 352 private void recordWrite(JetExpression left, JetExpression parentExpression) { 353 VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false); 354 if (descriptor != null) { 355 builder.write(parentExpression, left); 356 } 357 } 358 359 private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall<?> resolvedCall) { 360 mark(arrayAccessExpression); 361 if (!checkAndGenerateCall(arrayAccessExpression, resolvedCall)) { 362 for (JetExpression index : arrayAccessExpression.getIndexExpressions()) { 363 generateInstructions(index, NOT_IN_CONDITION); 364 } 365 366 generateInstructions(arrayAccessExpression.getArrayExpression(), NOT_IN_CONDITION); 367 } 368 } 369 370 @Override 371 public void visitUnaryExpressionVoid(@NotNull JetUnaryExpression expression, CFPContext context) { 372 mark(expression); 373 JetSimpleNameExpression operationSign = expression.getOperationReference(); 374 IElementType operationType = operationSign.getReferencedNameElementType(); 375 JetExpression baseExpression = expression.getBaseExpression(); 376 if (baseExpression == null) return; 377 if (JetTokens.LABELS.contains(operationType)) { 378 String referencedName = operationSign.getReferencedName(); 379 visitLabeledExpression(referencedName.substring(1), baseExpression, context); 380 } 381 else if (JetTokens.EXCLEXCL == operationType) { 382 generateInstructions(baseExpression, NOT_IN_CONDITION); 383 builder.predefinedOperation(expression, NOT_NULL_ASSERTION); 384 } 385 else { 386 if (!generateCall(expression.getOperationReference())) { 387 generateInstructions(baseExpression, NOT_IN_CONDITION); 388 } 389 390 boolean incrementOrDecrement = isIncrementOrDecrement(operationType); 391 if (incrementOrDecrement) { 392 // We skip dup's and other subtleties here 393 visitAssignment(baseExpression, null, expression); 394 } 395 } 396 } 397 398 private boolean isIncrementOrDecrement(IElementType operationType) { 399 return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS; 400 } 401 402 403 @Override 404 public void visitIfExpressionVoid(@NotNull JetIfExpression expression, CFPContext context) { 405 mark(expression); 406 JetExpression condition = expression.getCondition(); 407 if (condition != null) { 408 generateInstructions(condition, IN_CONDITION); 409 } 410 Label elseLabel = builder.createUnboundLabel(); 411 builder.jumpOnFalse(elseLabel, expression); 412 JetExpression thenBranch = expression.getThen(); 413 if (thenBranch != null) { 414 generateInstructions(thenBranch, context); 415 } 416 else { 417 builder.loadUnit(expression); 418 } 419 Label resultLabel = builder.createUnboundLabel(); 420 builder.jump(resultLabel, expression); 421 builder.bindLabel(elseLabel); 422 JetExpression elseBranch = expression.getElse(); 423 if (elseBranch != null) { 424 generateInstructions(elseBranch, context); 425 } 426 else { 427 builder.loadUnit(expression); 428 } 429 builder.bindLabel(resultLabel); 430 } 431 432 private class FinallyBlockGenerator { 433 private final JetFinallySection finallyBlock; 434 private final CFPContext context; 435 private Label startFinally = null; 436 private Label finishFinally = null; 437 438 private FinallyBlockGenerator(JetFinallySection block, CFPContext context) { 439 finallyBlock = block; 440 this.context = context; 441 } 442 443 public void generate() { 444 JetBlockExpression finalExpression = finallyBlock.getFinalExpression(); 445 if (finalExpression == null) return; 446 if (startFinally != null) { 447 assert finishFinally != null; 448 builder.repeatPseudocode(startFinally, finishFinally); 449 return; 450 } 451 startFinally = builder.createUnboundLabel("start finally"); 452 builder.bindLabel(startFinally); 453 generateInstructions(finalExpression, context); 454 finishFinally = builder.createUnboundLabel("finish finally"); 455 builder.bindLabel(finishFinally); 456 } 457 } 458 459 460 @Override 461 public void visitTryExpressionVoid(@NotNull JetTryExpression expression, CFPContext context) { 462 mark(expression); 463 JetFinallySection finallyBlock = expression.getFinallyBlock(); 464 final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock, context); 465 if (finallyBlock != null) { 466 builder.enterTryFinally(new GenerationTrigger() { 467 private boolean working = false; 468 469 @Override 470 public void generate() { 471 // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}' 472 if (working) return; 473 working = true; 474 finallyBlockGenerator.generate(); 475 working = false; 476 } 477 }); 478 } 479 480 List<JetCatchClause> catchClauses = expression.getCatchClauses(); 481 boolean hasCatches = !catchClauses.isEmpty(); 482 Label onException = null; 483 if (hasCatches) { 484 onException = builder.createUnboundLabel("onException"); 485 builder.nondeterministicJump(onException, expression); 486 } 487 Label onExceptionToFinallyBlock = null; 488 if (finallyBlock != null) { 489 onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock"); 490 builder.nondeterministicJump(onExceptionToFinallyBlock, expression); 491 } 492 generateInstructions(expression.getTryBlock(), context); 493 494 if (hasCatches) { 495 Label afterCatches = builder.createUnboundLabel("afterCatches"); 496 builder.jump(afterCatches, expression); 497 498 builder.bindLabel(onException); 499 LinkedList<Label> catchLabels = Lists.newLinkedList(); 500 int catchClausesSize = catchClauses.size(); 501 for (int i = 0; i < catchClausesSize - 1; i++) { 502 catchLabels.add(builder.createUnboundLabel("catch " + i)); 503 } 504 if (!catchLabels.isEmpty()) { 505 builder.nondeterministicJump(catchLabels, expression); 506 } 507 boolean isFirst = true; 508 for (JetCatchClause catchClause : catchClauses) { 509 builder.enterLexicalScope(catchClause); 510 if (!isFirst) { 511 builder.bindLabel(catchLabels.remove()); 512 } 513 else { 514 isFirst = false; 515 } 516 JetParameter catchParameter = catchClause.getCatchParameter(); 517 if (catchParameter != null) { 518 builder.declareParameter(catchParameter); 519 builder.write(catchParameter, catchParameter); 520 } 521 JetExpression catchBody = catchClause.getCatchBody(); 522 if (catchBody != null) { 523 generateInstructions(catchBody, NOT_IN_CONDITION); 524 } 525 builder.jump(afterCatches, expression); 526 builder.exitLexicalScope(catchClause); 527 } 528 529 builder.bindLabel(afterCatches); 530 } 531 532 if (finallyBlock != null) { 533 builder.exitTryFinally(); 534 535 Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock"); 536 builder.jump(skipFinallyToErrorBlock, expression); 537 builder.bindLabel(onExceptionToFinallyBlock); 538 finallyBlockGenerator.generate(); 539 builder.jumpToError(expression); 540 builder.bindLabel(skipFinallyToErrorBlock); 541 542 finallyBlockGenerator.generate(); 543 } 544 } 545 546 @Override 547 public void visitWhileExpressionVoid(@NotNull JetWhileExpression expression, CFPContext context) { 548 mark(expression); 549 LoopInfo loopInfo = builder.enterLoop(expression, null, null); 550 551 builder.bindLabel(loopInfo.getConditionEntryPoint()); 552 JetExpression condition = expression.getCondition(); 553 if (condition != null) { 554 generateInstructions(condition, IN_CONDITION); 555 } 556 boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true); 557 if (!conditionIsTrueConstant) { 558 builder.jumpOnFalse(loopInfo.getExitPoint(), expression); 559 } 560 561 builder.bindLabel(loopInfo.getBodyEntryPoint()); 562 JetExpression body = expression.getBody(); 563 if (body != null) { 564 generateInstructions(body, NOT_IN_CONDITION); 565 } 566 builder.jump(loopInfo.getEntryPoint(), expression); 567 builder.exitLoop(expression); 568 builder.loadUnit(expression); 569 } 570 571 @Override 572 public void visitDoWhileExpressionVoid(@NotNull JetDoWhileExpression expression, CFPContext context) { 573 builder.enterLexicalScope(expression); 574 mark(expression); 575 LoopInfo loopInfo = builder.enterLoop(expression, null, null); 576 577 builder.bindLabel(loopInfo.getBodyEntryPoint()); 578 JetExpression body = expression.getBody(); 579 if (body != null) { 580 generateInstructions(body, NOT_IN_CONDITION); 581 } 582 builder.bindLabel(loopInfo.getConditionEntryPoint()); 583 JetExpression condition = expression.getCondition(); 584 if (condition != null) { 585 generateInstructions(condition, IN_CONDITION); 586 } 587 builder.jumpOnTrue(loopInfo.getEntryPoint(), expression); 588 builder.exitLoop(expression); 589 builder.loadUnit(expression); 590 builder.exitLexicalScope(expression); 591 } 592 593 @Override 594 public void visitForExpressionVoid(@NotNull JetForExpression expression, CFPContext context) { 595 builder.enterLexicalScope(expression); 596 mark(expression); 597 JetExpression loopRange = expression.getLoopRange(); 598 if (loopRange != null) { 599 generateInstructions(loopRange, NOT_IN_CONDITION); 600 } 601 declareLoopParameter(expression); 602 603 // TODO : primitive cases 604 Label loopExitPoint = builder.createUnboundLabel(); 605 Label conditionEntryPoint = builder.createUnboundLabel(); 606 607 builder.bindLabel(conditionEntryPoint); 608 builder.nondeterministicJump(loopExitPoint, expression); 609 610 LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint); 611 612 builder.bindLabel(loopInfo.getBodyEntryPoint()); 613 writeLoopParameterAssignment(expression); 614 615 JetExpression body = expression.getBody(); 616 if (body != null) { 617 generateInstructions(body, NOT_IN_CONDITION); 618 } 619 620 builder.nondeterministicJump(loopInfo.getEntryPoint(), expression); 621 builder.exitLoop(expression); 622 builder.loadUnit(expression); 623 builder.exitLexicalScope(expression); 624 } 625 626 private void declareLoopParameter(JetForExpression expression) { 627 JetParameter loopParameter = expression.getLoopParameter(); 628 JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); 629 if (loopParameter != null) { 630 builder.declareParameter(loopParameter); 631 } 632 else if (multiDeclaration != null) { 633 visitMultiDeclaration(multiDeclaration, false); 634 } 635 } 636 637 private void writeLoopParameterAssignment(JetForExpression expression) { 638 JetParameter loopParameter = expression.getLoopParameter(); 639 JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); 640 if (loopParameter != null) { 641 builder.write(loopParameter, loopParameter); 642 } 643 else if (multiDeclaration != null) { 644 for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) { 645 builder.write(entry, entry); 646 } 647 } 648 } 649 650 @Override 651 public void visitBreakExpressionVoid(@NotNull JetBreakExpression expression, CFPContext context) { 652 JetElement loop = getCorrespondingLoop(expression); 653 if (loop != null) { 654 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 655 builder.jump(builder.getExitPoint(loop), expression); 656 } 657 } 658 659 @Override 660 public void visitContinueExpressionVoid(@NotNull JetContinueExpression expression, CFPContext context) { 661 JetElement loop = getCorrespondingLoop(expression); 662 if (loop != null) { 663 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 664 builder.jump(builder.getEntryPoint(loop), expression); 665 } 666 } 667 668 private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) { 669 String labelName = expression.getLabelName(); 670 JetElement loop; 671 if (labelName != null) { 672 JetSimpleNameExpression targetLabel = expression.getTargetLabel(); 673 assert targetLabel != null; 674 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel); 675 if (labeledElement instanceof JetLoopExpression) { 676 loop = (JetLoopExpression) labeledElement; 677 } 678 else { 679 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); 680 loop = null; 681 } 682 } 683 else { 684 loop = builder.getCurrentLoop(); 685 if (loop == null) { 686 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)); 687 } 688 } 689 return loop; 690 } 691 692 private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetLabelQualifiedExpression jumpExpression, @NotNull JetElement jumpTarget) { 693 BindingContext bindingContext = trace.getBindingContext(); 694 695 FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression); 696 FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget); 697 if (labelExprEnclosingFunc != labelTargetEnclosingFunc) { 698 trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression)); 699 } 700 } 701 702 @Override 703 public void visitReturnExpressionVoid(@NotNull JetReturnExpression expression, CFPContext context) { 704 JetExpression returnedExpression = expression.getReturnedExpression(); 705 if (returnedExpression != null) { 706 generateInstructions(returnedExpression, NOT_IN_CONDITION); 707 } 708 JetSimpleNameExpression labelElement = expression.getTargetLabel(); 709 JetElement subroutine; 710 String labelName = expression.getLabelName(); 711 if (labelElement != null) { 712 assert labelName != null; 713 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement); 714 if (labeledElement != null) { 715 assert labeledElement instanceof JetElement; 716 subroutine = (JetElement) labeledElement; 717 } 718 else { 719 subroutine = null; 720 } 721 } 722 else { 723 subroutine = builder.getReturnSubroutine(); 724 // TODO : a context check 725 } 726 727 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) { 728 if (returnedExpression == null) { 729 builder.returnNoValue(expression, subroutine); 730 } 731 else { 732 builder.returnValue(expression, subroutine); 733 } 734 } 735 } 736 737 @Override 738 public void visitParameterVoid(@NotNull JetParameter parameter, CFPContext context) { 739 builder.declareParameter(parameter); 740 JetExpression defaultValue = parameter.getDefaultValue(); 741 if (defaultValue != null) { 742 generateInstructions(defaultValue, context); 743 } 744 builder.write(parameter, parameter); 745 } 746 747 @Override 748 public void visitBlockExpressionVoid(@NotNull JetBlockExpression expression, CFPContext context) { 749 boolean declareLexicalScope = !isBlockInDoWhile(expression); 750 if (declareLexicalScope) { 751 builder.enterLexicalScope(expression); 752 } 753 mark(expression); 754 List<JetElement> statements = expression.getStatements(); 755 for (JetElement statement : statements) { 756 generateInstructions(statement, NOT_IN_CONDITION); 757 } 758 if (statements.isEmpty()) { 759 builder.loadUnit(expression); 760 } 761 if (declareLexicalScope) { 762 builder.exitLexicalScope(expression); 763 } 764 } 765 766 private boolean isBlockInDoWhile(@NotNull JetBlockExpression expression) { 767 PsiElement parent = expression.getParent(); 768 if (parent == null) return false; 769 return parent.getParent() instanceof JetDoWhileExpression; 770 } 771 772 @Override 773 public void visitNamedFunctionVoid(@NotNull JetNamedFunction function, CFPContext context) { 774 processLocalDeclaration(function); 775 } 776 777 @Override 778 public void visitFunctionLiteralExpressionVoid(@NotNull JetFunctionLiteralExpression expression, CFPContext context) { 779 mark(expression); 780 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); 781 processLocalDeclaration(functionLiteral); 782 builder.createFunctionLiteral(expression); 783 } 784 785 @Override 786 public void visitQualifiedExpressionVoid(@NotNull JetQualifiedExpression expression, CFPContext context) { 787 mark(expression); 788 JetExpression selectorExpression = expression.getSelectorExpression(); 789 790 if (selectorExpression == null) { 791 generateInstructions(expression.getReceiverExpression(), NOT_IN_CONDITION); 792 return; 793 } 794 795 generateInstructions(selectorExpression, NOT_IN_CONDITION); 796 797 // receiver was generated for resolvedCall 798 JetExpression calleeExpression = JetPsiUtil.getCalleeExpressionIfAny(selectorExpression); 799 if (calleeExpression == null || getResolvedCall(calleeExpression) == null) { 800 generateInstructions(expression.getReceiverExpression(), NOT_IN_CONDITION); 801 } 802 } 803 804 @Override 805 public void visitCallExpressionVoid(@NotNull JetCallExpression expression, CFPContext context) { 806 mark(expression); 807 if (!generateCall(expression.getCalleeExpression())) { 808 for (ValueArgument argument : expression.getValueArguments()) { 809 JetExpression argumentExpression = argument.getArgumentExpression(); 810 if (argumentExpression != null) { 811 generateInstructions(argumentExpression, NOT_IN_CONDITION); 812 } 813 } 814 815 for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) { 816 generateInstructions(functionLiteral, NOT_IN_CONDITION); 817 } 818 819 generateInstructions(expression.getCalleeExpression(), NOT_IN_CONDITION); 820 } 821 } 822 823 @Override 824 public void visitPropertyVoid(@NotNull JetProperty property, CFPContext context) { 825 builder.declareVariable(property); 826 JetExpression initializer = property.getInitializer(); 827 if (initializer != null) { 828 generateInstructions(initializer, NOT_IN_CONDITION); 829 visitAssignment(property, null, property); 830 } 831 JetExpression delegate = property.getDelegateExpression(); 832 if (delegate != null) { 833 generateInstructions(delegate, NOT_IN_CONDITION); 834 } 835 if (JetPsiUtil.isLocal(property)) { 836 for (JetPropertyAccessor accessor : property.getAccessors()) { 837 generateInstructions(accessor, NOT_IN_CONDITION); 838 } 839 } 840 } 841 842 @Override 843 public void visitMultiDeclarationVoid(@NotNull JetMultiDeclaration declaration, CFPContext context) { 844 visitMultiDeclaration(declaration, true); 845 } 846 847 private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) { 848 generateInstructions(declaration.getInitializer(), NOT_IN_CONDITION); 849 850 for (JetMultiDeclarationEntry entry : declaration.getEntries()) { 851 builder.declareVariable(entry); 852 ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); 853 if (resolvedCall != null) { 854 builder.call(entry, resolvedCall); 855 } 856 if (generateWriteForEntries) { 857 builder.write(entry, entry); 858 } 859 } 860 } 861 862 @Override 863 public void visitPropertyAccessorVoid(@NotNull JetPropertyAccessor accessor, CFPContext context) { 864 processLocalDeclaration(accessor); 865 } 866 867 @Override 868 public void visitBinaryWithTypeRHSExpressionVoid(@NotNull JetBinaryExpressionWithTypeRHS expression, CFPContext context) { 869 mark(expression); 870 IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); 871 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { 872 generateInstructions(expression.getLeft(), NOT_IN_CONDITION); 873 } 874 else { 875 visitJetElementVoid(expression, context); 876 } 877 } 878 879 @Override 880 public void visitThrowExpressionVoid(@NotNull JetThrowExpression expression, CFPContext context) { 881 mark(expression); 882 JetExpression thrownExpression = expression.getThrownExpression(); 883 if (thrownExpression != null) { 884 generateInstructions(thrownExpression, NOT_IN_CONDITION); 885 } 886 builder.throwException(expression); 887 } 888 889 @Override 890 public void visitArrayAccessExpressionVoid(@NotNull JetArrayAccessExpression expression, CFPContext context) { 891 mark(expression); 892 ResolvedCall<FunctionDescriptor> getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression); 893 if (!checkAndGenerateCall(expression, getMethodResolvedCall)) { 894 generateArrayAccess(expression, getMethodResolvedCall); 895 } 896 } 897 898 @Override 899 public void visitIsExpressionVoid(@NotNull JetIsExpression expression, CFPContext context) { 900 mark(expression); 901 generateInstructions(expression.getLeftHandSide(), context); 902 } 903 904 @Override 905 public void visitWhenExpressionVoid(@NotNull JetWhenExpression expression, CFPContext context) { 906 mark(expression); 907 JetExpression subjectExpression = expression.getSubjectExpression(); 908 if (subjectExpression != null) { 909 generateInstructions(subjectExpression, context); 910 } 911 boolean hasElse = false; 912 913 Label doneLabel = builder.createUnboundLabel(); 914 915 Label nextLabel = null; 916 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) { 917 JetWhenEntry whenEntry = iterator.next(); 918 mark(whenEntry); 919 920 boolean isElse = whenEntry.isElse(); 921 if (isElse) { 922 hasElse = true; 923 if (iterator.hasNext()) { 924 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry)); 925 } 926 } 927 Label bodyLabel = builder.createUnboundLabel(); 928 929 JetWhenCondition[] conditions = whenEntry.getConditions(); 930 for (int i = 0; i < conditions.length; i++) { 931 JetWhenCondition condition = conditions[i]; 932 condition.accept(conditionVisitor, context); 933 if (i + 1 < conditions.length) { 934 builder.nondeterministicJump(bodyLabel, expression); 935 } 936 } 937 938 if (!isElse) { 939 nextLabel = builder.createUnboundLabel(); 940 builder.nondeterministicJump(nextLabel, expression); 941 } 942 943 builder.bindLabel(bodyLabel); 944 generateInstructions(whenEntry.getExpression(), context); 945 builder.jump(doneLabel, expression); 946 947 if (!isElse) { 948 builder.bindLabel(nextLabel); 949 } 950 } 951 builder.bindLabel(doneLabel); 952 if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) { 953 trace.report(NO_ELSE_IN_WHEN.on(expression)); 954 } 955 } 956 957 @Override 958 public void visitObjectLiteralExpressionVoid(@NotNull JetObjectLiteralExpression expression, CFPContext context) { 959 mark(expression); 960 JetObjectDeclaration declaration = expression.getObjectDeclaration(); 961 generateInstructions(declaration, context); 962 963 builder.createAnonymousObject(expression); 964 } 965 966 @Override 967 public void visitObjectDeclarationVoid(@NotNull JetObjectDeclaration objectDeclaration, CFPContext context) { 968 visitClassOrObject(objectDeclaration, context); 969 } 970 971 @Override 972 public void visitStringTemplateExpressionVoid(@NotNull JetStringTemplateExpression expression, CFPContext context) { 973 mark(expression); 974 for (JetStringTemplateEntry entry : expression.getEntries()) { 975 if (entry instanceof JetStringTemplateEntryWithExpression) { 976 JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry; 977 generateInstructions(entryWithExpression.getExpression(), NOT_IN_CONDITION); 978 } 979 } 980 builder.loadStringTemplate(expression); 981 } 982 983 @Override 984 public void visitTypeProjectionVoid(@NotNull JetTypeProjection typeProjection, CFPContext context) { 985 // TODO : Support Type Arguments. Class object may be initialized at this point"); 986 } 987 988 @Override 989 public void visitAnonymousInitializerVoid(@NotNull JetClassInitializer classInitializer, CFPContext context) { 990 generateInstructions(classInitializer.getBody(), context); 991 } 992 993 private void visitClassOrObject(JetClassOrObject classOrObject, CFPContext context) { 994 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { 995 generateInstructions(specifier, context); 996 } 997 List<JetDeclaration> declarations = classOrObject.getDeclarations(); 998 if (JetPsiUtil.isLocal(classOrObject)) { 999 for (JetDeclaration declaration : declarations) { 1000 generateInstructions(declaration, context); 1001 } 1002 return; 1003 } 1004 //For top-level and inner classes and objects functions are collected and checked separately. 1005 for (JetDeclaration declaration : declarations) { 1006 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { 1007 generateInstructions(declaration, context); 1008 } 1009 } 1010 } 1011 1012 @Override 1013 public void visitClassVoid(@NotNull JetClass klass, CFPContext context) { 1014 List<JetParameter> parameters = klass.getPrimaryConstructorParameters(); 1015 for (JetParameter parameter : parameters) { 1016 generateInstructions(parameter, context); 1017 } 1018 visitClassOrObject(klass, context); 1019 } 1020 1021 @Override 1022 public void visitDelegationToSuperCallSpecifierVoid(@NotNull JetDelegatorToSuperCall call, CFPContext context) { 1023 List<? extends ValueArgument> valueArguments = call.getValueArguments(); 1024 for (ValueArgument valueArgument : valueArguments) { 1025 generateInstructions(valueArgument.getArgumentExpression(), context); 1026 } 1027 } 1028 1029 @Override 1030 public void visitDelegationByExpressionSpecifierVoid(@NotNull JetDelegatorByExpressionSpecifier specifier, CFPContext context) { 1031 generateInstructions(specifier.getDelegateExpression(), context); 1032 } 1033 1034 @Override 1035 public void visitJetFileVoid(@NotNull JetFile file, CFPContext context) { 1036 for (JetDeclaration declaration : file.getDeclarations()) { 1037 if (declaration instanceof JetProperty) { 1038 generateInstructions(declaration, context); 1039 } 1040 } 1041 } 1042 1043 @Override 1044 public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { 1045 builder.unsupported(element); 1046 } 1047 1048 @Nullable 1049 private ResolvedCall<?> getResolvedCall(@NotNull JetElement expression) { 1050 return trace.get(BindingContext.RESOLVED_CALL, expression); 1051 } 1052 1053 private boolean generateCall(@Nullable JetExpression calleeExpression) { 1054 if (calleeExpression == null) return false; 1055 return checkAndGenerateCall(calleeExpression, getResolvedCall(calleeExpression)); 1056 } 1057 1058 private boolean checkAndGenerateCall(JetExpression calleeExpression, @Nullable ResolvedCall<?> resolvedCall) { 1059 if (resolvedCall == null) { 1060 builder.compilationError(calleeExpression, "No resolved call"); 1061 return false; 1062 } 1063 generateCall(calleeExpression, resolvedCall); 1064 return true; 1065 } 1066 1067 private void generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) { 1068 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 1069 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 1070 generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall()); 1071 return; 1072 } 1073 1074 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 1075 1076 generateReceiver(resolvedCall.getThisObject()); 1077 generateReceiver(resolvedCall.getReceiverArgument()); 1078 1079 for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) { 1080 ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor); 1081 if (argument == null) continue; 1082 1083 generateValueArgument(argument); 1084 } 1085 1086 if (resultingDescriptor instanceof VariableDescriptor) { 1087 builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor); 1088 } 1089 else { 1090 builder.call(calleeExpression, resolvedCall); 1091 } 1092 } 1093 1094 private void generateReceiver(ReceiverValue receiver) { 1095 if (!receiver.exists()) return; 1096 if (receiver instanceof ThisReceiver) { 1097 // TODO: Receiver is passed implicitly: no expression to tie the read to 1098 } 1099 else if (receiver instanceof ExpressionReceiver) { 1100 generateInstructions(((ExpressionReceiver) receiver).getExpression(), NOT_IN_CONDITION); 1101 } 1102 else if (receiver instanceof TransientReceiver) { 1103 // Do nothing 1104 } 1105 else { 1106 throw new IllegalArgumentException("Unknown receiver kind: " + receiver); 1107 } 1108 } 1109 1110 private void generateValueArgument(ResolvedValueArgument argument) { 1111 for (ValueArgument valueArgument : argument.getArguments()) { 1112 JetExpression expression = valueArgument.getArgumentExpression(); 1113 if (expression != null) { 1114 generateInstructions(expression, NOT_IN_CONDITION); 1115 } 1116 } 1117 } 1118 } 1119 }