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) {
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user