package pp.s1184725.boppi;

/**
 * This class tracks a variable's properties. It is agnostic of the type system
 * used. The type reference and offset are immutable.
 *
 * @param <T>
 *            the typing class
 * 
 * @author Frank Wibbelink
 */
public class Variable<T> {
	private final T type;
	private final int depth;
	private final int offset;
	private boolean constant;
	private boolean assigned, possiblyAssigned;

	/**
	 * Creates a variable with the given type instance and memory offset.
	 * 
	 * @param type
	 *            the type of the variable
	 * @param depth
	 *            the lexical depth of this variable
	 * @param offset
	 *            the memory offset for this variable
	 */
	public Variable(T type, int depth, int offset) {
		this.type = type;
		this.depth = depth;
		this.offset = offset;
		this.assigned = false;
		this.possiblyAssigned = false;
	}

	/**
	 * Marks this variable assigned.
	 */
	public void assign() {
		assigned = true;
	}

	/**
	 * Gets the lexical depth of this variable instance.
	 * 
	 * @return the depth
	 */
	public int getDepth() {
		return depth;
	}

	/**
	 * Gets the local data offset of this variable instance.
	 * 
	 * @return the offset
	 */
	public int getOffset() {
		return offset;
	}

	/**
	 * Gets the type of this variable instance.
	 * 
	 * @return the type
	 */
	public T getType() {
		return type;
	}

	/**
	 * Returns whether this variable has been assigned.
	 * 
	 * @return whether this variable has been assigned
	 */
	public boolean isAssigned() {
		return assigned;
	}

	/**
	 * Returns whether this variable is a constant.
	 * 
	 * @return whether this variable is a constant
	 */
	public boolean isConstant() {
		return constant;
	}

	/**
	 * Returns whether this variable has been assigned conditionally.
	 * 
	 * @return whether this variable has been assigned conditionally
	 */
	public boolean isPossiblyAssigned() {
		return possiblyAssigned;
	}

	/**
	 * Marks this variable as possibly assigned.
	 */
	public void possiblyAssign() {
		possiblyAssigned = true;
	}

	/**
	 * Sets the const-ness of this variable.
	 * 
	 * @param constant
	 *            whether this variable is a constant
	 */
	public void setConstant(boolean constant) {
		this.constant = constant;
	}

	@Override
	public String toString() {
		return String.format("%s:%X@%d", type.toString(), hashCode(), offset); //$NON-NLS-1$
	}
}
