CF for break and continue in nested function literals
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user