package gpinterpreter.stack;
import gpinterpreter.Instruction;
import gpinterpreter.Interpreter;
import gpinterpreter.vector.VecInstruction;
import gpinterpreter.vector.VecInterpreter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import primitives.cluster.ClusterHead;
import primitives.cluster.ClusterNode;
import primitives.cluster.ClusterUtils;
import primitives.cluster.IClusterLevel;
import primitives.util.UndefinedIndexException;
/**
*
* @author mat
*/
public class StackInterpreter extends Interpreter<StackInstruction> {
private Stack<IClusterLevel> stack;
private HashSet<Integer> seen;
public StackInterpreter(List<StackInstruction> p, ClusterHead tree) {
super(p, tree);
stack = new Stack<IClusterLevel>();
seen = new HashSet<Integer>();
}
private int wastage=0;
public int getWastage(){
return wastage;
}
public void execute(StackInstruction nextInstruction) {
IClusterLevel c1, c2;
int op = nextInstruction.getOperand();
switch (nextInstruction.getType()) {
// PUSH n
// where n is a base cluster ID
// stack = [clusternode $n]:stack
case PUSH:
//don't do anything if the operand has already been put on the stack at some point.
if(seen.contains(op)){
wastage++;
break;
}
if (op == 0) {
Logger.getLogger(StackInterpreter.class.getName()).log(Level.INFO, "Attempt to merge with head of cluster tree aborted");
break;
}
try {
c1 = ClusterUtils.lookupIndexInTree(op, tree);
} catch (UndefinedIndexException e) {
Logger.getLogger(StackInterpreter.class.getName()).log(Level.WARNING, "Operand of PUSH not found", e);
c1 = e.getDefaultNode();
}
seen.add(op);
stack.push(c1);
break;
case CLUSTER:
//take the two elements from the stack
//they are now in a cluster.
//push that cluster back onto the stack.
if (stack.size() < 2) {
//can't cluster less than 2 items. treat this as a PUSH operand
//don't do anything if the operand's been seen.
if(seen.contains(op)){
wastage++;
break;
}
try {
c1 = ClusterUtils.lookupIndexInTree(op, tree);
} catch (UndefinedIndexException e) {
Logger.getLogger(StackInterpreter.class.getName()).log(Level.WARNING, "Operand of PUSH not found", e);
c1 = e.getDefaultNode();
}
stack.push(c1);
seen.add(op);
break;
}
c1 = stack.pop();
c2 = stack.pop();
if (c1.equals(c2)) {
break;
}
ClusterNode parent1, parent2;
parent1 = ClusterUtils.findParent(c1, tree);
parent2 = ClusterUtils.findParent(c2, tree);
if(parent1 == parent2 && parent1 != tree){
break;
}
ClusterNode newParent = ClusterUtils.addEmptyIgnoreID(tree, tree);
newParent.addChild(c1);
newParent.addChild(c2);
ClusterUtils.move(c1, parent1, newParent, tree, false);
ClusterUtils.move(c2, parent2, newParent, tree, false);
Logger.getLogger(StackInterpreter.class.getName()).log(Level.FINEST, String.format("CLUSTER (%s) (%s)", c1, c2));
stack.push(newParent);
break;
case NOP:
default:
break;
}
}
}