ValueExplorer.java

package edu.udel.cis.vsl.tass.dynamic.impl.value;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import edu.udel.cis.vsl.tass.dynamic.IF.type.ArrayValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.FunctionValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.PrimitiveValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.RecordValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.ReferenceValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.ValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.VectorValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.value.ValueIF;
import edu.udel.cis.vsl.tass.morph.MorphicVector;
import edu.udel.cis.vsl.tass.symbolic.IF.SymbolicConstantIF;
import edu.udel.cis.vsl.tass.symbolic.IF.SymbolicExpressionIF;
import edu.udel.cis.vsl.tass.symbolic.IF.SymbolicUniverseIF;
import edu.udel.cis.vsl.tass.symbolic.IF.tree.SymbolicConstantExpressionIF;
import edu.udel.cis.vsl.tass.symbolic.IF.tree.TreeExpressionIF;

public class ValueExplorer {

	private SymbolicUniverseIF universe;

	private Set<ValueIF> seenValues = null;

	private Set<ValueTypeIF> seenTypes = null;

	public ValueExplorer(SymbolicUniverseIF universe) {
		this.universe = universe;
	}

	/**
	 * Returns the set of all symbolic constants referenced within the value or
	 * the type of the value.
	 */
	public Collection<SymbolicConstantIF> symbolicConstants(
			Collection<ValueIF> valueSet) {
		Collection<SymbolicConstantIF> result = new LinkedHashSet<SymbolicConstantIF>();
		seenValues = new HashSet<ValueIF>();
		seenTypes = new HashSet<ValueTypeIF>();

		for (ValueIF value : valueSet)
			findSymbolicConstants(value, result);
		seenValues = null;
		seenTypes = null;
		return result;
	}

	private void findSymbolicConstants(ValueIF value,
			Collection<SymbolicConstantIF> set) {
		assert value != null;
		if (seenValues.add(value)) {
			if (value instanceof SymbolicValue) {
				findSymbolicConstants((SymbolicValue) value, set);
			} else if (value instanceof ArrayValue) {
				findSymbolicConstants((ArrayValue) value, set);
			} else if (value instanceof RecordValue) {
				findSymbolicConstants((RecordValue) value, set);
			} else if (value instanceof ReferenceValue) {
				findSymbolicConstants((ReferenceValue) value, set);
			} else if (value instanceof VectorValue) {
				findSymbolicConstants((VectorValue) value, set);
			} else if (value instanceof UndefinedValue) {
			} else {
				throw new RuntimeException("Unknown kind of value: " + value);
			}
			findSymbolicConstants(value.valueType(), set);
		}
	}

	private void findSymbolicConstants(SymbolicValue value,
			Collection<SymbolicConstantIF> set) {
		TreeExpressionIF tree = universe.tree(value.getSymbolicExpression());

		findSymbolicConstants(tree, set);
	}

	private void findSymbolicConstants(TreeExpressionIF tree,
			Collection<SymbolicConstantIF> set) {
		if (tree instanceof SymbolicConstantExpressionIF) {
			set.add(((SymbolicConstantExpressionIF) tree).symbolicConstant());
		} else {
			int numArgs = tree.numArguments();

			for (int i = 0; i < numArgs; i++)
				findSymbolicConstants(tree.argument(i), set);
		}
	}

	private void findSymbolicConstants(ArrayValue array,
			Collection<SymbolicConstantIF> set) {
		SymbolicExpressionIF origin = array.origin();
		TreeExpressionIF originTree = universe.tree(origin);
		MorphicVector<ValueIF> elements = array.elements();

		findSymbolicConstants(originTree, set);
		for (ValueIF element : elements) {
			if (element != null)
				findSymbolicConstants(element, set);
		}
	}

	private void findSymbolicConstants(VectorValue vector,
			Collection<SymbolicConstantIF> set) {
		for (ValueIF element : vector) {
			if (element != null)
				findSymbolicConstants(element, set);
		}

	}

	private void findSymbolicConstants(RecordValue record,
			Collection<SymbolicConstantIF> set) {
		RecordValueTypeIF valueType = record.valueType();
		int numElements = valueType.type().numFields();

		for (int i = 0; i < numElements; i++)
			findSymbolicConstants(record.element(i), set);
	}

	private void findSymbolicConstants(ReferenceValue reference,
			Collection<SymbolicConstantIF> set) {
		if (reference.isNull()) {
		} else {
			ReferenceValue parent = (ReferenceValue) reference.parent();

			if (parent != null)
				findSymbolicConstants(parent, set);
			if (reference instanceof VariableReferenceValue) {
			} else if (reference instanceof ArrayElementReferenceValue) {
				ArrayElementReferenceValue arrayElementReference = (ArrayElementReferenceValue) reference;

				findSymbolicConstants(arrayElementReference.index(), set);
			} else if (reference instanceof RecordElementReferenceValue) {
			} else if (reference instanceof VectorElementReferenceValue) {
			} else {
				throw new RuntimeException("Unknown reference type: "
						+ reference);
			}
		}
	}

	private void findSymbolicConstants(ValueTypeIF type,
			Collection<SymbolicConstantIF> set) {
		if (seenTypes.add(type)) {
			if (type instanceof PrimitiveValueTypeIF) {
			} else if (type instanceof ArrayValueTypeIF) {
				ArrayValueTypeIF arrayType = (ArrayValueTypeIF) type;

				findSymbolicConstants(arrayType.baseType(), set);
				findSymbolicConstants(arrayType.lengthVector(), set);
			} else if (type instanceof VectorValueTypeIF) {
				findSymbolicConstants(((VectorValueTypeIF) type).elementType(),
						set);
			} else if (type instanceof FunctionValueTypeIF) {
				FunctionValueTypeIF functionType = (FunctionValueTypeIF) type;
				int numArgs = functionType.numArguments();

				findSymbolicConstants(functionType.returnType(), set);
				for (int i = 0; i < numArgs; i++) {
					findSymbolicConstants(functionType.argumentType(i), set);
				}
			} else if (type instanceof RecordValueTypeIF) {
				RecordValueTypeIF recordValueType = (RecordValueTypeIF) type;
				int numFields = recordValueType.type().numFields();

				for (int i = 0; i < numFields; i++)
					findSymbolicConstants(recordValueType.fieldType(i), set);
			} else if (type instanceof ReferenceValueTypeIF) {
				ValueTypeIF baseType = ((ReferenceValueTypeIF) type).baseType();

				if (baseType != null)
					findSymbolicConstants(baseType, set);
			} else {
				throw new RuntimeException("Unknown type: " + type);
			}
		}
	}

}