CF supported for function literals
This commit is contained in:
@@ -105,6 +105,11 @@ public class JetControlFlowProcessor {
|
||||
exitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
|
||||
value(expression.getExpression(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConstantExpression(JetConstantExpression expression) {
|
||||
builder.readNode(expression);
|
||||
|
||||
+43
-41
@@ -1,7 +1,6 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.JetControlFlowBuilder;
|
||||
import org.jetbrains.jet.lang.cfg.JetControlFlowBuilderAdapter;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
@@ -18,17 +17,20 @@ import java.util.Stack;
|
||||
*/
|
||||
public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter {
|
||||
|
||||
private final Stack<BlockInfo> loopInfo = new Stack<BlockInfo>();
|
||||
// private final Stack<BlockInfo> subroutineInfo = new Stack<BlockInfo>();
|
||||
private final Map<JetElement, BlockInfo> elementToBlockInfo = new HashMap<JetElement, BlockInfo>();
|
||||
private int labelCount = 0;
|
||||
|
||||
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
|
||||
|
||||
public JetControlFlowInstructionsGenerator() {
|
||||
public JetControlFlowInstructionsGenerator(JetElement subroutine) {
|
||||
super(null);
|
||||
pushBuilder();
|
||||
pushBuilder(subroutine);
|
||||
}
|
||||
|
||||
private void pushBuilder() {
|
||||
Pseudocode parentPseudocode = builder == null ? new Pseudocode() : builders.peek().getPseudocode();
|
||||
JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(parentPseudocode);
|
||||
private void pushBuilder(JetElement subroutine) {
|
||||
JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(subroutine);
|
||||
builders.push(worker);
|
||||
builder = worker;
|
||||
}
|
||||
@@ -42,7 +44,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
if (isFunctionLiteral) {
|
||||
pushBuilder();
|
||||
pushBuilder(builder.getCurrentSubroutine());
|
||||
builder.enterSubroutine(subroutine, false);
|
||||
}
|
||||
else {
|
||||
@@ -57,8 +59,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
JetControlFlowInstructionsGeneratorWorker worker = popBuilder();
|
||||
JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
|
||||
FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction(subroutine);
|
||||
builder.add(instruction);
|
||||
instruction.setBody(worker.getPseudocode());
|
||||
builder.add(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,40 +68,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
return builders.peek().getPseudocode();
|
||||
}
|
||||
|
||||
private static class BlockInfo {
|
||||
private final JetElement element;
|
||||
private final Label entryPoint;
|
||||
private final Label exitPoint;
|
||||
|
||||
private BlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
|
||||
this.element = element;
|
||||
this.entryPoint = entryPoint;
|
||||
this.exitPoint = exitPoint;
|
||||
}
|
||||
|
||||
public JetElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public Label getEntryPoint() {
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
public Label getExitPoint() {
|
||||
return exitPoint;
|
||||
}
|
||||
}
|
||||
|
||||
private final Stack<BlockInfo> loopInfo = new Stack<BlockInfo>();
|
||||
private final Stack<BlockInfo> subroutineInfo = new Stack<BlockInfo>();
|
||||
private final Map<JetElement, BlockInfo> elementToBlockInfo = new HashMap<JetElement, BlockInfo>();
|
||||
|
||||
private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder {
|
||||
|
||||
private final Pseudocode pseudocode;
|
||||
private final JetElement currentSubroutine;
|
||||
|
||||
private JetControlFlowInstructionsGeneratorWorker(@Nullable Pseudocode parent) {
|
||||
private JetControlFlowInstructionsGeneratorWorker(JetElement currentSubroutine) {
|
||||
this.pseudocode = new Pseudocode();
|
||||
this.currentSubroutine = currentSubroutine;
|
||||
}
|
||||
|
||||
public Pseudocode getPseudocode() {
|
||||
@@ -142,14 +118,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
Label entryPoint = createUnboundLabel();
|
||||
BlockInfo blockInfo = new BlockInfo(subroutine, entryPoint, createUnboundLabel());
|
||||
subroutineInfo.push(blockInfo);
|
||||
// subroutineInfo.push(blockInfo);
|
||||
elementToBlockInfo.put(subroutine, blockInfo);
|
||||
bindLabel(entryPoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetElement getCurrentSubroutine() {
|
||||
return subroutineInfo.empty() ? null : subroutineInfo.peek().getElement();
|
||||
return currentSubroutine;// subroutineInfo.empty() ? null : subroutineInfo.peek().getElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,7 +135,9 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
|
||||
@Override
|
||||
public Label getExitPoint(@NotNull JetElement labelElement) {
|
||||
return elementToBlockInfo.get(labelElement).getExitPoint();
|
||||
BlockInfo blockInfo = elementToBlockInfo.get(labelElement);
|
||||
assert blockInfo != null : labelElement.getText();
|
||||
return blockInfo.getExitPoint();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -169,6 +147,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
bindLabel(getExitPoint(subroutine));
|
||||
add(new SubroutineExitInstruction(subroutine));
|
||||
elementToBlockInfo.remove(subroutine);
|
||||
// subroutineInfo.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,7 +182,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
|
||||
@Override
|
||||
public void bindLabel(@NotNull Label label) {
|
||||
pseudocode.addLabel(label);
|
||||
pseudocode.bindLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,4 +206,27 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
}
|
||||
}
|
||||
|
||||
private static class BlockInfo {
|
||||
private final JetElement element;
|
||||
private final Label entryPoint;
|
||||
private final Label exitPoint;
|
||||
|
||||
private BlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
|
||||
this.element = element;
|
||||
this.entryPoint = entryPoint;
|
||||
this.exitPoint = exitPoint;
|
||||
}
|
||||
|
||||
public JetElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public Label getEntryPoint() {
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
public Label getExitPoint() {
|
||||
return exitPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,11 @@ import java.util.*;
|
||||
* @author abreslav
|
||||
*/
|
||||
public class Pseudocode {
|
||||
|
||||
public class PseudocodeLabel implements Label {
|
||||
private final String name;
|
||||
private Integer targetInstructionIndex;
|
||||
|
||||
|
||||
private PseudocodeLabel(String name) {
|
||||
this.name = name;
|
||||
@@ -28,35 +31,37 @@ public class Pseudocode {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getTargetInstructionIndex() {
|
||||
return targetInstructionIndex;
|
||||
}
|
||||
|
||||
public void setTargetInstructionIndex(int targetInstructionIndex) {
|
||||
this.targetInstructionIndex = targetInstructionIndex;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<Instruction> resolve() {
|
||||
Integer result = labels.get(this);
|
||||
assert result != null;
|
||||
return instructions.subList(result, instructions.size());
|
||||
assert targetInstructionIndex != null;
|
||||
return instructions.subList(getTargetInstructionIndex(), instructions.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
||||
private final Map<Label, Integer> labels = new LinkedHashMap<Label, Integer>();
|
||||
|
||||
// @Nullable
|
||||
// private final Pseudocode parent;
|
||||
//
|
||||
// public Pseudocode(Pseudocode parent) {
|
||||
// this.parent = parent;
|
||||
// }
|
||||
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
||||
|
||||
public PseudocodeLabel createLabel(String name) {
|
||||
return new PseudocodeLabel(name);
|
||||
PseudocodeLabel label = new PseudocodeLabel(name);
|
||||
labels.add(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
public void addInstruction(Instruction instruction) {
|
||||
instructions.add(instruction);
|
||||
}
|
||||
|
||||
public void addLabel(Label label) {
|
||||
labels.put(label, instructions.size());
|
||||
public void bindLabel(Label label) {
|
||||
((PseudocodeLabel) label).setTargetInstructionIndex(instructions.size());
|
||||
}
|
||||
|
||||
public void postProcess() {
|
||||
@@ -144,9 +149,9 @@ public class Pseudocode {
|
||||
public void dumpInstructions(@NotNull PrintStream out) {
|
||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
for (Map.Entry<Label, Integer> entry : labels.entrySet()) {
|
||||
if (entry.getValue() == i) {
|
||||
out.println(entry.getKey() + ":");
|
||||
for (PseudocodeLabel label: labels) {
|
||||
if (label.getTargetInstructionIndex() == i) {
|
||||
out.println(label.getName() + ":");
|
||||
}
|
||||
}
|
||||
out.println(" " + instruction);
|
||||
@@ -155,14 +160,13 @@ public class Pseudocode {
|
||||
|
||||
public void dumpGraph(@NotNull final PrintStream out) {
|
||||
String graphHeader = "digraph g";
|
||||
dumpSubgraph(out, graphHeader, new int[1], "");
|
||||
dumpSubgraph(out, graphHeader, new int[1], "", new HashMap<Instruction, String>());
|
||||
}
|
||||
|
||||
private void dumpSubgraph(final PrintStream out, String graphHeader, final int[] count, String style) {
|
||||
private void dumpSubgraph(final PrintStream out, String graphHeader, final int[] count, String style, final Map<Instruction, String> nodeToName) {
|
||||
out.println(graphHeader + " {");
|
||||
out.println(style);
|
||||
|
||||
final Map<Instruction, String> nodeToName = new HashMap<Instruction, String>();
|
||||
for (Instruction node : instructions) {
|
||||
if (node instanceof UnconditionalJumpInstruction) {
|
||||
continue;
|
||||
@@ -195,7 +199,7 @@ public class Pseudocode {
|
||||
@Override
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
int index = count[0];
|
||||
instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";");
|
||||
instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName);
|
||||
printEdge(out, nodeToName.get(instruction), "n" + index, null);
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
@@ -230,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();
|
||||
// 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) {
|
||||
|
||||
@@ -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