public class SizzleArray extends SizzleType {
	private SizzleType type;

	/**
	 * Construct a SizzleArray.
	 */
	public SizzleArray() {
	}

	/**
	 * Construct a SizzleArray.
	 * 
	 * @param sizzleType
	 *            A {@link SizzleType} representing the type of the elements in
	 *            this array
	 */
	public SizzleArray(final SizzleType sizzleType) {
		this.type = sizzleType;
	}

	/** {@inheritDoc} */
	@Override
	public boolean assigns(final SizzleType that) {
		// if that is a function, check its return type
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// otherwise, if it's not an array, forget it
		if (!(that instanceof SizzleArray))
			return false;

		// if the element types are wrong, forget it
		if (this.type.assigns(((SizzleArray) that).type))
			return true;

		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		// if that is a function, check its return type
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// otherwise, if it's not an array, forget it
		if (!(that instanceof SizzleArray))
			return false;

		// if the element types are wrong, forget it
		if (this.type.accepts(((SizzleArray) that).type))
			return true;

		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean compares(final SizzleType that) {
		// FIXME: is this needed?
		// if that is an array..
		if (that instanceof SizzleArray)
			// check against the element types of these arrays
			return this.type.compares(((SizzleArray) that).type);

		// otherwise, forget it
		return false;
	}

	/**
	 * Get the element type of this array.
	 * 
	 * @return A {@link SizzleScalar} representing the element type of this
	 *         array
	 */
	public SizzleScalar getType() {
		if (this.type instanceof SizzleScalar)
			return (SizzleScalar) this.type;

		throw new TypeException("this shouldn't happen");
	}

	/**
	 * Set the element type of this array.
	 * 
	 * @param type
	 *            A {@link SizzleScalar} representing the element type of this
	 *            array
	 */
	public void setType(final SizzleScalar type) {
		this.type = type;
	}

	/** {@inheritDoc} */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (this.type == null ? 0 : this.type.hashCode());
		return result;
	}

	/** {@inheritDoc} */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;

		if (!super.equals(obj))
			return false;

		if (this.getClass() != obj.getClass())
			return false;

		final SizzleArray other = (SizzleArray) obj;

		if (this.type == null) {
			if (other.type != null)
				return false;
		} else if (!this.type.equals(other.type))
			return false;

		return true;
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return this.type.toJavaType() + "[]";
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		if (this.type == null)
			return "array of none";
		else
			return "array of " + this.type.toString();
	}
} public class SizzleBool extends SizzleScalar {
	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "boolean";
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "boolean";
	}
} public class SizzleBytes extends SizzleScalar {
	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "byte[]";
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "bytes";
	}
} public class SizzleFloat extends SizzleScalar {
	/** {@inheritDoc} */
	@Override
	public SizzleScalar arithmetics(final SizzleType that) {
		// if that is a function, check its return type
		if (that instanceof SizzleFunction)
			return this.arithmetics(((SizzleFunction) that).getType());

		// if it's a float, the type is float
		if (that instanceof SizzleFloat)
			return new SizzleFloat();

		// same with ints
		if (that instanceof SizzleInt)
			return new SizzleFloat();

		return super.arithmetics(that);
	}

	/** {@inheritDoc} */
	@Override
	public boolean assigns(final SizzleType that) {
		// ints can be assigned to floats
		if (that instanceof SizzleInt)
			return true;

		// otherwise, just check the defaults
		return super.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "double";
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "float";
	}
} public class SizzleFunction extends SizzleType {
	private SizzleType type;
	private SizzleType[] formalParameters;
	private String name;
	private String macro;

	/**
	 * Construct a SizzleFunction.
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the return type
	 * 
	 */
	public SizzleFunction(final SizzleType type) {
		this.type = type;
	}

	/**
	 * Construct a SizzleFunction.
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the return type
	 * 
	 * @param formalParameters
	 *            An array of {@link SizzleType} containing the type of each
	 *            formal parameter
	 * 
	 */
	public SizzleFunction(final SizzleType type, final SizzleType[] formalParameters) {
		this(type);

		this.formalParameters = formalParameters;
	}

	/**
	 * Construct a SizzleFunction.
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the return type
	 * 
	 * @param formalParameters
	 *            An array of {@link SizzleType} containing the type of each
	 *            formal parameter
	 * 
	 * @param macro
	 *            A snippet of Java code that can be used as a macro
	 * 
	 */
	public SizzleFunction(final SizzleType type, final SizzleType[] formalParameters, final String macro) {
		this(type, formalParameters);

		this.macro = macro;
	}

	/**
	 * Construct a SizzleFunction.
	 * 
	 * @param name
	 *            A {@link String} containing the canonical name of the function
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the return type
	 * 
	 * @param formalParameters
	 *            An array of {@link SizzleType} containing the type of each
	 *            formal parameter
	 * 
	 */
	public SizzleFunction(final String name, final SizzleType type, final SizzleType[] formalParameters) {
		this(type, formalParameters);

		this.name = name;
	}

	/** {@inheritDoc} */
	@Override
	public boolean assigns(final SizzleType that) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean compares(final SizzleType that) {
		return this.type.compares(that);
	}

	/** {@inheritDoc} */
	@Override
	public SizzleScalar arithmetics(final SizzleType that) {
		return this.type.arithmetics(that);
	}

	/**
	 * Return the type of the parameter at a given position.
	 * 
	 * @param position
	 *            An int containing the desired position
	 * 
	 * @return A {@link SizzleType} representing the type of that parameter
	 */
	public SizzleType getParameter(final int position) {
		return this.formalParameters[position];
	}

	/**
	 * Returns the number of formal parameters for this function.
	 * 
	 * @return An int containing the number of formal parameters for this
	 *         function
	 * 
	 */
	public int countParameters() {
		return this.formalParameters.length;
	}

	/**
	 * Returns whether this function has a name.
	 * 
	 * @return True iff this function has a name
	 * 
	 */
	public boolean hasName() {
		return this.name != null;
	}

	/**
	 * Returns whether this function has a macro.
	 * 
	 * @return True iff this function has a macro
	 * 
	 */
	public boolean hasMacro() {
		return this.macro != null;
	}

	/**
	 * Get the return type of this function.
	 * 
	 * @return A {@link SizzleType} representing the return type of this
	 *         function
	 * 
	 */
	public SizzleType getType() {
		return this.type;
	}

	/**
	 * Set the return type of this function.
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the return type of this
	 *            function
	 * 
	 */
	public void setType(final SizzleType type) {
		this.type = type;
	}

	/**
	 * Get the types of the formal parameters of this function.
	 * 
	 * @return An array of {@link SizzleType} containing the types of the formal
	 *         arguments of this function
	 * 
	 */
	public SizzleType[] getFormalParameters() {
		return this.formalParameters;
	}

	/**
	 * Set the types of the formal parameters of this function.
	 * 
	 * @param formalArgs
	 *            An array of {@link SizzleType} containing the types of the
	 *            formal arguments of this function
	 * 
	 */
	public void setFormalParameters(final SizzleType[] formalParameters) {
		this.formalParameters = formalParameters;
	}

	public String getName() {
		return this.name;
	}

	public void setName(final String name) {
		this.name = name;
	}

	public String getMacro() {
		return this.macro;
	}

	public void setMacro(final String macro) {
		this.macro = macro;
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "function" + Arrays.toString(this.formalParameters) + ": " + this.type.toString();
	}

	/** {@inheritDoc} */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(this.formalParameters);
		result = prime * result + (this.type == null ? 0 : this.type.hashCode());
		return result;
	}

	/** {@inheritDoc} */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		final SizzleFunction other = (SizzleFunction) obj;
		if (!Arrays.equals(this.formalParameters, other.formalParameters))
			return false;
		if (this.type == null) {
			if (other.type != null)
				return false;
		} else if (!this.type.equals(other.type))
			return false;
		return true;
	}
} public class SizzleInt extends SizzleScalar {
	/** {@inheritDoc} */
	@Override
	public SizzleScalar arithmetics(final SizzleType that) {
		// if that is a function, check its return value
		if (that instanceof SizzleFunction)
			return this.arithmetics(((SizzleFunction) that).getType());
		// otherwise, if it is an int, the type is int
		else if (that instanceof SizzleInt)
			return new SizzleInt();
		// otherwise, if it's a time, the type is time
		else if (that instanceof SizzleTime)
			return new SizzleTime();
		// otherwise if it's a float, the type is float
		else if (that instanceof SizzleFloat)
			return new SizzleFloat();

		// otherwise, check the default
		return super.arithmetics(that);
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "int";
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "long";
	}
} public class SizzleMap extends SizzleType {
	private final SizzleType type;
	private final SizzleType indexType;

	/**
	 * Construct a SizzleMap.
	 */
	public SizzleMap() {
		this(null, null);
	}

	/**
	 * Construct a SizzleMap.
	 * 
	 * @param sizzleType
	 *            A {@link SizzleType} representing the type of the values in
	 *            this map
	 * 
	 * @param sizzleType2
	 *            A {@link SizzleType} representing the type of the indices in
	 *            this map
	 */
	public SizzleMap(final SizzleType sizzleType, final SizzleType sizzleType2) {
		this.type = sizzleType;
		this.indexType = sizzleType2;
	}

	/** {@inheritDoc} */
	@Override
	public boolean assigns(final SizzleType that) {
		// if that is a function, check the return value
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// otherwise, if that is not a map, forget it
		if (!(that instanceof SizzleMap))
			return false;

		// if that index type is not equivalent this this's, forget it
		if (!((SizzleMap) that).indexType.assigns(this.indexType))
			return false;

		// same for the value type
		if (!((SizzleMap) that).type.assigns(this.type))
			return false;

		// ok
		return true;
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		// if that is a function, check the return value
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// otherwise, if that is not a map, forget it
		if (!(that instanceof SizzleMap))
			return false;

		// if that index type is not equivalent this this's, forget it
		if (!((SizzleMap) that).indexType.accepts(this.indexType))
			return false;

		// same for the value type
		if (!((SizzleMap) that).type.accepts(this.type))
			return false;

		// ok
		return true;
	}

	/**
	 * Get the type of the values of this map.
	 * 
	 * @return A {@link SizzleType} representing the type of the values of this
	 *         map
	 */
	public SizzleType getType() {
		return this.type;
	}

	/**
	 * Get the type of the indices of this map.
	 * 
	 * @return A {@link SizzleType} representing the type of the indices of this
	 *         map
	 */
	public SizzleType getIndexType() {
		return this.indexType;
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "map[" + this.indexType + "] of " + this.type;
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "java.util.HashMap<" + this.indexType.toJavaType() + ", " + this.type.toJavaType() + ">";
	}

	/** {@inheritDoc} */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (this.indexType == null ? 0 : this.indexType.hashCode());
		result = prime * result + (this.type == null ? 0 : this.type.hashCode());
		return result;
	}

	/** {@inheritDoc} */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		final SizzleMap other = (SizzleMap) obj;
		if (this.indexType == null) {
			if (other.indexType != null)
				return false;
		} else if (!this.indexType.equals(other.indexType))
			return false;
		if (this.type == null) {
			if (other.type != null)
				return false;
		} else if (!this.type.equals(other.type))
			return false;
		return true;
	}
} public class SizzleName extends SizzleScalar {
	private final SizzleType type;
	private final String id;

	public SizzleName(final SizzleType type, final String id) {
		this.type = type;
		this.id = id;
	}

	public SizzleName(final SizzleType type) {
		this(type, type.toString());
	}

	public SizzleType getType() {
		return this.type;
	}

	@Override
	public String toString() {
		return this.id + " type";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + (this.id == null ? 0 : this.id.hashCode());
		result = prime * result + (this.type == null ? 0 : this.type.hashCode());
		return result;
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		final SizzleName other = (SizzleName) obj;
		if (this.id == null) {
			if (other.id != null)
				return false;
		} else if (!this.id.equals(other.id))
			return false;
		if (this.type == null) {
			if (other.type != null)
				return false;
		} else if (!this.type.equals(other.type))
			return false;
		return true;
	}
} public class SizzleScalar extends SizzleType {
	/** {@inheritDoc} */
	@Override
	public boolean assigns(final SizzleType that) {
		// if that is a function, check the return type
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// otherwise, if it's not a scalar, forget it
		if (!(that instanceof SizzleScalar))
			return false;

		// check that the classes match
		return this.getClass().equals(that.getClass());
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		// if that is a function, check the return type
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// otherwise, if it's not a scalar, forget it
		if (!(that instanceof SizzleScalar))
			return false;

		// check that the classes match
		return true;
	}

	/** {@inheritDoc} */
	@Override
	public boolean compares(final SizzleType that) {
		// if that is a function, check the return type
		if (that instanceof SizzleFunction)
			return this.compares(((SizzleFunction) that).getType());

		// otherwise, check if the types are equivalent one way or the other
		if (this.assigns(that) || that.assigns(this))
			return true;

		// forget it
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean equals(final Object obj) {
		if (obj == null)
			return false;

		return this.getClass().equals(obj.getClass());
	}

	@Override
	public String toString() {
		return "scalar";
	}
} public class SizzleString extends SizzleScalar {
	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "String";
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "string";
	}
} public class SizzleTable extends SizzleType {
	private SizzleType type;
	private List<SizzleScalar> indexTypes;
	private SizzleScalar weightType;

	/**
	 * Construct a SizzleTable.
	 * 
	 * @param types
	 *            A {@link List} of {@link SizzleType} representing the types of
	 *            this SizzleTable
	 */
	public SizzleTable(final SizzleType type) {
		this(type, null, null);
	}

	/**
	 * Construct a SizzleTable.
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the type of this SizzleTable
	 * 
	 * @param subscripts
	 *            A {@link List} of {@link String} containing the names of the
	 *            subscripts of this SizzleTable
	 * 
	 * @param indexTypes
	 *            A {@link List} of {@link SizzleScalar} representing the index
	 *            types of this SizzleTable
	 */
	public SizzleTable(final SizzleType type, final List<SizzleScalar> indexTypes) {
		this(type, indexTypes, null);
	}

	/**
	 * Construct a SizzleTable.
	 * 
	 * @param type
	 *            A {@link SizzleType} representing the type of this SizzleTable
	 * 
	 * @param indexTypes
	 *            A {@link List} of {@link SizzleScalar} representing the index
	 *            types of this SizzleTable
	 * 
	 * @param weightType
	 *            A {@link SizzleScalar} representing the weight type of this
	 *            SizzleTable
	 * 
	 */
	public SizzleTable(final SizzleType type, final List<SizzleScalar> indexTypes, final SizzleScalar weightType) {
		this.type = type;
		this.indexTypes = indexTypes;
		this.weightType = weightType;
	}

	/**
	 * Return the number of indices this table has.
	 * 
	 * @return An int containing the number of types each emit to this table
	 *         will require
	 */
	public int countIndices() {
		if (this.indexTypes == null)
			return 0;
		return this.indexTypes.size();
	}

	/**
	 * Get the type of value to be emitted to this table.
	 * 
	 * @return A {@link SizzleType} representing the type of the value to be
	 *         emitted to this table
	 * 
	 */
	public SizzleType getType() {
		return this.type;
	}

	/**
	 * Get the type of the index at that position.
	 * 
	 * @param position
	 *            An int representing the position
	 * 
	 * @return A {@link SizzleScalar} representing the type of the index at that
	 *         position
	 * 
	 */
	public SizzleScalar getIndex(final int position) {
		return this.indexTypes.get(position);
	}

	/**
	 * Returns whether this table will accept an emit of those types.
	 * 
	 * @param types
	 *            An {@link List} of {@link SizzleType} containing the types to
	 *            be emitted
	 * 
	 * @return True if this table will accept them, false otherwise
	 */
	@Override
	public boolean accepts(final SizzleType type) {
		// check if the types are equivalent
		if (!this.type.assigns(type))
			return false;

		// they were
		return true;
	}

	/**
	 * Returns whether this table will accept an weight of that type.
	 * 
	 * @param that
	 *            An {@link SizzleType} containing the weight type of the emit
	 * 
	 * @return True if this table will accept it, false otherwise
	 */
	public boolean acceptsWeight(final SizzleType that) {
		// if it's null, forget it
		if (this.weightType == null)
			return false;

		// otherwise, check if the types are equivalent
		return this.weightType.assigns(that);
	}

	/**
	 * Set the type of the values to be emitted to this table.
	 * 
	 * @param types
	 *            A {@link SizzleType} representing the type of the values to be
	 *            emitted to this table
	 * 
	 */
	public void setType(final SizzleType type) {
		this.type = type;
	}

	/**
	 * Get the types of the indices into this table.
	 * 
	 * @return A {@link List} of {@link SizzleScalar} representing the types of
	 *         the indices into this table
	 * 
	 */
	public List<SizzleScalar> getIndexTypes() {
		return this.indexTypes;
	}

	/**
	 * Set the types of the indices into this table.
	 * 
	 * @param indexTypes
	 *            A {@link List} of {@link SizzleScalar} representing the types
	 *            of the indices into this table
	 * 
	 */
	public void setIndexTypes(final List<SizzleScalar> indexTypes) {
		this.indexTypes = indexTypes;
	}

	/**
	 * Get the type of the weight of this table.
	 * 
	 * @return A {@link SizzleScalar} representing the type of the weight of
	 *         this table
	 * 
	 */
	public SizzleScalar getWeightType() {
		return this.weightType;
	}

	/**
	 * Set the type of the weight of this table.
	 * 
	 * @param weightType
	 *            A {@link SizzleScalar} representing the type of the weight of
	 *            this table
	 * 
	 */
	public void setWeightType(final SizzleScalar weightType) {
		this.weightType = weightType;
	}

	/** {@inheritDoc} */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + (this.indexTypes == null ? 0 : this.indexTypes.hashCode());
		result = prime * result + (this.type == null ? 0 : this.type.hashCode());
		result = prime * result + (this.weightType == null ? 0 : this.weightType.hashCode());
		return result;
	}

	/** {@inheritDoc} */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		final SizzleTable other = (SizzleTable) obj;
		if (this.indexTypes == null) {
			if (other.indexTypes != null)
				return false;
		} else if (!this.indexTypes.equals(other.indexTypes))
			return false;
		if (this.type == null) {
			if (other.type != null)
				return false;
		} else if (!this.type.equals(other.type))
			return false;
		if (this.weightType == null) {
			if (other.weightType != null)
				return false;
		} else if (!this.weightType.equals(other.weightType))
			return false;
		return true;
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return this.getType() + "/" + this.indexTypes + "/" + this.weightType;
	}
} public class SizzleTime extends SizzleScalar {
	/** {@inheritDoc} */
	@Override
	public SizzleScalar arithmetics(final SizzleType that) {
		// if that is a function, try its return type
		if (that instanceof SizzleFunction)
			return this.arithmetics(((SizzleFunction) that).getType());
		// otherwise, if it is a time or in, the type is time
		else if (that instanceof SizzleTime || that instanceof SizzleInt)
			return new SizzleTime();

		return super.arithmetics(that);
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "time";
	}

	/** {@inheritDoc} */
	@Override
	public String toJavaType() {
		return "long";
	}
} public class SizzleTuple extends SizzleType {
	private final List<SizzleType> members;
	private final Map<String, Integer> names;

	/**
	 * Construct a SizzleTuple.
	 * 
	 * @param members
	 *            A {@link LinkedHashMap} of {@link SizzleType} containing a
	 *            mapping from the names to the types of the members of this
	 *            tuple
	 * 
	 */
	public SizzleTuple(final List<SizzleType> members) {
		this(members, new HashMap<String, Integer>());
	}

	public SizzleTuple(final List<SizzleType> members, final Map<String, Integer> names) {
		this.members = members;
		this.names = names;
	}

	/** {@inheritDoc} */
	@Override
	public boolean assigns(final SizzleType that) {
		if (that instanceof SizzleFunction)
			return this.assigns(((SizzleFunction) that).getType());

		// have to construct it somehow
		if (that instanceof SizzleBytes)
			return true;

		if (!(that instanceof SizzleTuple))
			return false;

		return true;
	}

	/** {@inheritDoc} */
	@Override
	public boolean accepts(final SizzleType that) {
		return this.assigns(that);
	}

	/**
	 * Return the type of the member identified by a given index.
	 * 
	 * @param index
	 *            An int containing the index of the member
	 * 
	 * @return A {@link SizzleType} representing the type of the member
	 * 
	 */
	public SizzleType getMember(final int index) {
		return this.members.get(index);
	}

	/**
	 * Return the type of the member identified by a given name.
	 * 
	 * @param member
	 *            A {@link String} containing the name of the member
	 * 
	 * @return A {@link SizzleType} representing the type of the member
	 * 
	 */
	public SizzleType getMember(final String member) {
		return this.members.get(this.names.get(member));
	}

	public List<SizzleType> getTypes() {
		return this.members;
	}

	@Override
	public String toJavaType() {
		return "Object[]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + (this.members == null ? 0 : this.members.hashCode());
		return result;
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		final SizzleTuple other = (SizzleTuple) obj;
		if (this.members == null) {
			if (other.members != null)
				return false;
		} else if (!this.members.equals(other.members))
			return false;
		return true;
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return "tuple " + this.members.toString();
	}
} public abstract class SizzleType {
	/**
	 * Returns the type that results from an expression of this type and an
	 * expression of that type in an arithmetic expression. (e.g. an int plus a
	 * float results in an expression of type float).
	 * 
	 * @param that
	 *            A SizzleType representing the other expression's type
	 * 
	 * @return A SizzleType representing the type of the resulting expression
	 */
	public SizzleScalar arithmetics(final SizzleType that) {
		// by default, no types are allowed in arithmetic
		throw new TypeException("incorrect type " + this + " for arithmetic with " + that);
	}

	/**
	 * Returns true when an expression of that type may be assigned to a
	 * variable of this type.
	 * 
	 * @return A boolean representing whether an expression of that type may be
	 *         assigned to a variable of this type
	 */
	public boolean assigns(final SizzleType that) {
		// by default no types can be assigned
		return false;
	}

	/**
	 * Returns true when an expression of that type may be used as a formal
	 * parameter of this type.
	 * 
	 * @return A boolean representing whether an expression of that type may be
	 *         used as a formal parameter of this type
	 */
	public boolean accepts(final SizzleType that) {
		// by default no types will be accepted
		return false;
	}

	/**
	 * Returns true when an expression of that type may be compared to an
	 * expression of this type.
	 * 
	 * @return A boolean representing whether an expression of that type may be
	 *         compared to an expression of this type
	 */
	public boolean compares(final SizzleType that) {
		// by default, no types can be compared
		return false;
	}

	/**
	 * Returns a string representation of the Java equivalent of this Sizzle
	 * type.
	 * 
	 * @return A String containing the name of the Java type equivalent to this
	 *         Sizzle type
	 */
	public String toJavaType() {
		throw new TypeException("no java equivalent for type " + this.toString());
	}

	/** {@inheritDoc} */
	@Override
	public boolean equals(final Object that) {
		if (that == null)
			return false;

		// return whether the class names are the same
		return that.getClass().equals(this.getClass());
	}

	/** {@inheritDoc} */
	@Override
	public int hashCode() {
		return 0;
	}

	/** {@inheritDoc} */
	@Override
	public abstract String toString();
}
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import sizzle.parser.ParseException;
import sizzle.parser.SizzleParser;
import sizzle.types.SizzleArray;
import sizzle.types.SizzleBool;
import sizzle.types.SizzleBytes;
import sizzle.types.SizzleFloat;
import sizzle.types.SizzleFunction;
import sizzle.types.SizzleInt;
import sizzle.types.SizzleMap;
import sizzle.types.SizzleName;
import sizzle.types.SizzleScalar;
import sizzle.types.SizzleString;
import sizzle.types.SizzleTable;
import sizzle.types.SizzleTime;
import sizzle.types.SizzleTuple;
import sizzle.types.SizzleType;
package sizzle.compiler;




public class TestTypeCheckingVisitor {
	public static TypeCheckingVisitor typeChecker;

	@BeforeClass
	public static void init() {
		TestTypeCheckingVisitor.typeChecker = new TypeCheckingVisitor();
		// this is a JavaCC wtf, do not remove
		try {
			new SizzleParser(new StringReader(""));
		} catch (final Error e) {
			// eat it
		}
	}

	@Test
	public void testTypeCheckingVisitorSimple() throws IOException, ParseException {
		final String source = "count: table sum of int;\ntotal: table sum of float;\nsum_of_squares: table sum of float;\nx: float = input;\nemit count <- 1;\nemit total <- x;\nemit sum_of_squares <- x * x;\n";

		final SymbolTable st = new SymbolTable();

		SizzleParser.ReInit(new StringReader(source));
		TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

		Assert.assertEquals("count is not an unweighted, unindexed table of ints", new SizzleTable(new SizzleInt()), st.get("count"));