/* * Copyright 2011 Jon S Akhtar (Sylvanaar) * * 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.sylvanaar.idea.Lua.lang.psi.dataFlow; import com.sylvanaar.idea.Lua.lang.psi.controlFlow.CallEnvironment; import com.sylvanaar.idea.Lua.lang.psi.controlFlow.CallInstruction; import com.sylvanaar.idea.Lua.lang.psi.controlFlow.ControlFlowUtil; import com.sylvanaar.idea.Lua.lang.psi.controlFlow.Instruction; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; /** * @author ven */ public class DFAEngine<E> { private final Instruction[] myFlow; private final DfaInstance<E> myDfa; private final Semilattice<E> mySemilattice; public DFAEngine(Instruction[] flow, DfaInstance<E> dfa, Semilattice<E> semilattice) { myFlow = flow; myDfa = dfa; mySemilattice = semilattice; } private static class MyCallEnvironment implements CallEnvironment { ArrayList<Stack<CallInstruction>> myEnv; private MyCallEnvironment(int instructionNum) { myEnv = new ArrayList<Stack<CallInstruction>>(instructionNum); for (int i = 0; i < instructionNum; i++) { myEnv.add(new Stack<CallInstruction>()); } } public Stack<CallInstruction> callStack(Instruction instruction) { return myEnv.get(instruction.num()); } public void update(Stack<CallInstruction> callStack, Instruction instruction) { myEnv.set(instruction.num(), callStack); } } public ArrayList<E> performDFA() { ArrayList<E> info = new ArrayList<E>(myFlow.length); CallEnvironment env = new MyCallEnvironment(myFlow.length); for (int i = 0; i < myFlow.length; i++) { info.add(myDfa.initial()); } boolean[] visited = new boolean[myFlow.length]; final boolean forward = myDfa.isForward(); int[] order = ControlFlowUtil.postorder(myFlow); //todo for backward? for (int i = forward ? 0 : myFlow.length - 1; forward ? i < myFlow.length : i >= 0;) { Instruction instr = myFlow[order[i]]; if (!visited[instr.num()]) { Queue<Instruction> worklist = new LinkedList<Instruction>(); worklist.add(instr); visited[instr.num()] = true; while (!worklist.isEmpty()) { final Instruction curr = worklist.remove(); final int num = curr.num(); final E oldE = info.get(num); E newE = join(curr, info, env); myDfa.fun(newE, curr); if (!mySemilattice.eq(newE, oldE)) { info.set(num, newE); for (Instruction next : getNext(curr, env)) { worklist.add(next); visited[next.num()] = true; } } } } if (forward) i++; else i--; } return info; } private E join(Instruction instruction, ArrayList<E> info, CallEnvironment env) { final Iterable<? extends Instruction> prev = myDfa.isForward() ? instruction.pred(env) : instruction.succ(env); ArrayList<E> prevInfos = new ArrayList<E>(); for (Instruction i : prev) { prevInfos.add(info.get(i.num())); } return mySemilattice.join(prevInfos); } private Iterable<? extends Instruction> getNext(Instruction curr, CallEnvironment env) { return myDfa.isForward() ? curr.succ(env) : curr.pred(env); } }