Tests for basic control flow structures
This commit is contained in:
@@ -49,6 +49,8 @@ public interface JetControlFlowBuilder {
|
|||||||
void returnValue(@NotNull JetElement subroutine);
|
void returnValue(@NotNull JetElement subroutine);
|
||||||
void returnNoValue(@NotNull JetElement subroutine);
|
void returnNoValue(@NotNull JetElement subroutine);
|
||||||
|
|
||||||
|
void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
void unsupported(JetElement element);
|
void unsupported(JetElement element);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,4 +118,9 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
public void unsupported(JetElement element) {
|
public void unsupported(JetElement element) {
|
||||||
builder.unsupported(element);
|
builder.unsupported(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||||
|
builder.writeNode(assignment, lValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,348 +0,0 @@
|
|||||||
package org.jetbrains.jet.lang.cfg;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author abreslav
|
|
||||||
*/
|
|
||||||
//public class JetControlFlowGraphBuilder extends AbstractControlFlowBuilder {
|
|
||||||
//
|
|
||||||
// private final List<CFGNode> nodes = new ArrayList<CFGNode>();
|
|
||||||
//
|
|
||||||
// private final List<CFGEdge> edges = new ArrayList<CFGEdge>();
|
|
||||||
// private final Map<Label, CFGNode> labelsToNodes = new HashMap<Label, CFGNode>();
|
|
||||||
// // toLabel -> edge
|
|
||||||
// private final Map<Label, List<CFGEdge>> pendingEdges = new HashMap<Label, List<CFGEdge>>();
|
|
||||||
//
|
|
||||||
// private List<Label> labelsToBeBound = new ArrayList<Label>();
|
|
||||||
//
|
|
||||||
// private CFGNode currentNode;
|
|
||||||
//
|
|
||||||
// public JetControlFlowGraphBuilder(JetExpression block) {
|
|
||||||
//// currentNode = createNode(block);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void build(Pseudocode pseudocode) {
|
|
||||||
// List<Instruction> instructions = pseudocode.getInstructions();
|
|
||||||
// Map<Label, Integer> labels = pseudocode.getLabels();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void exitSubroutine(JetElement element) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @NotNull
|
|
||||||
// private CFGNode closest(List<CFGNode> nodes, int index) {
|
|
||||||
// int size = nodes.size();
|
|
||||||
// for (int i = index; i < size; i++) {
|
|
||||||
// CFGNode cfgNode = nodes.get(i);
|
|
||||||
// if (cfgNode != null) return cfgNode;
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void dumpGraph(PrintStream out) {
|
|
||||||
// out.println("digraph g {");
|
|
||||||
//
|
|
||||||
// Map<CFGNode, String> nodeToName = new HashMap<CFGNode, String>();
|
|
||||||
// int count = 0;
|
|
||||||
// for (CFGNode node : nodes) {
|
|
||||||
// String name = "n" + count++;
|
|
||||||
// nodeToName.put(node, name);
|
|
||||||
// String text = node.getElement().getText();
|
|
||||||
// int newline = text.indexOf("\n");
|
|
||||||
// if (newline >= 0) {
|
|
||||||
// text = text.substring(0, newline);
|
|
||||||
// }
|
|
||||||
// String shape = node instanceof CFGConditionNode ? "diamond" : "box";
|
|
||||||
// out.println(name + "[label=\"" + text + "\", shape=" + shape + "];");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (CFGEdge edge : edges) {
|
|
||||||
// String from = nodeToName.get(edge.getFrom());
|
|
||||||
// String to = nodeToName.get(edge.getTo());
|
|
||||||
//
|
|
||||||
// String label = edge.getDebugLabel();
|
|
||||||
// if (label != null) {
|
|
||||||
// label = "[label=\"" + label + "\"]";
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// label = "";
|
|
||||||
// }
|
|
||||||
// out.println(from + " -> " + to + label + ";");
|
|
||||||
// }
|
|
||||||
// out.println("}");
|
|
||||||
// out.close();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private CFGNode createNode(JetExpression block) {
|
|
||||||
// CFGNode node = new CFGReadNode(block);
|
|
||||||
// afterNodeCreation(node);
|
|
||||||
// return node;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void afterNodeCreation(CFGNode node) {
|
|
||||||
// nodes.add(node);
|
|
||||||
// bindLabelIfNeeded(node);
|
|
||||||
//
|
|
||||||
// if (currentNode != null) {
|
|
||||||
// createEdgeIfNeeded(currentNode, node);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// currentNode = node;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Nullable
|
|
||||||
// private CFGEdge createEdgeIfNeeded(@NotNull CFGNode from, CFGNode to) {
|
|
||||||
// CFGEdge edge = new CFGEdge(from, to);
|
|
||||||
// if (from instanceof CFGConditionNode) {
|
|
||||||
// CFGConditionNode conditionNode = (CFGConditionNode) from;
|
|
||||||
// if (conditionNode.getElseEdge() == null) {
|
|
||||||
// conditionNode.setElseEdge(edge);
|
|
||||||
// }
|
|
||||||
// else if (conditionNode.getThenEdge() == null) {
|
|
||||||
// conditionNode.setThenEdge(edge);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if (from instanceof CFGReadNode) {
|
|
||||||
// CFGReadNode readNode = (CFGReadNode) from;
|
|
||||||
// if (readNode.getOutgoingEdge() == null) {
|
|
||||||
// readNode.setOutgoingEdge(edge);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// return readNode.getOutgoingEdge();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// edges.add(edge);
|
|
||||||
// return edge;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void bindLabelIfNeeded(CFGNode node) {
|
|
||||||
// for (Label label : labelsToBeBound) {
|
|
||||||
// labelsToNodes.put(label, node);
|
|
||||||
// List<CFGEdge> edges = pendingEdges.get(label);
|
|
||||||
// if (edges != null) {
|
|
||||||
// for (CFGEdge edge : edges) {
|
|
||||||
// edge.setTo(node);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// labelsToBeBound.clear();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Nullable
|
|
||||||
// private CFGEdge createEdgeToLabel(CFGNode fromNode, Label toLabel) {
|
|
||||||
// CFGNode toNode = labelsToNodes.get(toLabel);
|
|
||||||
// if (toNode != null) {
|
|
||||||
// return createEdgeIfNeeded(fromNode, toNode);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// List<CFGEdge> edges = pendingEdges.get(toLabel);
|
|
||||||
// if (edges == null) {
|
|
||||||
// edges = new ArrayList<CFGEdge>();
|
|
||||||
// pendingEdges.put(toLabel, edges);
|
|
||||||
// }
|
|
||||||
// CFGEdge edge = createEdgeIfNeeded(fromNode, null);
|
|
||||||
// if (edge != null) {
|
|
||||||
// edges.add(edge);
|
|
||||||
// }
|
|
||||||
// return edge;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void readNode(JetExpression element) {
|
|
||||||
// createNode(element);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void jump(Label label) {
|
|
||||||
// CFGNode target = labelsToNodes.get(label);
|
|
||||||
// if (target != null) {
|
|
||||||
// createEdgeIfNeeded(currentNode, target);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// createEdgeToLabel(currentNode, label);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void bindLabel(Label label) {
|
|
||||||
// assert !labelsToNodes.containsKey(label) : label;
|
|
||||||
// labelsToBeBound.add(label);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void jumpOnFalse(Label label) {
|
|
||||||
// CFGConditionNode conditionNode = new CFGConditionNode(currentNode.getElement());
|
|
||||||
// afterNodeCreation(conditionNode);
|
|
||||||
// conditionNode.setElseEdge(createEdgeToLabel(conditionNode, label));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void jumpOnTrue(Label label) {
|
|
||||||
// CFGConditionNode conditionNode = new CFGConditionNode(currentNode.getElement());
|
|
||||||
// afterNodeCreation(conditionNode);
|
|
||||||
// conditionNode.setThenEdge(createEdgeToLabel(conditionNode, label));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void createBoundLabel(JetSimpleNameExpression labelElement, JetExpression labeledExpression) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Label getEntryPoint(JetSimpleNameExpression labelElement) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void jumpToLoopExitPoint(JetSimpleNameExpression labelElement) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Label getCurrentSubroutineExitPoint() {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void returnValue(Label label) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void nondeterministicJump(Label firstBranch, Label secondBranch) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void exitTryFinally() {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void popCatchClauses() {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void pushCatchClauses(List<JetCatchClause> catchClauses) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void enterTryFinally(JetBlockExpression element) {
|
|
||||||
// throw new UnsupportedOperationException(); // TODO
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void unsupported(JetElement element) {
|
|
||||||
// throw new IllegalStateException("Unsupported element: " + element.getText() + " " + element);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//abstract class CFGNode {
|
|
||||||
// private JetElement element;
|
|
||||||
//
|
|
||||||
// public CFGNode(JetElement element) {
|
|
||||||
// this.element = element;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @NotNull
|
|
||||||
// public JetElement getElement() {
|
|
||||||
// return element;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setElement(JetElement element) {
|
|
||||||
// this.element = element;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//class CFGReadNode extends CFGNode {
|
|
||||||
// private CFGEdge outgoingEdge;
|
|
||||||
//
|
|
||||||
// public CFGReadNode(JetElement element) {
|
|
||||||
// super(element);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public CFGEdge getOutgoingEdge() {
|
|
||||||
// return outgoingEdge;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setOutgoingEdge(CFGEdge outgoingEdge) {
|
|
||||||
// this.outgoingEdge = outgoingEdge;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//class CFGConditionNode extends CFGNode {
|
|
||||||
//
|
|
||||||
// private CFGEdge thenEdge;
|
|
||||||
// private CFGEdge elseEdge;
|
|
||||||
//
|
|
||||||
// public CFGConditionNode(JetElement element) {
|
|
||||||
// super(element);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public CFGConditionNode() {
|
|
||||||
// super(null);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public CFGEdge getThenEdge() {
|
|
||||||
// return thenEdge;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setThenEdge(CFGEdge thenEdge) {
|
|
||||||
// this.thenEdge = thenEdge;
|
|
||||||
// thenEdge.setDebugLabel("yes");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public CFGEdge getElseEdge() {
|
|
||||||
// return elseEdge;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setElseEdge(CFGEdge elseEdge) {
|
|
||||||
// this.elseEdge = elseEdge;
|
|
||||||
// elseEdge.setDebugLabel("no");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//class CFGEdge {
|
|
||||||
// private CFGNode from;
|
|
||||||
// private CFGNode to;
|
|
||||||
// private String debugLabel = null;
|
|
||||||
//
|
|
||||||
// public CFGEdge(CFGNode from, CFGNode to) {
|
|
||||||
// this.from = from;
|
|
||||||
// this.to = to;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public CFGNode getFrom() {
|
|
||||||
// return from;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setFrom(CFGNode from) {
|
|
||||||
// this.from = from;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public CFGNode getTo() {
|
|
||||||
// return to;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setTo(CFGNode to) {
|
|
||||||
// this.to = to;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public String getDebugLabel() {
|
|
||||||
// return debugLabel;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void setDebugLabel(String debugLabel) {
|
|
||||||
// this.debugLabel = debugLabel;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -167,11 +167,24 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel);
|
builder.bindLabel(resultLabel);
|
||||||
}
|
}
|
||||||
|
else if (operationType == JetTokens.EQ) {
|
||||||
|
JetExpression left = expression.getLeft();
|
||||||
|
if (right != null) {
|
||||||
|
value(right, false);
|
||||||
|
}
|
||||||
|
if (left instanceof JetSimpleNameExpression) {
|
||||||
|
builder.writeNode(expression, left);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("Assignments to " + left + " are not supported yet"); // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
value(expression.getLeft(), false);
|
value(expression.getLeft(), false);
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
value(right, false);
|
value(right, false);
|
||||||
}
|
}
|
||||||
|
value(expression.getOperationReference(), false);
|
||||||
builder.readNode(expression);
|
builder.readNode(expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +207,10 @@ public class JetControlFlowProcessor {
|
|||||||
value(expression.getCondition(), false);
|
value(expression.getCondition(), false);
|
||||||
Label elseLabel = builder.createUnboundLabel();
|
Label elseLabel = builder.createUnboundLabel();
|
||||||
builder.jumpOnFalse(elseLabel);
|
builder.jumpOnFalse(elseLabel);
|
||||||
value(expression.getThen(), true);
|
JetExpression then = expression.getThen();
|
||||||
|
if (then != null) {
|
||||||
|
value(then, true);
|
||||||
|
}
|
||||||
Label resultLabel = builder.createUnboundLabel();
|
Label resultLabel = builder.createUnboundLabel();
|
||||||
builder.jump(resultLabel);
|
builder.jump(resultLabel);
|
||||||
builder.bindLabel(elseLabel);
|
builder.bindLabel(elseLabel);
|
||||||
@@ -368,6 +384,51 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) {
|
||||||
|
value(expression.getReceiverExpression(), false);
|
||||||
|
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||||
|
if (selectorExpression != null) {
|
||||||
|
value(selectorExpression, false);
|
||||||
|
}
|
||||||
|
builder.readNode(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitCallExpression(JetCallExpression expression) {
|
||||||
|
for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
|
||||||
|
value(typeArgument, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JetArgument argument : expression.getValueArguments()) {
|
||||||
|
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||||
|
if (argumentExpression != null) {
|
||||||
|
value(argumentExpression, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) {
|
||||||
|
value(functionLiteral, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
value(expression.getCalleeExpression(), false);
|
||||||
|
builder.readNode(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitProperty(JetProperty property) {
|
||||||
|
JetExpression initializer = property.getInitializer();
|
||||||
|
if (initializer != null) {
|
||||||
|
value(initializer, false);
|
||||||
|
builder.writeNode(property, property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitTypeProjection(JetTypeProjection typeProjection) {
|
||||||
|
// TODO : Support Type Arguments. Class object may be initialized at this point");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitJetElement(JetElement elem) {
|
public void visitJetElement(JetElement elem) {
|
||||||
builder.unsupported(elem);
|
builder.unsupported(elem);
|
||||||
|
|||||||
@@ -54,4 +54,8 @@ public class InstructionVisitor {
|
|||||||
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
|
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
|
||||||
visitInstructionWithNext(instruction);
|
visitInstructionWithNext(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
||||||
|
visitInstructionWithNext(writeValueInstruction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -159,6 +159,11 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
add(new ReturnNoValueInstruction(getExitPoint(subroutine)));
|
add(new ReturnNoValueInstruction(getExitPoint(subroutine)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||||
|
add(new WriteValueInstruction(assignment, lValue));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNode(@NotNull JetExpression expression) {
|
public void readNode(@NotNull JetExpression expression) {
|
||||||
add(new ReadValueInstruction(expression));
|
add(new ReadValueInstruction(expression));
|
||||||
|
|||||||
@@ -193,21 +193,6 @@ public class Pseudocode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpGraph(@NotNull final PrintStream out) {
|
|
||||||
String graphHeader = "digraph g";
|
|
||||||
dumpSubgraph(out, graphHeader, new int[1], "", new HashMap<Instruction, String>());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dumpSubgraph(final PrintStream out, String graphHeader, final int[] count, String style, final Map<Instruction, String> nodeToName) {
|
|
||||||
out.println(graphHeader + " {");
|
|
||||||
out.println(style);
|
|
||||||
|
|
||||||
dumpNodes(out, count, nodeToName);
|
|
||||||
dumpEdges(out, count, nodeToName);
|
|
||||||
|
|
||||||
out.println("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dumpEdges(final PrintStream out, final int[] count, final Map<Instruction, String> nodeToName) {
|
public void dumpEdges(final PrintStream out, final int[] count, final Map<Instruction, String> nodeToName) {
|
||||||
for (final Instruction fromInst : instructions) {
|
for (final Instruction fromInst : instructions) {
|
||||||
fromInst.accept(new InstructionVisitor() {
|
fromInst.accept(new InstructionVisitor() {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class WriteValueInstruction extends InstructionWithNext {
|
||||||
|
@NotNull
|
||||||
|
private final JetElement lValue;
|
||||||
|
|
||||||
|
public WriteValueInstruction(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||||
|
super(assignment);
|
||||||
|
this.lValue = lValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(InstructionVisitor visitor) {
|
||||||
|
visitor.visitWriteValue(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (lValue instanceof JetNamedDeclaration) {
|
||||||
|
JetNamedDeclaration value = (JetNamedDeclaration) lValue;
|
||||||
|
return value.getName() + " <- ";
|
||||||
|
}
|
||||||
|
return lValue.getText() + " <-";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -166,23 +166,10 @@ public class ClassDescriptorResolver {
|
|||||||
List<TypeParameterDescriptor> typeParameterDescriptors = resolveTypeParameters(functionDescriptor, innerScope, function.getTypeParameters());
|
List<TypeParameterDescriptor> typeParameterDescriptors = resolveTypeParameters(functionDescriptor, innerScope, function.getTypeParameters());
|
||||||
List<ValueParameterDescriptor> valueParameterDescriptors = resolveValueParameters(functionDescriptor, innerScope, function.getValueParameters());
|
List<ValueParameterDescriptor> valueParameterDescriptors = resolveValueParameters(functionDescriptor, innerScope, function.getValueParameters());
|
||||||
|
|
||||||
JetType returnType;
|
|
||||||
JetTypeReference returnTypeRef = function.getReturnTypeRef();
|
JetTypeReference returnTypeRef = function.getReturnTypeRef();
|
||||||
JetExpression bodyExpression = function.getBodyExpression();
|
JetType returnType = null;
|
||||||
if (returnTypeRef != null) {
|
if (returnTypeRef != null) {
|
||||||
returnType = typeResolver.resolveType(innerScope, returnTypeRef);
|
returnType = typeResolver.resolveType(innerScope, returnTypeRef);
|
||||||
// TODO : check body type, consider recursion
|
|
||||||
if (bodyExpression != null) {
|
|
||||||
semanticServices.getTypeInferrer(trace).getType(innerScope, bodyExpression, function.hasBlockBody());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (bodyExpression == null) {
|
|
||||||
semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body element");
|
|
||||||
returnType = ErrorUtils.createErrorType("No type, no body");
|
|
||||||
} else {
|
|
||||||
// TODO : Recursion possible
|
|
||||||
returnType = semanticServices.getTypeInferrer(trace).safeGetType(innerScope, bodyExpression, function.hasBlockBody());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
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.JetControlFlowProcessor;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTrace;
|
||||||
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||||
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
|
||||||
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.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +19,7 @@ public class TopDownAnalyzer {
|
|||||||
|
|
||||||
private final Map<JetClass, MutableClassDescriptor> classes = new LinkedHashMap<JetClass, MutableClassDescriptor>();
|
private final Map<JetClass, MutableClassDescriptor> classes = new LinkedHashMap<JetClass, MutableClassDescriptor>();
|
||||||
private final Map<JetNamespace, WritableScope> namespaceScopes = new LinkedHashMap<JetNamespace, WritableScope>();
|
private final Map<JetNamespace, WritableScope> namespaceScopes = new LinkedHashMap<JetNamespace, WritableScope>();
|
||||||
private final Map<JetDeclaration, FunctionDescriptor> functions = new HashMap<JetDeclaration, FunctionDescriptor>();
|
private final Map<JetDeclaration, FunctionDescriptor> functions = new LinkedHashMap<JetDeclaration, FunctionDescriptor>();
|
||||||
private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>();
|
private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>();
|
||||||
|
|
||||||
private final JetSemanticServices semanticServices;
|
private final JetSemanticServices semanticServices;
|
||||||
@@ -28,6 +27,7 @@ public class TopDownAnalyzer {
|
|||||||
private final BindingTrace trace;
|
private final BindingTrace trace;
|
||||||
private final JetTypeInferrer typeInferrer;
|
private final JetTypeInferrer typeInferrer;
|
||||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||||
|
private boolean readyToProcessExpressions = false;
|
||||||
|
|
||||||
public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||||
this.semanticServices = semanticServices;
|
this.semanticServices = semanticServices;
|
||||||
@@ -55,6 +55,7 @@ public class TopDownAnalyzer {
|
|||||||
collectTypeDeclarators(toplevelScope, declarations);
|
collectTypeDeclarators(toplevelScope, declarations);
|
||||||
resolveTypeDeclarations();
|
resolveTypeDeclarations();
|
||||||
processBehaviorDeclarators(toplevelScope, declarations);
|
processBehaviorDeclarators(toplevelScope, declarations);
|
||||||
|
readyToProcessExpressions = true;
|
||||||
resolveBehaviorDeclarationBodies();
|
resolveBehaviorDeclarationBodies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +273,7 @@ public class TopDownAnalyzer {
|
|||||||
|
|
||||||
assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
|
assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
|
||||||
JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
|
JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
|
||||||
|
|
||||||
JetExpression bodyExpression = declarationWithBody.getBodyExpression();
|
JetExpression bodyExpression = declarationWithBody.getBodyExpression();
|
||||||
|
|
||||||
if (bodyExpression != null) {
|
if (bodyExpression != null) {
|
||||||
@@ -286,13 +288,43 @@ public class TopDownAnalyzer {
|
|||||||
preferBlock = jetFunction.hasBlockBody();
|
preferBlock = jetFunction.hasBlockBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveExpression(parameterScope, bodyExpression, preferBlock, controlFlowDataTrace);
|
JetType returnType = resolveExpression(parameterScope, bodyExpression, preferBlock, controlFlowDataTrace);
|
||||||
|
|
||||||
|
if (declaration instanceof JetFunction) {
|
||||||
|
JetFunction function = (JetFunction) declaration;
|
||||||
|
if (function.getReturnTypeRef() != null) {
|
||||||
|
if (returnType != null) {
|
||||||
|
if (!semanticServices.getTypeChecker().isConvertibleTo(returnType, descriptor.getUnsubstitutedReturnType())) {
|
||||||
|
semanticServices.getErrorHandler().typeMismatch(bodyExpression, descriptor.getUnsubstitutedReturnType(), returnType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JetType safeReturnType = returnType;
|
||||||
|
if (safeReturnType == null) {
|
||||||
|
safeReturnType = ErrorUtils.createErrorType("Unable to infer body type");
|
||||||
|
}
|
||||||
|
((FunctionDescriptorImpl) descriptor).setUnsubstitutedReturnType(safeReturnType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (declaration instanceof JetFunction) {
|
||||||
|
JetFunction function = (JetFunction) declaration;
|
||||||
|
if (function.getReturnTypeRef() == null) {
|
||||||
|
semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body element");
|
||||||
|
((FunctionDescriptorImpl) descriptor).setUnsubstitutedReturnType(ErrorUtils.createErrorType("No type, no body"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert descriptor.getUnsubstitutedReturnType() != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock, JetControlFlowDataTrace controlFlowDataTrace) {
|
@Nullable
|
||||||
typeInferrer.getType(scope, expression, preferBlock);
|
private JetType resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock, JetControlFlowDataTrace controlFlowDataTrace) {
|
||||||
|
assert readyToProcessExpressions : "Must be ready collecting types";
|
||||||
|
return typeInferrer.getType(scope, expression, preferBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.types;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -35,13 +36,17 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
|
|||||||
public FunctionDescriptor initialize(
|
public FunctionDescriptor initialize(
|
||||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||||
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
|
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
|
||||||
@NotNull JetType unsubstitutedReturnType) {
|
@Nullable JetType unsubstitutedReturnType) {
|
||||||
this.typeParameters = typeParameters;
|
this.typeParameters = typeParameters;
|
||||||
this.unsubstitutedValueParameters = unsubstitutedValueParameters;
|
this.unsubstitutedValueParameters = unsubstitutedValueParameters;
|
||||||
this.unsubstitutedReturnType = unsubstitutedReturnType;
|
this.unsubstitutedReturnType = unsubstitutedReturnType;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUnsubstitutedReturnType(@NotNull JetType unsubstitutedReturnType) {
|
||||||
|
this.unsubstitutedReturnType = unsubstitutedReturnType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<TypeParameterDescriptor> getTypeParameters() {
|
public List<TypeParameterDescriptor> getTypeParameters() {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
== assignments ==
|
||||||
|
fun assignments() : Unit {
|
||||||
|
var x = 1
|
||||||
|
x = 2
|
||||||
|
|
||||||
|
x = if (true) 1 else 2
|
||||||
|
|
||||||
|
val y = true && false
|
||||||
|
val z = false && true
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
r(1)
|
||||||
|
x <-
|
||||||
|
r(2)
|
||||||
|
x <-
|
||||||
|
r(true)
|
||||||
|
jf(l2)
|
||||||
|
r(1)
|
||||||
|
jmp(l3)
|
||||||
|
l2:
|
||||||
|
r(2)
|
||||||
|
l3:
|
||||||
|
x <-
|
||||||
|
r(true)
|
||||||
|
jf(l4)
|
||||||
|
r(false)
|
||||||
|
l4:
|
||||||
|
y <-
|
||||||
|
r(false)
|
||||||
|
jf(l5)
|
||||||
|
r(true)
|
||||||
|
l5:
|
||||||
|
z <-
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fun assignments() : Unit {
|
||||||
|
var x = 1
|
||||||
|
x = 2
|
||||||
|
|
||||||
|
x = if (true) 1 else 2
|
||||||
|
|
||||||
|
val y = true && false
|
||||||
|
val z = false && true
|
||||||
|
}
|
||||||
@@ -1,6 +1,97 @@
|
|||||||
|
== anonymous_0 ==
|
||||||
|
{1}
|
||||||
|
---------------------
|
||||||
|
l2:
|
||||||
|
<START>
|
||||||
|
r(1)
|
||||||
|
l3:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
== f ==
|
||||||
|
fun f(a : Boolean) : Unit {
|
||||||
|
1
|
||||||
|
a
|
||||||
|
2.lng
|
||||||
|
foo(a, 3)
|
||||||
|
genfun<Any>()
|
||||||
|
flfun {1}
|
||||||
|
3.equals(4)
|
||||||
|
|
||||||
|
3 equals 4
|
||||||
|
|
||||||
|
1 + 2
|
||||||
|
|
||||||
|
a && true
|
||||||
|
a || false
|
||||||
|
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
l0:
|
l0:
|
||||||
<START>
|
<START>
|
||||||
|
r(1)
|
||||||
r(a)
|
r(a)
|
||||||
|
r(2)
|
||||||
|
r(lng)
|
||||||
|
r(2.lng)
|
||||||
|
r(a)
|
||||||
|
r(3)
|
||||||
|
r(foo)
|
||||||
|
r(foo(a, 3))
|
||||||
|
r(genfun)
|
||||||
|
r(genfun<Any>())
|
||||||
|
rf({1})
|
||||||
|
r(flfun)
|
||||||
|
r(flfun {1})
|
||||||
|
r(3)
|
||||||
|
r(4)
|
||||||
|
r(equals)
|
||||||
|
r(equals(4))
|
||||||
|
r(3.equals(4))
|
||||||
|
r(3)
|
||||||
|
r(4)
|
||||||
|
r(equals)
|
||||||
|
r(3 equals 4)
|
||||||
|
r(1)
|
||||||
|
r(2)
|
||||||
|
r(+)
|
||||||
|
r(1 + 2)
|
||||||
|
r(a)
|
||||||
|
jf(l4)
|
||||||
|
r(true)
|
||||||
|
l4:
|
||||||
|
r(a)
|
||||||
|
jt(l5)
|
||||||
|
r(false)
|
||||||
|
l1:
|
||||||
|
l5:
|
||||||
|
<END>
|
||||||
|
l2:
|
||||||
|
<START>
|
||||||
|
r(1)
|
||||||
|
l3:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
== foo ==
|
||||||
|
fun foo(a : Boolean, b : Int) : Unit {}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
== genfun ==
|
||||||
|
fun genfun<T>() : Unit {}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
== flfun ==
|
||||||
|
fun flfun(f : {() : Any}) : Unit {}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
l1:
|
l1:
|
||||||
<END>
|
<END>
|
||||||
=====================
|
=====================
|
||||||
|
|||||||
@@ -1,3 +1,23 @@
|
|||||||
fun f(a : Boolean) {
|
fun f(a : Boolean) : Unit {
|
||||||
|
1
|
||||||
a
|
a
|
||||||
}
|
2.lng
|
||||||
|
foo(a, 3)
|
||||||
|
genfun<Any>()
|
||||||
|
flfun {1}
|
||||||
|
3.equals(4)
|
||||||
|
|
||||||
|
3 equals 4
|
||||||
|
|
||||||
|
1 + 2
|
||||||
|
|
||||||
|
a && true
|
||||||
|
a || false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(a : Boolean, b : Int) : Unit {}
|
||||||
|
|
||||||
|
fun genfun<T>() : Unit {}
|
||||||
|
|
||||||
|
fun flfun(f : {() : Any}) : Unit {}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
== lazyBooleans ==
|
||||||
|
fun lazyBooleans(a : Boolean, b : Boolean) : Unit {
|
||||||
|
if (a) {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
3
|
||||||
|
if (a && b) 5 else 6
|
||||||
|
7
|
||||||
|
if (a || b) 8 else 9
|
||||||
|
10
|
||||||
|
if (a) 11
|
||||||
|
12
|
||||||
|
if (a) else 13
|
||||||
|
14
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
r(a)
|
||||||
|
jf(l2)
|
||||||
|
r(1)
|
||||||
|
jmp(l3)
|
||||||
|
l2:
|
||||||
|
r(2)
|
||||||
|
l3:
|
||||||
|
r(3)
|
||||||
|
r(a)
|
||||||
|
jf(l4)
|
||||||
|
r(b)
|
||||||
|
l4:
|
||||||
|
jf(l5)
|
||||||
|
r(5)
|
||||||
|
jmp(l6)
|
||||||
|
l5:
|
||||||
|
r(6)
|
||||||
|
l6:
|
||||||
|
r(7)
|
||||||
|
r(a)
|
||||||
|
jt(l7)
|
||||||
|
r(b)
|
||||||
|
l7:
|
||||||
|
jf(l8)
|
||||||
|
r(8)
|
||||||
|
jmp(l9)
|
||||||
|
l8:
|
||||||
|
r(9)
|
||||||
|
l9:
|
||||||
|
r(10)
|
||||||
|
r(a)
|
||||||
|
jf(l10)
|
||||||
|
r(11)
|
||||||
|
jmp(l11)
|
||||||
|
l10:
|
||||||
|
l11:
|
||||||
|
r(12)
|
||||||
|
r(a)
|
||||||
|
jf(l12)
|
||||||
|
jmp(l13)
|
||||||
|
l12:
|
||||||
|
r(13)
|
||||||
|
l13:
|
||||||
|
r(14)
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
fun lazyBooleans(a : Boolean, b : Boolean) : Unit {
|
||||||
|
if (a) {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
3
|
||||||
|
if (a && b) 5 else 6
|
||||||
|
7
|
||||||
|
if (a || b) 8 else 9
|
||||||
|
10
|
||||||
|
if (a) 11
|
||||||
|
12
|
||||||
|
if (a) else 13
|
||||||
|
14
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
== foo ==
|
||||||
|
fun foo() {
|
||||||
|
if (b)
|
||||||
|
return@a 1
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
l6:
|
||||||
|
<START>
|
||||||
|
r(b)
|
||||||
|
jf(l8)
|
||||||
|
r(1)
|
||||||
|
ret(*)
|
||||||
|
jmp(l9)
|
||||||
|
l7:
|
||||||
|
l8:
|
||||||
|
l9:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
== anonymous_0 ==
|
||||||
|
{a =>
|
||||||
|
2
|
||||||
|
fun foo() {
|
||||||
|
if (b)
|
||||||
|
return@a 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return@a 5;
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
l4:
|
||||||
|
<START>
|
||||||
|
r(2)
|
||||||
|
r(5)
|
||||||
|
ret(*)
|
||||||
|
l5:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
== nonlocals1 ==
|
||||||
|
fun nonlocals1(a : Boolean, b : Boolean) : Unit {
|
||||||
|
if (a)
|
||||||
|
return 1
|
||||||
|
1
|
||||||
|
@a{a =>
|
||||||
|
2
|
||||||
|
fun foo() {
|
||||||
|
if (b)
|
||||||
|
return@a 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return@a 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
1.lng
|
||||||
|
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
r(a)
|
||||||
|
jf(l2)
|
||||||
|
r(1)
|
||||||
|
ret(*)
|
||||||
|
jmp(l3)
|
||||||
|
l2:
|
||||||
|
l3:
|
||||||
|
r(1)
|
||||||
|
rf({a =>
|
||||||
|
2
|
||||||
|
fun foo() {
|
||||||
|
if (b)
|
||||||
|
return@a 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return@a 5;
|
||||||
|
})
|
||||||
|
r(1)
|
||||||
|
r(lng)
|
||||||
|
r(1.lng)
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
l4:
|
||||||
|
<START>
|
||||||
|
r(2)
|
||||||
|
r(5)
|
||||||
|
ret(*)
|
||||||
|
l5:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
fun nonlocals1(a : Boolean, b : Boolean) : Unit {
|
||||||
|
if (a)
|
||||||
|
return 1
|
||||||
|
1
|
||||||
|
@a{a =>
|
||||||
|
2
|
||||||
|
fun foo() {
|
||||||
|
if (b)
|
||||||
|
return@a 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return@a 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
1.lng
|
||||||
|
|
||||||
|
}
|
||||||
@@ -42,62 +42,83 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
|||||||
configureByFile(getTestFilePath());
|
configureByFile(getTestFilePath());
|
||||||
JetFile file = (JetFile) getFile();
|
JetFile file = (JetFile) getFile();
|
||||||
|
|
||||||
|
final Map<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
||||||
|
final JetControlFlowDataTrace jetControlFlowDataTrace = new JetControlFlowDataTrace() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
|
data.put(element, pseudocode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.THROW_EXCEPTION, new JetControlFlowDataTraceFactory() {
|
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.THROW_EXCEPTION, new JetControlFlowDataTraceFactory() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JetControlFlowDataTrace createTrace(JetElement element) {
|
public JetControlFlowDataTrace createTrace(JetElement element) {
|
||||||
return new JetControlFlowDataTrace() {
|
return jetControlFlowDataTrace;
|
||||||
private final Map<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@Override
|
try {
|
||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
try {
|
||||||
data.put(element, pseudocode);
|
processCFData(name, data);
|
||||||
}
|
} catch (AssertionFailedError e) {
|
||||||
|
dumpDot(name, data.values());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
dumpDot(name, data.values());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
}
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
processCFData(name);
|
|
||||||
} catch (AssertionFailedError e) {
|
|
||||||
dumpDot(name, data.values());
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processCFData(String name) throws IOException {
|
private void processCFData(String name, Map<JetElement, Pseudocode> data) throws IOException {
|
||||||
Collection<Pseudocode> pseudocodes = data.values();
|
Collection<Pseudocode> pseudocodes = data.values();
|
||||||
for (Pseudocode pseudocode : pseudocodes) {
|
for (Pseudocode pseudocode : pseudocodes) {
|
||||||
pseudocode.postProcess();
|
pseudocode.postProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder instructionDump = new StringBuilder();
|
StringBuilder instructionDump = new StringBuilder();
|
||||||
for (Pseudocode pseudocode : pseudocodes) {
|
int i = 0;
|
||||||
pseudocode.dumpInstructions(instructionDump);
|
for (Pseudocode pseudocode : pseudocodes) {
|
||||||
instructionDump.append("=====================\n");
|
JetElement correspondingElement = pseudocode.getCorrespondingElement();
|
||||||
}
|
String label;
|
||||||
|
if (correspondingElement instanceof JetNamedDeclaration) {
|
||||||
|
JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) correspondingElement;
|
||||||
|
label = namedDeclaration.getName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
label = "anonymous_" + i++;
|
||||||
|
}
|
||||||
|
|
||||||
String expectedInstructionsFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".instructions");
|
instructionDump.append("== ").append(label).append(" ==\n");
|
||||||
File expectedInstructionsFile = new File(expectedInstructionsFileName);
|
|
||||||
if (!expectedInstructionsFile.exists()) {
|
|
||||||
FileUtil.writeToFile(expectedInstructionsFile, instructionDump.toString());
|
|
||||||
fail("No expected instructions for " + name + " generated result is written into " + expectedInstructionsFileName);
|
|
||||||
}
|
|
||||||
String expectedInstructions = FileUtil.loadFile(expectedInstructionsFile);
|
|
||||||
|
|
||||||
assertEquals(expectedInstructions, instructionDump.toString());
|
instructionDump.append(correspondingElement.getText());
|
||||||
|
instructionDump.append("\n---------------------\n");
|
||||||
|
pseudocode.dumpInstructions(instructionDump);
|
||||||
|
instructionDump.append("=====================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
String expectedInstructionsFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".instructions");
|
||||||
|
File expectedInstructionsFile = new File(expectedInstructionsFileName);
|
||||||
|
if (!expectedInstructionsFile.exists()) {
|
||||||
|
FileUtil.writeToFile(expectedInstructionsFile, instructionDump.toString());
|
||||||
|
fail("No expected instructions for " + name + " generated result is written into " + expectedInstructionsFileName);
|
||||||
|
}
|
||||||
|
String expectedInstructions = FileUtil.loadFile(expectedInstructionsFile);
|
||||||
|
|
||||||
|
assertEquals(expectedInstructions, instructionDump.toString());
|
||||||
|
|
||||||
// StringBuilder graphDump = new StringBuilder();
|
// StringBuilder graphDump = new StringBuilder();
|
||||||
// for (Pseudocode pseudocode : pseudocodes) {
|
// for (Pseudocode pseudocode : pseudocodes) {
|
||||||
// topOrderDump(pseudocode.)
|
// topOrderDump(pseudocode.)
|
||||||
// }
|
// }
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpDot(String name, Collection<Pseudocode> pseudocodes) throws FileNotFoundException {
|
private void dumpDot(String name, Collection<Pseudocode> pseudocodes) throws FileNotFoundException {
|
||||||
|
|||||||
Reference in New Issue
Block a user