package edu.mit.streamjit.impl.compiler;

import static com.google.common.base.Preconditions.*;
import com.google.common.primitives.Primitives;
import edu.mit.streamjit.impl.compiler.types.NullType;
import edu.mit.streamjit.impl.compiler.types.PrimitiveType;
import edu.mit.streamjit.impl.compiler.types.RegularType;
import edu.mit.streamjit.impl.compiler.types.Type;

/**
 * A constant Value that can be loaded from the constant pool or pushed onto the
 * operand stack as an immediate operand.
 *
 * Constants are immutable and interned by ConstantFactory.  Note that this
 * implies replaceAllUsesWith() is not supported by Constant as it would replace
 * uses in the whole program.
 *
 * The constant types are the primitive types (represented by their wrappers),
 * String, Class<?>, and the null type (represented as a Constant<?> with a null
 * value).
 * @param <T> the type of the constant value (not to be confused with the IR
 * type, which may be primitive)
 * @author Jeffrey Bosboom <jeffreybosboom@gmail.com>
 * @since 4/12/2013
 */
public final class Constant<T> extends Value implements Parented<Module> {
	private final Module parent;
	/**
	 * The constant value.  An instance of Boolean, Byte, Char, Short, Integer,
	 * Long, Float, Double, String or Class, or null.
	 */
	private final T constant;

	Constant(Type type, T constant, Module parent) {
		super(type);
		this.parent = checkNotNull(parent);
		if (type instanceof NullType)
			checkArgument(constant == null, "NullType but not null value");
		else if (type instanceof PrimitiveType)
			checkArgument(Primitives.wrap(((RegularType)type).getKlass().getBackingClass()).equals(constant.getClass()),
					"got a %s (%s), but type is %s", constant, constant.getClass().getName(), type);
		else if (type.equals(parent.types().getType(parent.getKlass(String.class))))
			checkArgument(constant instanceof String,
					"got a %s (%s), but type is %s", constant, constant.getClass().getName(), type);
		else if (type.equals(parent.types().getType(parent.getKlass(Class.class))))
			checkArgument(constant instanceof Class,
					"got a %s (%s), but type is %s", constant, constant.getClass().getName(), type);
		else
			checkArgument(false,
					"bad constant type %s; value was %s (%s)", type, constant, constant.getClass().getName());
		this.constant = constant;
		setName(toString());
	}

	public T getConstant() {
		return constant;
	}

	@Override
	public Module getParent() {
		return parent;
	}

	/**
	 * Throws UnsupportedOperationException.
	 * @param value will be ignored
	 * @throws UnsupportedOperationException always
	 * @deprecated Constants are interned, so RAUW rewrites the whole program,
	 * which is seldom desired.
	 */
	@Deprecated
	@Override
	public void replaceAllUsesWith(Value value) {
		throw new UnsupportedOperationException("constants don't support RAUW");
	}

	@Override
	public String toString() {
		if (constant == null)
			return "null";
		if (constant instanceof String)
			//TODO: escape and quote this string
			return (String)constant;
		if (constant instanceof Class)
			return constant.toString() + ".class";
		return "("+getType().toString()+")"+constant;
	}

	@SuppressWarnings("unchecked")
	<X> Constant<X> as(Class<X> klass) {
		checkArgument(klass.isInstance(getConstant()));
		return (Constant<X>)this;
	}
}

@@ -2358,57 +2358,8 @@
 %09%7D%0A%0A
-%09public T getConstant() %7B%0A%09%09return constant;%0A%09%7D%0A%0A
 %09@Ov
@@ -2415,16 +2415,468 @@
 nt;%0A%09%7D%0A%0A
+%09public T getConstant() %7B%0A%09%09return constant;%0A%09%7D%0A%0A%09/**%0A%09 * Casts this Constant to the given Constant%3CX%3E if this constant really is%0A%09 * of that type.%0A%09 * @param %3CX%3E the constant type to cast to%0A%09 * @param klass the constant type to cast to%0A%09 * @return this constant, cast to the given type%0A%09 */%0A%09@SuppressWarnings(%22unchecked%22)%0A%09public %3CX%3E Constant%3CX%3E as(Class%3CX%3E klass) %7B%0A%09%09checkArgument(klass.isInstance(getConstant()));%0A%09%09return (Constant%3CX%3E)this;%0A%09%7D%0A%0A
 %09/**%0A%09 *
@@ -3568,159 +3568,7 @@
 ;%0A%09%7D
-%0A%0A%09@SuppressWarnings(%22unchecked%22)%0A%09%3CX%3E Constant%3CX%3E as(Class%3CX%3E klass) %7B%0A%09%09checkArgument(klass.isInstance(getConstant()));%0A%09%09return (Constant%3CX%3E)this;%0A%09%7D
 %0A%7D%0A

Make Constant.as public