CF for break and continue in nested function literals

This commit is contained in:
Andrey Breslav
2011-04-01 14:47:11 +04:00
parent a97cad116c
commit 1e5673f479
9 changed files with 123 additions and 37 deletions
@@ -128,8 +128,11 @@ public class JetControlFlowProcessor {
}
private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
enterLabeledElement(labelName, labeledExpression);
value(labeledExpression, false);
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
if (deparenthesized != null) {
enterLabeledElement(labelName, deparenthesized);
value(labeledExpression, false);
}
}
@Override
@@ -259,22 +262,45 @@ public class JetControlFlowProcessor {
@Override
public void visitBreakExpression(JetBreakExpression expression) {
JetSimpleNameExpression labelElement = expression.getTargetLabel();
Label exitPoint = (labelElement != null)
? builder.getExitPoint(resolveLabel(expression.getLabelName(), expression.getTargetLabel()))
: builder.getExitPoint(builder.getCurrentLoop());
builder.jump(exitPoint);
JetElement loop = getCorrespondingLoop(expression);
if (loop != null) {
builder.jump(builder.getExitPoint(loop));
}
}
@Override
public void visitContinueExpression(JetContinueExpression expression) {
JetSimpleNameExpression labelElement = expression.getTargetLabel();
if (labelElement != null) {
builder.jump(builder.getEntryPoint(resolveLabel(expression.getLabelName(), expression.getTargetLabel())));
JetElement loop = getCorrespondingLoop(expression);
if (loop != null) {
builder.jump(builder.getEntryPoint(loop));
}
}
private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) {
String labelName = expression.getLabelName();
JetElement loop;
if (labelName != null) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null;
loop = resolveLabel(labelName, targetLabel);
if (!isLoop(loop)) {
semanticServices.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop");
loop = null;
}
}
else {
builder.jump(builder.getEntryPoint(builder.getCurrentLoop()));
loop = builder.getCurrentLoop();
if (loop == null) {
semanticServices.getErrorHandler().genericError(expression.getNode(), "'break' and 'continue' are only allowed inside a loop");
}
}
return loop;
}
private boolean isLoop(JetElement loop) {
return loop instanceof JetWhileExpression ||
loop instanceof JetDoWhileExpression ||
loop instanceof JetForExpression;
}
@Override
@@ -50,4 +50,8 @@ public class InstructionVisitor {
public void visitInstruction(Instruction instruction) {
}
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
visitInstructionWithNext(instruction);
}
}
@@ -121,6 +121,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
// subroutineInfo.push(blockInfo);
elementToBlockInfo.put(subroutine, blockInfo);
bindLabel(entryPoint);
add(new SubroutineEnterInstruction(subroutine));
}
@Override
@@ -147,8 +147,13 @@ public class Pseudocode {
}
public void dumpInstructions(@NotNull PrintStream out) {
List<Pseudocode> locals = new ArrayList<Pseudocode>();
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
Instruction instruction = instructions.get(i);
if (instruction instanceof FunctionLiteralValueInstruction) {
FunctionLiteralValueInstruction functionLiteralValueInstruction = (FunctionLiteralValueInstruction) instruction;
locals.add(functionLiteralValueInstruction.getBody());
}
for (PseudocodeLabel label: labels) {
if (label.getTargetInstructionIndex() == i) {
out.println(label.getName() + ":");
@@ -156,6 +161,9 @@ public class Pseudocode {
}
out.println(" " + instruction);
}
for (Pseudocode local : locals) {
local.dumpInstructions(out);
}
}
public void dumpGraph(@NotNull final PrintStream out) {
@@ -191,6 +199,9 @@ public class Pseudocode {
else if (node instanceof FunctionLiteralValueInstruction) {
shape = "Mcircle";
}
else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) {
shape = "roundrect, style=rounded";
}
out.println(name + "[label=\"" + text + "\", shape=" + shape + "];");
}
@@ -0,0 +1,30 @@
package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetElement;
/**
* @author abreslav
*/
public class SubroutineEnterInstruction extends InstructionWithNext {
private final JetElement subroutine;
public SubroutineEnterInstruction(@NotNull JetElement subroutine) {
super(subroutine);
this.subroutine = subroutine;
}
public JetElement getSubroutine() {
return subroutine;
}
@Override
public void accept(InstructionVisitor visitor) {
visitor.visitSubroutineEnter(this);
}
@Override
public String toString() {
return "<START>";
}
}
@@ -0,0 +1,18 @@
package org.jetbrains.jet.lang.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author abreslav
*/
public class JetPsiUtil {
@Nullable
public static JetExpression deparenthesize(@NotNull JetExpression expression) {
JetExpression result = expression;
while (result instanceof JetParenthesizedExpression) {
result = ((JetParenthesizedExpression) expression).getExpression();
}
return result;
}
}
@@ -2,9 +2,14 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.*;
/**
@@ -225,21 +230,21 @@ public class TopDownAnalyzer {
declaringScope.addFunctionDescriptor(descriptor);
functions.put(function, descriptor);
// JetExpression bodyExpression = function.getBodyExpression();
// if (bodyExpression != null) {
// System.out.println("-------------");
// JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(function);
// new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression);
// Pseudocode pseudocode = instructionsGenerator.getPseudocode();
// pseudocode.postProcess();
// pseudocode.dumpInstructions(System.out);
// System.out.println("-------------");
// try {
// pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot"));
// } catch (FileNotFoundException e) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
// }
// }
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
System.out.println("-------------");
JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(function);
new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression);
Pseudocode pseudocode = instructionsGenerator.getPseudocode();
pseudocode.postProcess();
pseudocode.dumpInstructions(System.out);
System.out.println("-------------");
try {
pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot"));
} catch (FileNotFoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
private void processProperty(WritableScope declaringScope, JetProperty property) {
@@ -86,15 +86,6 @@ public class JetTypeInferrer {
return new TypeInferrerVisitor(scope, preferBlock).getType(expression);
}
@Nullable
private static JetExpression deparenthesize(@NotNull JetExpression expression) {
JetExpression result = expression;
while (result instanceof JetParenthesizedExpression) {
result = ((JetParenthesizedExpression) expression).getExpression();
}
return result;
}
@Nullable
private List<JetType> getTypes(JetScope scope, List<JetExpression> indexExpressions) {
List<JetType> argumentTypes = new ArrayList<JetType>();
@@ -1318,7 +1309,7 @@ public class JetTypeInferrer {
@Override
protected void visitAssignment(JetBinaryExpression expression) {
JetExpression left = expression.getLeft();
JetExpression deparenthesized = deparenthesize(left);
JetExpression deparenthesized = JetPsiUtil.deparenthesize(left);
JetExpression right = expression.getRight();
if (deparenthesized instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized;
@@ -29,6 +29,6 @@ public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase {
}
public void testQualifiedThis() throws Exception {
// doTest("/checker/QualifiedThis.jet", true, true);
doTest("/checker/QualifiedThis.jet", true, true);
}
}