added repeat pseudocode method
repeat from startLabel to finishLabel (logic is inside PseudocodeImpl)
This commit is contained in:
@@ -88,4 +88,6 @@ public interface JetControlFlowBuilder {
|
|||||||
|
|
||||||
// Other
|
// Other
|
||||||
void unsupported(JetElement element);
|
void unsupported(JetElement element);
|
||||||
|
|
||||||
|
void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,4 +222,10 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
assert builder != null;
|
assert builder != null;
|
||||||
builder.declare(property);
|
builder.declare(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel) {
|
||||||
|
assert builder != null;
|
||||||
|
builder.repeatPseudocode(startLabel, finishLabel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -345,11 +345,38 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel);
|
builder.bindLabel(resultLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class FinallyBlockGenerator {
|
||||||
|
private final JetFinallySection finallyBlock;
|
||||||
|
private Label startFinally = null;
|
||||||
|
private Label finishFinally = null;
|
||||||
|
|
||||||
|
private FinallyBlockGenerator(JetFinallySection block) {
|
||||||
|
finallyBlock = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generate() {
|
||||||
|
JetBlockExpression finalExpression = finallyBlock.getFinalExpression();
|
||||||
|
if (finalExpression == null) return;
|
||||||
|
if (startFinally != null) {
|
||||||
|
assert finishFinally != null;
|
||||||
|
builder.repeatPseudocode(startFinally, finishFinally);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startFinally = builder.createUnboundLabel("start finally");
|
||||||
|
builder.bindLabel(startFinally);
|
||||||
|
value(finalExpression, inCondition);
|
||||||
|
finishFinally = builder.createUnboundLabel("finish finally");
|
||||||
|
builder.bindLabel(finishFinally);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTryExpression(JetTryExpression expression) {
|
public void visitTryExpression(JetTryExpression expression) {
|
||||||
builder.read(expression);
|
builder.read(expression);
|
||||||
final JetFinallySection finallyBlock = expression.getFinallyBlock();
|
final JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||||
|
final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
|
||||||
if (finallyBlock != null) {
|
if (finallyBlock != null) {
|
||||||
builder.enterTryFinally(new GenerationTrigger() {
|
builder.enterTryFinally(new GenerationTrigger() {
|
||||||
private boolean working = false;
|
private boolean working = false;
|
||||||
@@ -359,7 +386,7 @@ public class JetControlFlowProcessor {
|
|||||||
// This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
|
// This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
|
||||||
if (working) return;
|
if (working) return;
|
||||||
working = true;
|
working = true;
|
||||||
value(finallyBlock.getFinalExpression(), inCondition);
|
finallyBlockGenerator.generate();
|
||||||
working = false;
|
working = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -425,11 +452,11 @@ public class JetControlFlowProcessor {
|
|||||||
Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
|
Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
|
||||||
builder.jump(skipFinallyToErrorBlock);
|
builder.jump(skipFinallyToErrorBlock);
|
||||||
builder.bindLabel(onExceptionToFinallyBlock);
|
builder.bindLabel(onExceptionToFinallyBlock);
|
||||||
value(finallyBlock.getFinalExpression(), inCondition);
|
finallyBlockGenerator.generate();
|
||||||
builder.jumpToError();
|
builder.jumpToError();
|
||||||
builder.bindLabel(skipFinallyToErrorBlock);
|
builder.bindLabel(skipFinallyToErrorBlock);
|
||||||
|
|
||||||
value(finallyBlock.getFinalExpression(), inCondition);
|
finallyBlockGenerator.generate();
|
||||||
}
|
}
|
||||||
builder.stopAllowDead(allowDeadLabels);
|
builder.stopAllowDead(allowDeadLabels);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -328,6 +328,11 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
public void unsupported(JetElement element) {
|
public void unsupported(JetElement element) {
|
||||||
add(new UnsupportedElementInstruction(element));
|
add(new UnsupportedElementInstruction(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel) {
|
||||||
|
pseudocode.repeatPart(startLabel, finishLabel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TryFinallyBlockInfo extends BlockInfo {
|
public static class TryFinallyBlockInfo extends BlockInfo {
|
||||||
|
|||||||
@@ -16,9 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.*;
|
||||||
import com.google.common.collect.Maps;
|
import com.intellij.util.containers.MultiMap;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.cfg.Label;
|
import org.jetbrains.jet.lang.cfg.Label;
|
||||||
@@ -79,6 +78,9 @@ public class PseudocodeImpl implements Pseudocode {
|
|||||||
return mutableInstructionList.get(targetInstructionIndex);
|
return mutableInstructionList.get(targetInstructionIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Label copy() {
|
||||||
|
return new PseudocodeLabel("copy " + name, allowDead);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<Instruction> mutableInstructionList = new ArrayList<Instruction>();
|
private final List<Instruction> mutableInstructionList = new ArrayList<Instruction>();
|
||||||
@@ -92,7 +94,7 @@ public class PseudocodeImpl implements Pseudocode {
|
|||||||
private final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
|
private final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
|
||||||
|
|
||||||
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
||||||
private final Map<PseudocodeLabel, Collection<Label>> stopAllowDeadLabels = Maps.newHashMap();
|
private final Map<Label, Collection<Label>> stopAllowDeadLabels = Maps.newHashMap();
|
||||||
|
|
||||||
private final JetElement correspondingElement;
|
private final JetElement correspondingElement;
|
||||||
private SubroutineExitInstruction exitInstruction;
|
private SubroutineExitInstruction exitInstruction;
|
||||||
@@ -398,8 +400,8 @@ public class PseudocodeImpl implements Pseudocode {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private Map<Instruction, Collection<Label>> prepareAllowDeadStoppers() {
|
private Map<Instruction, Collection<Label>> prepareAllowDeadStoppers() {
|
||||||
Map<Instruction, Collection<Label>> stopAllowedDeadInstructions = Maps.newHashMap();
|
Map<Instruction, Collection<Label>> stopAllowedDeadInstructions = Maps.newHashMap();
|
||||||
for (Map.Entry<PseudocodeLabel, Collection<Label>> entry : stopAllowDeadLabels.entrySet()) {
|
for (Map.Entry<Label, Collection<Label>> entry : stopAllowDeadLabels.entrySet()) {
|
||||||
PseudocodeLabel stopAllowedDeadLabel = entry.getKey();
|
Label stopAllowedDeadLabel = entry.getKey();
|
||||||
Instruction stopAllowDeadInsruction = getJumpTarget(stopAllowedDeadLabel);
|
Instruction stopAllowDeadInsruction = getJumpTarget(stopAllowedDeadLabel);
|
||||||
if (((InstructionImpl)stopAllowDeadInsruction).isDead()) {
|
if (((InstructionImpl)stopAllowDeadInsruction).isDead()) {
|
||||||
stopAllowedDeadInstructions.put(stopAllowDeadInsruction, entry.getValue());
|
stopAllowedDeadInstructions.put(stopAllowDeadInsruction, entry.getValue());
|
||||||
@@ -458,4 +460,68 @@ public class PseudocodeImpl implements Pseudocode {
|
|||||||
assert targetPosition < mutableInstructionList.size() : currentPosition;
|
assert targetPosition < mutableInstructionList.size() : currentPosition;
|
||||||
return mutableInstructionList.get(targetPosition);
|
return mutableInstructionList.get(targetPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void repeatPart(@NotNull Label startLabel, @NotNull Label finishLabel) {
|
||||||
|
Integer startIndex = ((PseudocodeLabel) startLabel).getTargetInstructionIndex();
|
||||||
|
assert startIndex != null;
|
||||||
|
Integer finishIndex = ((PseudocodeLabel) finishLabel).getTargetInstructionIndex();
|
||||||
|
assert finishIndex != null;
|
||||||
|
|
||||||
|
Map<Label, Label> originalToCopy = Maps.newHashMap();
|
||||||
|
Multimap<Instruction, Label> originalLabelsForInstruction = HashMultimap.create();
|
||||||
|
for (PseudocodeLabel label : labels) {
|
||||||
|
Integer index = label.getTargetInstructionIndex();
|
||||||
|
if (index == null) continue; //label is not bounded yet
|
||||||
|
if (label == startLabel || label == finishLabel) continue;
|
||||||
|
|
||||||
|
if (startIndex <= index && index <= finishIndex) {
|
||||||
|
originalToCopy.put(label, label.copy());
|
||||||
|
originalLabelsForInstruction.put(getJumpTarget(label), label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int index = startIndex; index < finishIndex; index++) {
|
||||||
|
Instruction oldInstruction = mutableInstructionList.get(index);
|
||||||
|
Instruction newInstruction = copyInstruction(oldInstruction, originalToCopy);
|
||||||
|
if (originalLabelsForInstruction.containsKey(oldInstruction)) {
|
||||||
|
Collection<Label> oldLabels = originalLabelsForInstruction.get(oldInstruction);
|
||||||
|
for (Label oldLabel : oldLabels) {
|
||||||
|
bindLabel(originalToCopy.get(oldLabel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addInstruction(newInstruction);
|
||||||
|
}
|
||||||
|
for (Map.Entry<Label, Label> entry : originalToCopy.entrySet()) {
|
||||||
|
Label oldLabel = entry.getKey();
|
||||||
|
Label newLabel = entry.getValue();
|
||||||
|
Collection<Label> stopAllowDead = stopAllowDeadLabels.get(oldLabel);
|
||||||
|
if (stopAllowDead != null) {
|
||||||
|
stopAllowDeadLabels.put(newLabel, copyLabels(stopAllowDead, originalToCopy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Instruction copyInstruction(@NotNull Instruction instruction, @NotNull Map<Label, Label> originalToCopy) {
|
||||||
|
if (instruction instanceof AbstractJumpInstruction) {
|
||||||
|
Label originalTarget = ((AbstractJumpInstruction) instruction).getTargetLabel();
|
||||||
|
if (originalToCopy.containsKey(originalTarget)) {
|
||||||
|
return ((AbstractJumpInstruction)instruction).copy(originalToCopy.get(originalTarget));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (instruction instanceof NondeterministicJumpInstruction) {
|
||||||
|
List<Label> originalTargets = ((NondeterministicJumpInstruction) instruction).getTargetLabels();
|
||||||
|
List<Label> copyTargets = copyLabels(originalTargets, originalToCopy);
|
||||||
|
return ((NondeterministicJumpInstruction) instruction).copy(copyTargets);
|
||||||
|
}
|
||||||
|
return ((InstructionImpl)instruction).copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private List<Label> copyLabels(Collection<Label> labels, Map<Label, Label> originalToCopy) {
|
||||||
|
List<Label> newLabels = Lists.newArrayList();
|
||||||
|
for (Label label : labels) {
|
||||||
|
Label newLabel = originalToCopy.get(label);
|
||||||
|
newLabels.add(newLabel != null ? newLabel : label);
|
||||||
|
}
|
||||||
|
return newLabels;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user