mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Refactor Ruby & Python Contrlo flow building
This commit is contained in:
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public interface ConditionalInstruction extends Instruction {
|
||||
boolean getResult();
|
||||
PsiElement getCondition();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.intellij.codeInsight.controlflow;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public interface ControlFlow {
|
||||
Instruction[] getInstructions();
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.intellij.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.impl.ConditionalInstructionImpl;
|
||||
import com.intellij.codeInsight.controlflow.impl.ControlFlowImpl;
|
||||
import com.intellij.codeInsight.controlflow.impl.InstructionImpl;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class ControlFlowBuilder {
|
||||
// Here we store all the instructions
|
||||
|
||||
|
||||
public List<Instruction> instructions;
|
||||
|
||||
public Instruction prevInstruction;
|
||||
|
||||
// Here we store all the pending instructions with their scope
|
||||
public List<Pair<PsiElement, Instruction>> pending;
|
||||
|
||||
public int instructionCount;
|
||||
|
||||
public ControlFlowBuilder() {
|
||||
instructions = new ArrayList<Instruction>();
|
||||
pending = new ArrayList<Pair<PsiElement, Instruction>>();
|
||||
instructionCount = 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Instruction findInstructionByElement(final PsiElement element) {
|
||||
for (int i = instructions.size() - 1; i >= 0; i--) {
|
||||
final Instruction instruction = instructions.get(i);
|
||||
if (element.equals(instruction.getElement())) {
|
||||
return instruction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds edge between 2 edges
|
||||
*
|
||||
* @param beginInstruction Begin of new edge
|
||||
* @param endInstruction End of new edge
|
||||
*/
|
||||
public void addEdge(final Instruction beginInstruction, final Instruction endInstruction) {
|
||||
if (beginInstruction == null || endInstruction == null) {
|
||||
return;
|
||||
}
|
||||
if (!beginInstruction.allSucc().contains(endInstruction)) {
|
||||
beginInstruction.allSucc().add(endInstruction);
|
||||
}
|
||||
|
||||
if (!endInstruction.allPred().contains(beginInstruction)) {
|
||||
endInstruction.allPred().add(beginInstruction);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new node and set prev instruction pointing to this instruction
|
||||
*
|
||||
* @param instruction new instruction
|
||||
*/
|
||||
public void addNode(final Instruction instruction) {
|
||||
instructions.add(instruction);
|
||||
if (prevInstruction != null) {
|
||||
addEdge(prevInstruction, instruction);
|
||||
}
|
||||
prevInstruction = instruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops control flow, used for break, next, redo
|
||||
*/
|
||||
public void flowAbrupted() {
|
||||
prevInstruction = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds pending edge in pendingScope
|
||||
*
|
||||
* @param pendingScope Scope for instruction
|
||||
* @param instruction "Last" pending instruction
|
||||
*/
|
||||
public void addPendingEdge(final PsiElement pendingScope, final Instruction instruction) {
|
||||
if (instruction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
// another optimization! Place pending before first scope, not contained in pendingScope
|
||||
// the same logic is used in checkPending
|
||||
if (pendingScope != null) {
|
||||
for (; i < pending.size(); i++) {
|
||||
final Pair<PsiElement, Instruction> pair = pending.get(i);
|
||||
final PsiElement scope = pair.getFirst();
|
||||
if (scope == null) {
|
||||
continue;
|
||||
}
|
||||
if (!PsiTreeUtil.isAncestor(scope, pendingScope, true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pending.add(i, Pair.create(pendingScope, instruction));
|
||||
}
|
||||
|
||||
public void checkPending(@NotNull final Instruction instruction) {
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (element == null) {
|
||||
// if element is null (fake element, we just process all pending)
|
||||
for (Pair<PsiElement, Instruction> pair : pending) {
|
||||
addEdge(pair.getSecond(), instruction);
|
||||
}
|
||||
pending.clear();
|
||||
}
|
||||
else {
|
||||
// else we just all the pending with scope containing in element
|
||||
// reverse order is just an optimization
|
||||
for (int i = pending.size() - 1; i >= 0; i--) {
|
||||
final Pair<PsiElement, Instruction> pair = pending.get(i);
|
||||
final PsiElement scopeWhenToAdd = pair.getFirst();
|
||||
if (scopeWhenToAdd == null) {
|
||||
continue;
|
||||
}
|
||||
if (!PsiTreeUtil.isAncestor(scopeWhenToAdd, element, false)) {
|
||||
addEdge(pair.getSecond(), instruction);
|
||||
pending.remove(i);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates instruction for given element, and adds it to myInstructionsStack
|
||||
* Warning! Always call finishNode after startNode
|
||||
*
|
||||
* @param element Element to create instruction for
|
||||
* @return new instruction
|
||||
*/
|
||||
public Instruction startNode(final PsiElement element) {
|
||||
final Instruction instruction = new InstructionImpl(this, element);
|
||||
addNode(instruction);
|
||||
checkPending(instruction);
|
||||
return instruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates conditional instruction for given element, and adds it to myInstructionsStack
|
||||
* Warning! Always call finishNode after startNode
|
||||
*
|
||||
* @param element Element to create instruction for
|
||||
* @return new instruction
|
||||
*/
|
||||
public Instruction startConditionalNode(final PsiElement element, final PsiElement condition, final boolean result) {
|
||||
final ConditionalInstruction instruction = new ConditionalInstructionImpl(this, element, condition, result);
|
||||
addNode(instruction);
|
||||
checkPending(instruction);
|
||||
return instruction;
|
||||
}
|
||||
|
||||
public ControlFlow build(final PsiElementVisitor visitor, final PsiElement element) {
|
||||
// create start pseudo node
|
||||
startNode(null);
|
||||
|
||||
element.acceptChildren(visitor);
|
||||
|
||||
// create end pseudo node and close all pending edges
|
||||
checkPending(startNode(null));
|
||||
|
||||
final List<Instruction> result = instructions;
|
||||
return new ControlFlowImpl(result.toArray(new Instruction[result.size()]));
|
||||
}
|
||||
|
||||
|
||||
public static interface PendingProcessor {
|
||||
void process(PsiElement pendingScope, Instruction instruction);
|
||||
}
|
||||
|
||||
public void processPending(final PendingProcessor processor) {
|
||||
final List<Pair<PsiElement, Instruction>> pending = this.pending;
|
||||
this.pending = new ArrayList<Pair<PsiElement, Instruction>>();
|
||||
for (Pair<PsiElement, Instruction> pair : pending) {
|
||||
processor.process(pair.getFirst(), pair.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public interface Instruction {
|
||||
@Nullable
|
||||
PsiElement getElement();
|
||||
|
||||
Collection<Instruction> allSucc();
|
||||
|
||||
Collection<Instruction> allPred();
|
||||
|
||||
String getElementPresentation();
|
||||
|
||||
int num();
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.controlflow.impl;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
|
||||
import com.intellij.codeInsight.controlflow.ConditionalInstruction;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class ConditionalInstructionImpl extends InstructionImpl implements ConditionalInstruction {
|
||||
private final PsiElement myCondition;
|
||||
private final boolean myResult;
|
||||
|
||||
public ConditionalInstructionImpl(final ControlFlowBuilder builder,
|
||||
final PsiElement element,
|
||||
final PsiElement condition,
|
||||
final boolean result) {
|
||||
super(builder, element);
|
||||
myCondition = condition;
|
||||
myResult = result;
|
||||
}
|
||||
|
||||
public PsiElement getCondition() {
|
||||
return myCondition;
|
||||
}
|
||||
|
||||
public boolean getResult() {
|
||||
return myResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + ". Condition: " + myCondition.getText() + ":" + myResult;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.controlflow.impl;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ControlFlow;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class ControlFlowImpl implements ControlFlow {
|
||||
private final Instruction[] myInstructions;
|
||||
|
||||
public ControlFlowImpl(Instruction[] instructions) {
|
||||
myInstructions = instructions;
|
||||
}
|
||||
|
||||
public Instruction[] getInstructions() {
|
||||
return myInstructions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.controlflow.impl;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class InstructionImpl implements Instruction {
|
||||
final ArrayList<Instruction> myPred = new ArrayList<Instruction>();
|
||||
final ArrayList<Instruction> mySucc = new ArrayList<Instruction>();
|
||||
|
||||
protected final PsiElement myElement;
|
||||
private final int myNumber;
|
||||
|
||||
@Nullable
|
||||
public final PsiElement getElement() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
public InstructionImpl(final ControlFlowBuilder builder, final PsiElement element) {
|
||||
myElement = element;
|
||||
myNumber = builder.instructionCount++;
|
||||
}
|
||||
|
||||
public final Collection<Instruction> allSucc() {
|
||||
return mySucc;
|
||||
}
|
||||
|
||||
public final Collection<Instruction> allPred() {
|
||||
return myPred;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(myNumber);
|
||||
builder.append("(");
|
||||
for (int i = 0; i < mySucc.size(); i++) {
|
||||
if (i > 0) builder.append(',');
|
||||
builder.append(mySucc.get(i).num());
|
||||
}
|
||||
builder.append(") ").append(getElementPresentation());
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public String getElementPresentation() {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("element: ").append(myElement);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public final int num() {
|
||||
return myNumber;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user