
org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl Maven / Gradle / Ivy
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.cfg.pseudocode;
import com.google.common.collect.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.Label;
import org.jetbrains.jet.lang.cfg.LoopInfo;
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.PseudocodeTraverserPackage;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.*;
import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD;
import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.FORWARD;
public class PseudocodeImpl implements Pseudocode {
public class PseudocodeLabel implements Label {
private final String name;
private Integer targetInstructionIndex;
private PseudocodeLabel(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
public Integer getTargetInstructionIndex() {
return targetInstructionIndex;
}
public void setTargetInstructionIndex(int targetInstructionIndex) {
this.targetInstructionIndex = targetInstructionIndex;
}
@Nullable
private List resolve() {
assert targetInstructionIndex != null;
return mutableInstructionList.subList(getTargetInstructionIndex(), mutableInstructionList.size());
}
public Instruction resolveToInstruction() {
assert targetInstructionIndex != null;
return mutableInstructionList.get(targetInstructionIndex);
}
public Label copy() {
return new PseudocodeLabel("copy " + name);
}
}
private final List mutableInstructionList = new ArrayList();
private final List instructions = new ArrayList();
private Pseudocode parent = null;
private Set localDeclarations = null;
//todo getters
private final Map representativeInstructions = new HashMap();
private final Map loopInfo = Maps.newHashMap();
private final List labels = new ArrayList();
private final JetElement correspondingElement;
private SubroutineExitInstruction exitInstruction;
private SubroutineSinkInstruction sinkInstruction;
private SubroutineExitInstruction errorInstruction;
private boolean postPrecessed = false;
public PseudocodeImpl(JetElement correspondingElement) {
this.correspondingElement = correspondingElement;
}
@NotNull
@Override
public JetElement getCorrespondingElement() {
return correspondingElement;
}
@NotNull
@Override
public Set getLocalDeclarations() {
if (localDeclarations == null) {
localDeclarations = getLocalDeclarations(this);
}
return localDeclarations;
}
@NotNull
private static Set getLocalDeclarations(@NotNull Pseudocode pseudocode) {
Set localDeclarations = Sets.newLinkedHashSet();
for (Instruction instruction : ((PseudocodeImpl)pseudocode).mutableInstructionList) {
if (instruction instanceof LocalFunctionDeclarationInstruction) {
localDeclarations.add((LocalFunctionDeclarationInstruction) instruction);
localDeclarations.addAll(getLocalDeclarations(((LocalFunctionDeclarationInstruction)instruction).getBody()));
}
}
return localDeclarations;
}
@Override
@Nullable
public Pseudocode getParent() {
return parent;
}
private void setParent(Pseudocode parent) {
this.parent = parent;
}
@NotNull
public Pseudocode getRootPseudocode() {
Pseudocode parent = getParent();
while (parent != null) {
if (parent.getParent() == null) return parent;
parent = parent.getParent();
}
return this;
}
/*package*/ PseudocodeLabel createLabel(String name) {
PseudocodeLabel label = new PseudocodeLabel(name);
labels.add(label);
return label;
}
@Override
@NotNull
public List getInstructions() {
return instructions;
}
@NotNull
@Override
public List getReversedInstructions() {
LinkedHashSet traversedInstructions = Sets.newLinkedHashSet();
PseudocodeTraverserPackage.traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null);
if (traversedInstructions.size() < instructions.size()) {
List simplyReversedInstructions = Lists.newArrayList(instructions);
Collections.reverse(simplyReversedInstructions);
for (Instruction instruction : simplyReversedInstructions) {
if (!traversedInstructions.contains(instruction)) {
PseudocodeTraverserPackage.traverseFollowingInstructions(instruction, traversedInstructions, BACKWARD, null);
}
}
}
return Lists.newArrayList(traversedInstructions);
}
//for tests only
@NotNull
public List getAllInstructions() {
return mutableInstructionList;
}
@Override
@NotNull
public List getDeadInstructions() {
List deadInstructions = Lists.newArrayList();
for (Instruction instruction : mutableInstructionList) {
if (isDead(instruction)) {
deadInstructions.add(instruction);
}
}
return deadInstructions;
}
private static boolean isDead(@NotNull Instruction instruction) {
if (!((InstructionImpl)instruction).isDead()) return false;
for (Instruction copy : instruction.getCopies()) {
if (!((InstructionImpl)copy).isDead()) return false;
}
return true;
}
//for tests only
@NotNull
public List getLabels() {
return labels;
}
/*package*/ void addExitInstruction(SubroutineExitInstruction exitInstruction) {
addInstruction(exitInstruction);
assert this.exitInstruction == null;
this.exitInstruction = exitInstruction;
}
/*package*/ void addSinkInstruction(SubroutineSinkInstruction sinkInstruction) {
addInstruction(sinkInstruction);
assert this.sinkInstruction == null;
this.sinkInstruction = sinkInstruction;
}
/*package*/ void addErrorInstruction(SubroutineExitInstruction errorInstruction) {
addInstruction(errorInstruction);
assert this.errorInstruction == null;
this.errorInstruction = errorInstruction;
}
/*package*/ void addInstruction(Instruction instruction) {
mutableInstructionList.add(instruction);
instruction.setOwner(this);
if (instruction instanceof JetElementInstruction) {
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
representativeInstructions.put(elementInstruction.getElement(), instruction);
}
}
/*package*/ void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
loopInfo.put(expression, blockInfo);
}
@Override
@NotNull
public SubroutineExitInstruction getExitInstruction() {
return exitInstruction;
}
@Override
@NotNull
public SubroutineSinkInstruction getSinkInstruction() {
return sinkInstruction;
}
@Override
@NotNull
public SubroutineEnterInstruction getEnterInstruction() {
return (SubroutineEnterInstruction) mutableInstructionList.get(0);
}
/*package*/ void bindLabel(Label label) {
((PseudocodeLabel) label).setTargetInstructionIndex(mutableInstructionList.size());
}
public void postProcess() {
if (postPrecessed) return;
postPrecessed = true;
errorInstruction.setSink(getSinkInstruction());
exitInstruction.setSink(getSinkInstruction());
int index = 0;
for (Instruction instruction : mutableInstructionList) {
//recursively invokes 'postProcess' for local declarations
processInstruction(instruction, index);
index++;
}
if (getParent() != null) return;
// Collecting reachable instructions should be done after processing all instructions
// (including instructions in local declarations) to avoid being in incomplete state.
collectAndCacheReachableInstructions();
for (LocalFunctionDeclarationInstruction localFunctionDeclarationInstruction : getLocalDeclarations()) {
((PseudocodeImpl) localFunctionDeclarationInstruction.getBody()).collectAndCacheReachableInstructions();
}
}
private void collectAndCacheReachableInstructions() {
Set reachableInstructions = collectReachableInstructions();
for (Instruction instruction : mutableInstructionList) {
if (reachableInstructions.contains(instruction)) {
instructions.add(instruction);
}
}
markDeadInstructions();
}
private void processInstruction(Instruction instruction, final int currentPosition) {
instruction.accept(new InstructionVisitor() {
@Override
public void visitInstructionWithNext(InstructionWithNext instruction) {
instruction.setNext(getNextPosition(currentPosition));
}
@Override
public void visitJump(AbstractJumpInstruction instruction) {
instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
}
@Override
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
instruction.setNext(getNextPosition(currentPosition));
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy