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) { private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
enterLabeledElement(labelName, labeledExpression); JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
value(labeledExpression, false); if (deparenthesized != null) {
enterLabeledElement(labelName, deparenthesized);
value(labeledExpression, false);
}
} }
@Override @Override
@@ -259,22 +262,45 @@ public class JetControlFlowProcessor {
@Override @Override
public void visitBreakExpression(JetBreakExpression expression) { public void visitBreakExpression(JetBreakExpression expression) {
JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetElement loop = getCorrespondingLoop(expression);
Label exitPoint = (labelElement != null) if (loop != null) {
? builder.getExitPoint(resolveLabel(expression.getLabelName(), expression.getTargetLabel())) builder.jump(builder.getExitPoint(loop));
: builder.getExitPoint(builder.getCurrentLoop()); }
builder.jump(exitPoint);
} }
@Override @Override
public void visitContinueExpression(JetContinueExpression expression) { public void visitContinueExpression(JetContinueExpression expression) {
JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetElement loop = getCorrespondingLoop(expression);
if (labelElement != null) { if (loop != null) {
builder.jump(builder.getEntryPoint(resolveLabel(expression.getLabelName(), expression.getTargetLabel()))); 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 { 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 @Override
@@ -50,4 +50,8 @@ public class InstructionVisitor {
public void visitInstruction(Instruction instruction) { public void visitInstruction(Instruction instruction) {
} }
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
visitInstructionWithNext(instruction);
}
} }
@@ -121,6 +121,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
// subroutineInfo.push(blockInfo); // subroutineInfo.push(blockInfo);
elementToBlockInfo.put(subroutine, blockInfo); elementToBlockInfo.put(subroutine, blockInfo);
bindLabel(entryPoint); bindLabel(entryPoint);
add(new SubroutineEnterInstruction(subroutine));
} }
@Override @Override
@@ -147,8 +147,13 @@ public class Pseudocode {
} }
public void dumpInstructions(@NotNull PrintStream out) { public void dumpInstructions(@NotNull PrintStream out) {
List<Pseudocode> locals = new ArrayList<Pseudocode>();
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) { for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
Instruction instruction = instructions.get(i); Instruction instruction = instructions.get(i);
if (instruction instanceof FunctionLiteralValueInstruction) {
FunctionLiteralValueInstruction functionLiteralValueInstruction = (FunctionLiteralValueInstruction) instruction;
locals.add(functionLiteralValueInstruction.getBody());
}
for (PseudocodeLabel label: labels) { for (PseudocodeLabel label: labels) {
if (label.getTargetInstructionIndex() == i) { if (label.getTargetInstructionIndex() == i) {
out.println(label.getName() + ":"); out.println(label.getName() + ":");
@@ -156,6 +161,9 @@ public class Pseudocode {
} }
out.println(" " + instruction); out.println(" " + instruction);
} }
for (Pseudocode local : locals) {
local.dumpInstructions(out);
}
} }
public void dumpGraph(@NotNull final PrintStream out) { public void dumpGraph(@NotNull final PrintStream out) {
@@ -191,6 +199,9 @@ public class Pseudocode {
else if (node instanceof FunctionLiteralValueInstruction) { else if (node instanceof FunctionLiteralValueInstruction) {
shape = "Mcircle"; shape = "Mcircle";
} }
else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) {
shape = "roundrect, style=rounded";
}
out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); 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.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices; 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.psi.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.*; import java.util.*;
/** /**
@@ -225,21 +230,21 @@ public class TopDownAnalyzer {
declaringScope.addFunctionDescriptor(descriptor); declaringScope.addFunctionDescriptor(descriptor);
functions.put(function, descriptor); functions.put(function, descriptor);
// JetExpression bodyExpression = function.getBodyExpression(); JetExpression bodyExpression = function.getBodyExpression();
// if (bodyExpression != null) { if (bodyExpression != null) {
// System.out.println("-------------"); System.out.println("-------------");
// JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(function); JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(function);
// new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression); new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression);
// Pseudocode pseudocode = instructionsGenerator.getPseudocode(); Pseudocode pseudocode = instructionsGenerator.getPseudocode();
// pseudocode.postProcess(); pseudocode.postProcess();
// pseudocode.dumpInstructions(System.out); pseudocode.dumpInstructions(System.out);
// System.out.println("-------------"); System.out.println("-------------");
// try { try {
// pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot")); pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot"));
// } catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
// } }
// } }
} }
private void processProperty(WritableScope declaringScope, JetProperty property) { private void processProperty(WritableScope declaringScope, JetProperty property) {
@@ -86,15 +86,6 @@ public class JetTypeInferrer {
return new TypeInferrerVisitor(scope, preferBlock).getType(expression); 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 @Nullable
private List<JetType> getTypes(JetScope scope, List<JetExpression> indexExpressions) { private List<JetType> getTypes(JetScope scope, List<JetExpression> indexExpressions) {
List<JetType> argumentTypes = new ArrayList<JetType>(); List<JetType> argumentTypes = new ArrayList<JetType>();
@@ -1318,7 +1309,7 @@ public class JetTypeInferrer {
@Override @Override
protected void visitAssignment(JetBinaryExpression expression) { protected void visitAssignment(JetBinaryExpression expression) {
JetExpression left = expression.getLeft(); JetExpression left = expression.getLeft();
JetExpression deparenthesized = deparenthesize(left); JetExpression deparenthesized = JetPsiUtil.deparenthesize(left);
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
if (deparenthesized instanceof JetArrayAccessExpression) { if (deparenthesized instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized; JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized;
@@ -29,6 +29,6 @@ public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase {
} }
public void testQualifiedThis() throws Exception { public void testQualifiedThis() throws Exception {
// doTest("/checker/QualifiedThis.jet", true, true); doTest("/checker/QualifiedThis.jet", true, true);
} }
} }