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.Lists;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.tree.IElementType;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.JetNodeTypes;
025 import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
026 import org.jetbrains.jet.lang.cfg.pseudocode.LocalDeclarationInstruction;
027 import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
028 import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
029 import org.jetbrains.jet.lang.psi.*;
030 import org.jetbrains.jet.lang.resolve.BindingContext;
031 import org.jetbrains.jet.lang.resolve.BindingContextUtils;
032 import org.jetbrains.jet.lang.resolve.BindingTrace;
033 import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
034 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
035 import org.jetbrains.jet.lang.types.JetType;
036 import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
037 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
038 import org.jetbrains.jet.lexer.JetTokens;
039
040 import java.util.Collection;
041 import java.util.Iterator;
042 import java.util.LinkedList;
043 import java.util.List;
044
045 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
046
047 public class JetControlFlowProcessor {
048
049 private final JetControlFlowBuilder builder;
050 private final BindingTrace trace;
051
052 public JetControlFlowProcessor(BindingTrace trace) {
053 this.builder = new JetControlFlowInstructionsGenerator();
054 this.trace = trace;
055 }
056
057 public Pseudocode generatePseudocode(@NotNull JetElement subroutine) {
058 Pseudocode pseudocode = generate(subroutine);
059 ((PseudocodeImpl) pseudocode).postProcess();
060 for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
061 ((PseudocodeImpl)localDeclarationInstruction.getBody()).postProcess();
062 }
063 return pseudocode;
064 }
065
066 private Pseudocode generate(@NotNull JetElement subroutine) {
067 builder.enterSubroutine(subroutine);
068 CFPVisitor cfpVisitor = new CFPVisitor(false);
069 if (subroutine instanceof JetDeclarationWithBody) {
070 JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine;
071 List<JetParameter> valueParameters = declarationWithBody.getValueParameters();
072 for (JetParameter valueParameter : valueParameters) {
073 valueParameter.accept(cfpVisitor);
074 }
075 JetExpression bodyExpression = declarationWithBody.getBodyExpression();
076 if (bodyExpression != null) {
077 bodyExpression.accept(cfpVisitor);
078 }
079 } else {
080 subroutine.accept(cfpVisitor);
081 }
082 return builder.exitSubroutine(subroutine);
083 }
084
085 private void processLocalDeclaration(@NotNull JetDeclaration subroutine) {
086 Label afterDeclaration = builder.createUnboundLabel();
087 builder.nondeterministicJump(afterDeclaration);
088 generate(subroutine);
089 builder.bindLabel(afterDeclaration);
090 }
091
092
093 private class CFPVisitor extends JetVisitorVoid {
094 private final boolean inCondition;
095 private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() {
096
097 @Override
098 public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
099 generateInstructions(condition.getRangeExpression(), CFPVisitor.this.inCondition); // TODO : inCondition?
100 generateInstructions(condition.getOperationReference(), CFPVisitor.this.inCondition); // TODO : inCondition?
101 // TODO : read the call to contains()...
102 }
103
104 @Override
105 public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
106 // TODO: types in CF?
107 }
108
109 @Override
110 public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
111 generateInstructions(condition.getExpression(), inCondition);
112 }
113
114 @Override
115 public void visitJetElement(JetElement element) {
116 throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
117 }
118 };
119 private final JetVisitorVoid patternVisitor = new JetVisitorVoid() {
120
121 @Override
122 public void visitJetElement(JetElement element) {
123 throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
124 }
125 };
126
127 private CFPVisitor(boolean inCondition) {
128 this.inCondition = inCondition;
129 }
130
131 private void generateInstructions(@Nullable JetElement element, boolean inCondition) {
132 if (element == null) return;
133 CFPVisitor visitor;
134 if (this.inCondition == inCondition) {
135 visitor = this;
136 }
137 else {
138 visitor = new CFPVisitor(inCondition);
139 }
140 element.accept(visitor);
141 }
142
143 @Override
144 public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
145 builder.read(expression);
146
147 JetExpression innerExpression = expression.getExpression();
148 if (innerExpression != null) {
149 generateInstructions(innerExpression, inCondition);
150 }
151 }
152
153 @Override
154 public void visitAnnotatedExpression(JetAnnotatedExpression expression) {
155 builder.read(expression);
156
157 JetExpression baseExpression = expression.getBaseExpression();
158 if (baseExpression != null) {
159 generateInstructions(baseExpression, inCondition);
160 }
161 }
162
163 @Override
164 public void visitThisExpression(JetThisExpression expression) {
165 builder.read(expression);
166 }
167
168 @Override
169 public void visitConstantExpression(JetConstantExpression expression) {
170 builder.read(expression);
171 }
172
173 @Override
174 public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
175 builder.read(expression);
176 if (trace.get(BindingContext.PROCESSED, expression)) {
177 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
178 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
179 builder.jumpToError();
180 }
181 }
182 }
183
184 @Override
185 public void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression) {
186 String labelName = expression.getLabelName();
187 JetExpression labeledExpression = expression.getLabeledExpression();
188 if (labelName != null && labeledExpression != null) {
189 visitLabeledExpression(labelName, labeledExpression);
190 }
191 }
192
193 private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
194 JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
195 if (deparenthesized != null) {
196 generateInstructions(labeledExpression, inCondition);
197 }
198 }
199
200 @SuppressWarnings("SuspiciousMethodCalls") @Override
201 public void visitBinaryExpression(JetBinaryExpression expression) {
202 IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
203 JetExpression right = expression.getRight();
204 if (operationType == JetTokens.ANDAND) {
205 generateInstructions(expression.getLeft(), true);
206 Label resultLabel = builder.createUnboundLabel();
207 builder.jumpOnFalse(resultLabel);
208 if (right != null) {
209 generateInstructions(right, true);
210 }
211 builder.bindLabel(resultLabel);
212 if (!inCondition) {
213 builder.read(expression);
214 }
215 }
216 else if (operationType == JetTokens.OROR) {
217 generateInstructions(expression.getLeft(), true);
218 Label resultLabel = builder.createUnboundLabel();
219 builder.jumpOnTrue(resultLabel);
220 if (right != null) {
221 generateInstructions(right, true);
222 }
223 builder.bindLabel(resultLabel);
224 if (!inCondition) {
225 builder.read(expression);
226 }
227 }
228 else if (operationType == JetTokens.EQ) {
229 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
230 if (right != null) {
231 generateInstructions(right, false);
232 }
233 if (left instanceof JetSimpleNameExpression) {
234 builder.write(expression, left);
235 }
236 else if (left instanceof JetArrayAccessExpression) {
237 JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
238 visitAssignToArrayAccess(expression, arrayAccessExpression);
239 }
240 else if (left instanceof JetQualifiedExpression) {
241 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left;
242 generateInstructions(qualifiedExpression.getReceiverExpression(), false);
243 generateInstructions(expression.getOperationReference(), false);
244 builder.write(expression, left);
245 }
246 else {
247 builder.unsupported(expression); // TODO
248 }
249 }
250 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
251 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
252 if (left != null) {
253 generateInstructions(left, false);
254 }
255 if (right != null) {
256 generateInstructions(right, false);
257 }
258 if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
259 generateInstructions(expression.getOperationReference(), false);
260 builder.write(expression, left);
261 }
262 else if (left != null) {
263 builder.unsupported(expression); // TODO
264 }
265 }
266 else if (operationType == JetTokens.ELVIS) {
267 builder.read(expression);
268 generateInstructions(expression.getLeft(), false);
269 generateInstructions(expression.getOperationReference(), false);
270 Label afterElvis = builder.createUnboundLabel();
271 builder.jumpOnTrue(afterElvis);
272 if (right != null) {
273 generateInstructions(right, false);
274 }
275 builder.bindLabel(afterElvis);
276 }
277 else {
278 generateInstructions(expression.getLeft(), false);
279 if (right != null) {
280 generateInstructions(right, false);
281 }
282 generateInstructions(expression.getOperationReference(), false);
283 builder.read(expression);
284 }
285 }
286
287 private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
288 for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
289 generateInstructions(index, false);
290 }
291 generateInstructions(arrayAccessExpression.getArrayExpression(), false);
292 generateInstructions(expression.getOperationReference(), false);
293 builder.write(expression, arrayAccessExpression); // TODO : ???
294 }
295
296 @Override
297 public void visitUnaryExpression(JetUnaryExpression expression) {
298 JetSimpleNameExpression operationSign = expression.getOperationReference();
299 IElementType operationType = operationSign.getReferencedNameElementType();
300 JetExpression baseExpression = expression.getBaseExpression();
301 if (baseExpression == null) return;
302 if (JetTokens.LABELS.contains(operationType)) {
303 String referencedName = operationSign.getReferencedName();
304 visitLabeledExpression(referencedName.substring(1), baseExpression);
305 }
306 else {
307 generateInstructions(baseExpression, false);
308 generateInstructions(operationSign, false);
309
310 boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
311 if (incrementOrDecrement) {
312 builder.write(expression, baseExpression);
313 }
314
315 builder.read(expression);
316 }
317 }
318
319 private boolean isIncrementOrDecrement(IElementType operationType) {
320 return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS;
321 }
322
323
324 @Override
325 public void visitIfExpression(JetIfExpression expression) {
326 JetExpression condition = expression.getCondition();
327 if (condition != null) {
328 generateInstructions(condition, true);
329 }
330 Label elseLabel = builder.createUnboundLabel();
331 builder.jumpOnFalse(elseLabel);
332 JetExpression thenBranch = expression.getThen();
333 if (thenBranch != null) {
334 generateInstructions(thenBranch, inCondition);
335 }
336 else {
337 builder.readUnit(expression);
338 }
339 Label resultLabel = builder.createUnboundLabel();
340 builder.jump(resultLabel);
341 builder.bindLabel(elseLabel);
342 JetExpression elseBranch = expression.getElse();
343 if (elseBranch != null) {
344 generateInstructions(elseBranch, inCondition);
345 }
346 else {
347 builder.readUnit(expression);
348 }
349 builder.bindLabel(resultLabel);
350 }
351
352 private class FinallyBlockGenerator {
353 private final JetFinallySection finallyBlock;
354 private Label startFinally = null;
355 private Label finishFinally = null;
356
357 private FinallyBlockGenerator(JetFinallySection block) {
358 finallyBlock = block;
359 }
360
361 public void generate() {
362 JetBlockExpression finalExpression = finallyBlock.getFinalExpression();
363 if (finalExpression == null) return;
364 if (startFinally != null) {
365 assert finishFinally != null;
366 builder.repeatPseudocode(startFinally, finishFinally);
367 return;
368 }
369 startFinally = builder.createUnboundLabel("start finally");
370 builder.bindLabel(startFinally);
371 generateInstructions(finalExpression, inCondition);
372 finishFinally = builder.createUnboundLabel("finish finally");
373 builder.bindLabel(finishFinally);
374 }
375 }
376
377
378 @Override
379 public void visitTryExpression(JetTryExpression expression) {
380 builder.read(expression);
381 JetFinallySection finallyBlock = expression.getFinallyBlock();
382 final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
383 if (finallyBlock != null) {
384 builder.enterTryFinally(new GenerationTrigger() {
385 private boolean working = false;
386
387 @Override
388 public void generate() {
389 // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
390 if (working) return;
391 working = true;
392 finallyBlockGenerator.generate();
393 working = false;
394 }
395 });
396 }
397
398 List<JetCatchClause> catchClauses = expression.getCatchClauses();
399 boolean hasCatches = !catchClauses.isEmpty();
400 Label onException = null;
401 if (hasCatches) {
402 onException = builder.createUnboundLabel("onException");
403 builder.nondeterministicJump(onException);
404 }
405 Label onExceptionToFinallyBlock = null;
406 if (finallyBlock != null) {
407 onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock");
408 builder.nondeterministicJump(onExceptionToFinallyBlock);
409 }
410 generateInstructions(expression.getTryBlock(), inCondition);
411
412 Collection<Label> allowDeadLabels = Lists.newArrayList();
413 if (hasCatches) {
414 Label afterCatches = builder.createUnboundLabel("afterCatches");
415 builder.jump(afterCatches);
416
417 builder.bindLabel(onException);
418 LinkedList<Label> catchLabels = Lists.newLinkedList();
419 int catchClausesSize = catchClauses.size();
420 for (int i = 0; i < catchClausesSize - 1; i++) {
421 catchLabels.add(builder.createUnboundLabel("catch " + i));
422 }
423 if (!catchLabels.isEmpty()) {
424 builder.nondeterministicJump(catchLabels);
425 }
426 boolean isFirst = true;
427 for (JetCatchClause catchClause : catchClauses) {
428 if (!isFirst) {
429 builder.bindLabel(catchLabels.remove());
430 }
431 else {
432 isFirst = false;
433 }
434 JetParameter catchParameter = catchClause.getCatchParameter();
435 if (catchParameter != null) {
436 builder.declare(catchParameter);
437 builder.write(catchParameter, catchParameter);
438 }
439 JetExpression catchBody = catchClause.getCatchBody();
440 if (catchBody != null) {
441 generateInstructions(catchBody, false);
442 }
443 builder.jump(afterCatches);
444 }
445
446 builder.bindLabel(afterCatches);
447 }
448
449 if (finallyBlock != null) {
450 builder.exitTryFinally();
451
452 Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
453 builder.jump(skipFinallyToErrorBlock);
454 builder.bindLabel(onExceptionToFinallyBlock);
455 finallyBlockGenerator.generate();
456 builder.jumpToError();
457 builder.bindLabel(skipFinallyToErrorBlock);
458
459 finallyBlockGenerator.generate();
460 }
461 }
462
463 @Override
464 public void visitWhileExpression(JetWhileExpression expression) {
465 builder.read(expression);
466 LoopInfo loopInfo = builder.enterLoop(expression, null, null);
467
468 builder.bindLabel(loopInfo.getConditionEntryPoint());
469 JetExpression condition = expression.getCondition();
470 if (condition != null) {
471 generateInstructions(condition, true);
472 }
473 boolean conditionIsTrueConstant = false;
474 if (condition instanceof JetConstantExpression && condition.getNode().getElementType() == JetNodeTypes.BOOLEAN_CONSTANT) {
475 if (BooleanValue.TRUE == new CompileTimeConstantResolver().getBooleanValue(
476 (JetConstantExpression) condition, KotlinBuiltIns.getInstance().getBooleanType())) {
477 conditionIsTrueConstant = true;
478 }
479 }
480 if (!conditionIsTrueConstant) {
481 builder.jumpOnFalse(loopInfo.getExitPoint());
482 }
483
484 builder.bindLabel(loopInfo.getBodyEntryPoint());
485 JetExpression body = expression.getBody();
486 if (body != null) {
487 generateInstructions(body, false);
488 }
489 builder.jump(loopInfo.getEntryPoint());
490 builder.exitLoop(expression);
491 builder.readUnit(expression);
492 }
493
494 @Override
495 public void visitDoWhileExpression(JetDoWhileExpression expression) {
496 builder.read(expression);
497 LoopInfo loopInfo = builder.enterLoop(expression, null, null);
498
499 builder.bindLabel(loopInfo.getBodyEntryPoint());
500 JetExpression body = expression.getBody();
501 if (body != null) {
502 generateInstructions(body, false);
503 }
504 builder.bindLabel(loopInfo.getConditionEntryPoint());
505 JetExpression condition = expression.getCondition();
506 if (condition != null) {
507 generateInstructions(condition, true);
508 }
509 builder.jumpOnTrue(loopInfo.getEntryPoint());
510 builder.exitLoop(expression);
511 builder.readUnit(expression);
512 }
513
514 @Override
515 public void visitForExpression(JetForExpression expression) {
516 builder.read(expression);
517 JetExpression loopRange = expression.getLoopRange();
518 if (loopRange != null) {
519 generateInstructions(loopRange, false);
520 }
521 JetParameter loopParameter = expression.getLoopParameter();
522 if (loopParameter != null) {
523 generateInstructions(loopParameter, inCondition);
524 }
525 else {
526 JetMultiDeclaration multiParameter = expression.getMultiParameter();
527 generateInstructions(multiParameter, inCondition);
528 }
529
530 // TODO : primitive cases
531 Label loopExitPoint = builder.createUnboundLabel();
532 Label conditionEntryPoint = builder.createUnboundLabel();
533
534 builder.bindLabel(conditionEntryPoint);
535 builder.nondeterministicJump(loopExitPoint);
536
537 LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
538
539 builder.bindLabel(loopInfo.getBodyEntryPoint());
540 JetExpression body = expression.getBody();
541 if (body != null) {
542 generateInstructions(body, false);
543 }
544
545 builder.nondeterministicJump(loopInfo.getEntryPoint());
546 builder.exitLoop(expression);
547 builder.readUnit(expression);
548 }
549
550 @Override
551 public void visitBreakExpression(JetBreakExpression expression) {
552 JetElement loop = getCorrespondingLoop(expression);
553 if (loop != null) {
554 builder.jump(builder.getExitPoint(loop));
555 }
556 }
557
558 @Override
559 public void visitContinueExpression(JetContinueExpression expression) {
560 JetElement loop = getCorrespondingLoop(expression);
561 if (loop != null) {
562 builder.jump(builder.getEntryPoint(loop));
563 }
564 }
565
566 private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) {
567 String labelName = expression.getLabelName();
568 JetElement loop;
569 if (labelName != null) {
570 JetSimpleNameExpression targetLabel = expression.getTargetLabel();
571 assert targetLabel != null;
572 PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), targetLabel);
573 if (labeledElement instanceof JetLoopExpression) {
574 loop = (JetLoopExpression) labeledElement;
575 }
576 else {
577 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
578 loop = null;
579 }
580 }
581 else {
582 loop = builder.getCurrentLoop();
583 if (loop == null) {
584 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
585 }
586 }
587 return loop;
588 }
589
590 @Override
591 public void visitReturnExpression(JetReturnExpression expression) {
592 JetExpression returnedExpression = expression.getReturnedExpression();
593 if (returnedExpression != null) {
594 generateInstructions(returnedExpression, false);
595 }
596 JetSimpleNameExpression labelElement = expression.getTargetLabel();
597 JetElement subroutine;
598 String labelName = expression.getLabelName();
599 if (labelElement != null) {
600 assert labelName != null;
601 PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement);
602 if (labeledElement != null) {
603 assert labeledElement instanceof JetElement;
604 subroutine = (JetElement) labeledElement;
605 }
606 else {
607 subroutine = null;
608 }
609 }
610 else {
611 subroutine = builder.getReturnSubroutine();
612 // TODO : a context check
613 }
614
615 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) {
616 if (returnedExpression == null) {
617 builder.returnNoValue(expression, subroutine);
618 }
619 else {
620 builder.returnValue(expression, subroutine);
621 }
622 }
623 }
624
625 @Override
626 public void visitParameter(JetParameter parameter) {
627 builder.declare(parameter);
628 JetExpression defaultValue = parameter.getDefaultValue();
629 if (defaultValue != null) {
630 generateInstructions(defaultValue, inCondition);
631 }
632 builder.write(parameter, parameter);
633 }
634
635 @Override
636 public void visitBlockExpression(JetBlockExpression expression) {
637 List<JetElement> statements = expression.getStatements();
638 for (JetElement statement : statements) {
639 generateInstructions(statement, false);
640 }
641 if (statements.isEmpty()) {
642 builder.readUnit(expression);
643 }
644 }
645
646 @Override
647 public void visitNamedFunction(JetNamedFunction function) {
648 processLocalDeclaration(function);
649 }
650
651 @Override
652 public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
653 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
654 processLocalDeclaration(functionLiteral);
655 builder.read(expression);
656 }
657
658 @Override
659 public void visitQualifiedExpression(JetQualifiedExpression expression) {
660 generateInstructions(expression.getReceiverExpression(), false);
661 JetExpression selectorExpression = expression.getSelectorExpression();
662 if (selectorExpression != null) {
663 generateInstructions(selectorExpression, false);
664 }
665 builder.read(expression);
666 if (trace.get(BindingContext.PROCESSED, expression)) {
667 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
668 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
669 builder.jumpToError();
670 }
671 }
672 }
673
674 private void visitCall(JetCallElement call) {
675 for (ValueArgument argument : call.getValueArguments()) {
676 JetExpression argumentExpression = argument.getArgumentExpression();
677 if (argumentExpression != null) {
678 generateInstructions(argumentExpression, false);
679 }
680 }
681
682 for (JetExpression functionLiteral : call.getFunctionLiteralArguments()) {
683 generateInstructions(functionLiteral, false);
684 }
685 }
686
687 @Override
688 public void visitCallExpression(JetCallExpression expression) {
689 //inline functions after M1
690 // ResolvedCall<? extends CallableDescriptor> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
691 // assert resolvedCall != null;
692 // CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
693 // PsiElement element = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, resultingDescriptor);
694 // if (element instanceof JetNamedFunction) {
695 // JetNamedFunction namedFunction = (JetNamedFunction) element;
696 // if (namedFunction.hasModifier(JetTokens.INLINE_KEYWORD)) {
697 // }
698 // }
699
700 for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
701 generateInstructions(typeArgument, false);
702 }
703
704 visitCall(expression);
705
706 generateInstructions(expression.getCalleeExpression(), false);
707 builder.read(expression);
708 if (trace.get(BindingContext.PROCESSED, expression)) {
709 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
710 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
711 builder.jumpToError();
712 }
713 }
714 }
715
716 // @Override
717 // public void visitNewExpression(JetNewExpression expression) {
718 // // TODO : Instantiated class is loaded
719 // // TODO : type arguments?
720 // visitCall(expression);
721 // builder.read(expression);
722 // }
723
724 @Override
725 public void visitProperty(JetProperty property) {
726 builder.declare(property);
727 JetExpression initializer = property.getInitializer();
728 if (initializer != null) {
729 generateInstructions(initializer, false);
730 builder.write(property, property);
731 }
732 JetExpression delegate = property.getDelegateExpression();
733 if (delegate != null) {
734 generateInstructions(delegate, false);
735 }
736 for (JetPropertyAccessor accessor : property.getAccessors()) {
737 generateInstructions(accessor, false);
738 }
739 }
740
741 @Override
742 public void visitMultiDeclaration(JetMultiDeclaration declaration) {
743 JetExpression initializer = declaration.getInitializer();
744 if (initializer != null) {
745 generateInstructions(initializer, false);
746 }
747 List<JetMultiDeclarationEntry> entries = declaration.getEntries();
748 for (JetMultiDeclarationEntry entry : entries) {
749 builder.declare(entry);
750 builder.write(entry, entry);
751 }
752 }
753
754 @Override
755 public void visitPropertyAccessor(JetPropertyAccessor accessor) {
756 processLocalDeclaration(accessor);
757 }
758
759 @Override
760 public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) {
761 IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
762 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
763 generateInstructions(expression.getLeft(), false);
764 builder.read(expression);
765 }
766 else {
767 visitJetElement(expression);
768 }
769 }
770
771 @Override
772 public void visitThrowExpression(JetThrowExpression expression) {
773 JetExpression thrownExpression = expression.getThrownExpression();
774 if (thrownExpression != null) {
775 generateInstructions(thrownExpression, false);
776 }
777 builder.throwException(expression);
778 }
779
780 @Override
781 public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
782 for (JetExpression index : expression.getIndexExpressions()) {
783 generateInstructions(index, false);
784 }
785 generateInstructions(expression.getArrayExpression(), false);
786 // TODO : read 'get' or 'set' function
787 builder.read(expression);
788 }
789
790 @Override
791 public void visitIsExpression(JetIsExpression expression) {
792 generateInstructions(expression.getLeftHandSide(), inCondition);
793 // no CF for types
794 // TODO : builder.read(expression.getPattern());
795 builder.read(expression);
796 }
797
798 @Override
799 public void visitWhenExpression(JetWhenExpression expression) {
800 JetExpression subjectExpression = expression.getSubjectExpression();
801 if (subjectExpression != null) {
802 generateInstructions(subjectExpression, inCondition);
803 }
804 boolean hasElseOrIrrefutableBranch = false;
805
806 Label doneLabel = builder.createUnboundLabel();
807
808 Label nextLabel = null;
809 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
810 JetWhenEntry whenEntry = iterator.next();
811
812 builder.read(whenEntry);
813
814 if (whenEntry.isElse()) {
815 hasElseOrIrrefutableBranch = true;
816 if (iterator.hasNext()) {
817 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
818 }
819 }
820 boolean isIrrefutable = whenEntry.isElse();
821 if (isIrrefutable) {
822 hasElseOrIrrefutableBranch = true;
823 }
824
825 Label bodyLabel = builder.createUnboundLabel();
826
827 JetWhenCondition[] conditions = whenEntry.getConditions();
828 for (int i = 0; i < conditions.length; i++) {
829 JetWhenCondition condition = conditions[i];
830 condition.accept(conditionVisitor);
831 if (i + 1 < conditions.length) {
832 builder.nondeterministicJump(bodyLabel);
833 }
834 }
835
836 if (!isIrrefutable) {
837 nextLabel = builder.createUnboundLabel();
838 builder.nondeterministicJump(nextLabel);
839 }
840
841 builder.bindLabel(bodyLabel);
842 generateInstructions(whenEntry.getExpression(), inCondition);
843 builder.jump(doneLabel);
844
845 if (!isIrrefutable) {
846 builder.bindLabel(nextLabel);
847 }
848 }
849 builder.bindLabel(doneLabel);
850 if (!hasElseOrIrrefutableBranch && WhenChecker.mustHaveElse(expression, trace)) {
851 trace.report(NO_ELSE_IN_WHEN.on(expression));
852 }
853 }
854
855 @Override
856 public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
857 JetObjectDeclaration declaration = expression.getObjectDeclaration();
858 generateInstructions(declaration, inCondition);
859
860 List<JetDeclaration> declarations = declaration.getDeclarations();
861 List<JetDeclaration> functions = Lists.newArrayList();
862 for (JetDeclaration localDeclaration : declarations) {
863 if (!(localDeclaration instanceof JetProperty) && !(localDeclaration instanceof JetClassInitializer)) {
864 functions.add(localDeclaration);
865 }
866 }
867 for (JetDeclaration function : functions) {
868 generateInstructions(function, inCondition);
869 }
870 builder.read(expression);
871 }
872
873 @Override
874 public void visitObjectDeclaration(JetObjectDeclaration objectDeclaration) {
875 visitClassOrObject(objectDeclaration);
876 }
877
878 @Override
879 public void visitStringTemplateExpression(JetStringTemplateExpression expression) {
880 for (JetStringTemplateEntry entry : expression.getEntries()) {
881 if (entry instanceof JetStringTemplateEntryWithExpression) {
882 JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry;
883 generateInstructions(entryWithExpression.getExpression(), false);
884 }
885 }
886 builder.read(expression);
887 }
888
889 @Override
890 public void visitTypeProjection(JetTypeProjection typeProjection) {
891 // TODO : Support Type Arguments. Class object may be initialized at this point");
892 }
893
894 @Override
895 public void visitAnonymousInitializer(JetClassInitializer classInitializer) {
896 generateInstructions(classInitializer.getBody(), inCondition);
897 }
898
899 private void visitClassOrObject(JetClassOrObject classOrObject) {
900 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
901 generateInstructions(specifier, inCondition);
902 }
903 List<JetDeclaration> declarations = classOrObject.getDeclarations();
904 for (JetDeclaration declaration : declarations) {
905 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
906 generateInstructions(declaration, inCondition);
907 }
908 }
909 }
910
911 @Override
912 public void visitClass(JetClass klass) {
913 List<JetParameter> parameters = klass.getPrimaryConstructorParameters();
914 for (JetParameter parameter : parameters) {
915 generateInstructions(parameter, inCondition);
916 }
917 visitClassOrObject(klass);
918 }
919
920 @Override
921 public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
922 List<? extends ValueArgument> valueArguments = call.getValueArguments();
923 for (ValueArgument valueArgument : valueArguments) {
924 generateInstructions(valueArgument.getArgumentExpression(), inCondition);
925 }
926 }
927
928 @Override
929 public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
930 generateInstructions(specifier.getDelegateExpression(), inCondition);
931 }
932
933 @Override
934 public void visitJetFile(JetFile file) {
935 for (JetDeclaration declaration : file.getDeclarations()) {
936 if (declaration instanceof JetProperty) {
937 generateInstructions(declaration, inCondition);
938 }
939 }
940 }
941
942 @Override
943 public void visitJetElement(JetElement element) {
944 builder.unsupported(element);
945 }
946 }
947 }