/*
* xtc - The eXTensible Compiler
* Copyright (C) 2005-2007 Robert Grimm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import xtc.Constants;
import xtc.tree.Attribute;
import xtc.tree.Location;
import xtc.tree.Locatable;
import xtc.tree.Node;
import xtc.tree.Visitor;
import xtc.util.Runtime;
/**
* The superclass of all types.
*
* <p />The class hierarchy for types distinguishes basic from wrapped
* types, with wrapped types providing additional information for
* basic types. For each basic type, this class provides
* <code>is<i>Name</i>()</code> and <code>to<i>Name</i>()</code>
* methods to replace instanceof tests and casts, respectively. For
* each wrapped type, this class additionally provides a
* <code>has<i>Name</i>()</code> method, which identifies instances of
* the wrapped type even if they are wrapped inside another (wrapped)
* type. In other words, invocations of <code>has<i>Name</i>()</code>
* are forwarded across wrapped types while invocations of
* <code>is<i>Name</i>()</code> only apply to the outermost type
* object. For wrapped types, invocations of
* <code>to<i>Name</i>()</code> are also forwarded across (other)
* wrapped types.
*
* <p />As an example, consider an int type wrapped in an annotated
* type and an alias type:
* <pre>
* Type i = NumberT.INT;
* Type j = new AnnotatedT(i);
* Type k = new AliasT("alias", j);
* </pre>
* Then the following method invocations have the following results:
* <pre>
* k.isAlias() ⇒ <i>true</i>
* k.hasAlias() ⇒ <i>true</i>
* k.toAlias() ⇒ <i>k</i>
*
* k.isAnnotated() ⇒ <i>false</i>
* k.hasAnnotated() ⇒ <i>true</i>
* k.toAnnotated() ⇒ <i>j</i>
*
* k.isInteger() ⇒ <i>false</i>
* k.toInteger() ⇒ <i>error</i>
* </pre>
* The {@link #resolve()} method can be used to strip any wrapped
* types:
* <pre>
* Type r = k.resolve();
*
* r.isAlias() ⇒ <i>false</i>
* r.isAnnotated() ⇒ <i>false</i>
* r.isInteger() ⇒ <i>true</i>
* r.toInteger() ⇒ <i>i</i>
* </pre>
*
* <p />The {@link Tag} enumeration also identifies particular types.
* A type's tag can be accessed through {@link #tag()}, which is
* forwarded across wrapped types, and through {@link #wtag()}, which
* is <em>not</em> forwarded across wrapped types. As a result,
* <code>tag()</code> identifies basic types independent of whether
* they are wrapped or not, while <code>wtag()</code> always
* identifies the outermost type:
* <pre>
* k.tag() ⇒ <i>Tag.INTEGER</i>
* k.wtag() ⇒ <i>Tag.ALIAS</i>
*
* i.tag() ⇒ <i>Tag.INTEGER</i>
* i.tag() ⇒ <i>Tag.INTEGER</i>
* </pre>
*
* <p />Each type can have one or more of the following
* annotations:<ul>
*
* <li>Its source location represented as a {@link Location}.</li>
*
* <li>Its source language represented as a {@link Language} tag.</li>
*
* <li>Its scope represented as a {@link String}.</li>
*
* <li>Its constant value represented as a {@link Constant}.</li>
*
* <li>Its memory shape represented as a {@link Reference}. Only
* lvalues can have a shape.</li>
*
* <li>Its attributes represented as a list of {@link Attribute}
* values.</li>
*
* </ul>
* For each kind of annotation, this class defines tester, getter, and
* setter methods. The tester and getter methods come in two
* versions, one that is forwarded across wrapped types and one that
* uses a boolean parameter to control forwarding.
*
* @author Robert Grimm
* @version $Revision: 1.112 $
*/
public abstract class Type extends Node {
/**
* A type's tag. Only leaves of the type hierarchy have their own
* tags. A type's tag is accessed through {@link #tag()} and {@link
* #wtag()}.
*/
public static enum Tag {
/** A boolean. */
BOOLEAN,
/** An array. */
ARRAY,
/** A class. */
CLASS,
/** An interface. */
INTERFACE,
/** A function. */
FUNCTION,
/** A method. */
METHOD,
/** A named parameter. */
NAMED_PARAMETER,
/** An internal parameter. */
INTERNAL_PARAMETER,
/** A wildcard. */
WILDCARD,
/** A pointer. */
POINTER,
/** A struct. */
STRUCT,
/** A tuple. */
TUPLE,
/** A union. */
UNION,
/** A variant. */
VARIANT,
/** An error. */
ERROR,
/** An internal type. */
INTERNAL,
/** A label. */
LABEL,
/** A float. */
FLOAT,
/** An integer. */
INTEGER,
/** A package. */
PACKAGE,
/** A unit type. */
UNIT,
/** A void type. */
VOID,
/** An alias. */
ALIAS,
/** An annotated type. */
ANNOTATED,
/** An enumerator. */
ENUMERATOR,
/** An enum. */
ENUM,
/** An instantiated type. */
INSTANTIATED,
/** A parameterized type. */
PARAMETERIZED,
/** A variable. */
VARIABLE
}
// =========================================================================
/** The flag for whether this type is sealed. */
boolean sealed;
// This type's location is implicit in the Node.
/** This type's language. */
Language language;
/** This type's scope. */
String scope;
/** This type's constant value. */
Constant constant;
/** This type's shape. */
Reference shape;
/** This type's attributes. */
List<Attribute> attributes;
// =========================================================================
/**
* Create a new type. The newly created type does not have any
* annotations and is not sealed.
*/
public Type() { /* Nothing to do. */ }
/**
* Create a new type. The newly created type is not sealed. Its
* annotations are a copy of the specified template's annotations.
*
* @param template The type whose annotations to copy.
*/
public Type(Type template) {
if (null == template) return;
setLocation(template);
this.language = template.language;
this.scope = template.scope;
this.constant = template.constant;
this.shape = template.shape;
if (null != template.attributes) {
this.attributes = new ArrayList<Attribute>(template.attributes);
}
}
// =========================================================================
/**
* Create a deep copy of this type. The resulting type is not
* sealed.
*
* @return A deep copy of this type.
*/
public abstract Type copy();
// =========================================================================
/**
* Determine whether this type is sealed.
*
* @return <code>true</code> if this type is sealed.
*/
public boolean isSealed() {
return sealed;
}
/**
* Seal this type. Subclasses that reference other types must
* override this method and, if the instance is not sealed, first
* invoke the superclass' version and then seal all referenced
* types. For example, if a subclass references a single type
* <code>type</code>, the corresponding overridden method reads:
* <pre>
* public Type seal() {
* if (! isSealed()) {
* super.seal();
* type.seal();
* }
* return this;
* }
* </pre>
* First testing whether a type is sealed and then invoking the
* superclass' <code>seal()</code> method avoids infinite recursions
* for mutually recursive types.
*
* @see #seal(List)
*
* @return This type.
*/
public Type seal() {
sealed = true;
return this;
}
/**
* Ensure that this type is not sealed. This method must be called
* by any subclass before modifying its internal state.
*
* @throws IllegalStateException Signals that this type is sealed.
*/
protected void checkNotSealed() {
if (sealed) {
throw new IllegalStateException("Type " + this + " is sealed");
}
}
// =========================================================================
/**
* Annotate this type. If this type is not an annotated type or a
* sealed annotated type, this method wraps this type in a new
* {@link AnnotatedT}.
*
* @return The annotated type.
*/
public Type annotate() {
return isAnnotated() && (! isSealed()) ? this : new AnnotatedT(this);
}
/**
* Deannotate this type. This method strips away any {@link
* AnnotatedT} from this type.
*
* @return The deannotated type.
*/
public Type deannotate() {
Type t = this;
while (t.isAnnotated()) t = t.toAnnotated().getType();
return t;
}
// =========================================================================
public Object setProperty(String name, Object value) {
checkNotSealed();
return super.setProperty(name, value);
}
public Object removeProperty(String name) {
checkNotSealed();
return super.removeProperty(name);
}
public Set<String> properties() {
if (sealed) {
return Collections.unmodifiableSet(super.properties());
} else {
return properties();
}
}
// =========================================================================
/**
* Determine whether this type or any wrapped type has a location.
* Calling this method on type <code>t</code> is equivalent to:
* <pre>
* t.hasLocation(true)
* </pre>
*
* @see #hasLocation(boolean)
*
* @return <code>true</code> if this type or any wrapped type has a
* location.
*/
public boolean hasLocation() {
return hasLocation(true);
}
/**
* Determine whether this type or any wrapped type has a location.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has a
* location.
*/
public boolean hasLocation(boolean forward) {
return super.hasLocation();
}
/**
* Get this type's or any wrapped type's location. Calling this
* method on type <code>t</code> is equivalent to:
* <pre>
* t.getLocation(true)
* </pre>
*
* @see #getLocation(boolean)
*
* @return The location or <code>null</code> if this type or any
* wrapped type does not have a location.
*/
public Location getLocation() {
return getLocation(true);
}
/**
* Get this type's or any wrapped type's location.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return The location or <code>null</code> if this type or any
* wrapped type does not have a location.
*/
public Location getLocation(boolean forward) {
return super.getLocation();
}
/**
* Set this type's location.
*
* @param location The location.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type locate(Location location) {
setLocation(location);
return this;
}
/**
* Set this type's location.
*
* @param locatable The locatable.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type locate(Locatable locatable) {
setLocation(locatable);
return this;
}
public void setLocation(Location location) {
checkNotSealed();
super.setLocation(location);
}
public void setLocation(Locatable locatable) {
checkNotSealed();
super.setLocation(locatable);
}
// =========================================================================
/**
* Determine whether this type or any wrapped type has a language.
* Calling this method on type <code>t</code> is equivalent to:
* <pre>
* t.hasLanguage(true)
* </pre>
*
* @see #hasLanguage(boolean)
*
* @return <code>true</code> if this type or any wrapped type has a
* language.
*/
public boolean hasLanguage() {
return hasLanguage(true);
}
/**
* Determine whether this type or any wrapped type has a language.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has a
* language.
*/
public boolean hasLanguage(boolean forward) {
return null != language;
}
/**
* Get this type's or any wrapped type's language. Calling this
* method on type <code>t</code> is equivalent to:
* <pre>
* t.getLanguage(true)
* </pre>
*
* @see #getLanguage(boolean)
*
* @return The language or <code>null</code> if this type or any
* wrapped type does not have a language.
*/
public Language getLanguage() {
return getLanguage(true);
}
/**
* Get this type's or any wrapped type's language.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return The language or <code>null</code> if this type or any
* wrapped type does not have a language.
*/
public Language getLanguage(boolean forward) {
return language;
}
/**
* Set this type's language.
*
* @param language The language.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type language(Language language) {
checkNotSealed();
this.language = language;
return this;
}
// =========================================================================
/**
* Determine whether this type or any wrapped type has a scope.
* Calling this method on type <code>t</code> is equivalent to:
* <pre>
* t.hasScope(true)
* </pre>
*
* @see #hasScope(boolean)
*
* @return <code>true</code> if this type or any wrapped type has a
* scope.
*/
public boolean hasScope() {
return hasScope(true);
}
/**
* Determine whether this type or any wrapped type has a scope.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has a
* scope.
*/
public boolean hasScope(boolean forward) {
return null != scope;
}
/**
* Get this type's or any wrapped type's scope. Calling this method
* on type <code>t</code> is equivalent to:
* <pre>
* t.getScope(true)
* </pre>
*
* @see #getScope(boolean)
*
* @return The scope or <code>null</code> if this type or any
* wrapped type does not have a scope.
*/
public String getScope() {
return getScope(true);
}
/**
* Get this type's or any wrapped type's scope.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return The scope or <code>null</code> if this type or any
* wrapped type does not have a scope.
*/
public String getScope(boolean forward) {
return scope;
}
/**
* Set this type's scope.
*
* @param scope The scope.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type scope(String scope) {
checkNotSealed();
this.scope = scope;
return this;
}
// =========================================================================
/**
* Determine whether this type or any wrapped type has a constant.
* Calling this method on type <code>t</code> is equivalent to:
* <pre>
* t.hasConstant(true)
* </pre>
*
* @see #hasConstant(boolean)
*
* @return <code>true</code> if this type has a constant.
*/
public boolean hasConstant() {
return hasConstant(true);
}
/**
* Determine whether this type or any wrapped type has a constant.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has a
* constant.
*/
public boolean hasConstant(boolean forward) {
return null != constant;
}
/**
* Get this type's or any wrapped type's constant. Calling this
* method on type <code>t</code> is equivalent to:
* <pre>
* t.getConstant(true)
* </pre>
*
* @see #getConstant(boolean)
*
* @return The constant or <code>null</code> if this type or any
* wrapped type does not have a constant.
*/
public Constant getConstant() {
return getConstant(true);
}
/**
* Get this type's or any wrapped type's constant.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return The constant or <code>null</code> if this type or any
* wrapped type does not have a constant.
*/
public Constant getConstant(boolean forward) {
return constant;
}
/**
* Set this type's constant.
*
* @see #constant(Object)
*
* @param value The value.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type constant(boolean value) {
return constant(value ? BigInteger.ONE : BigInteger.ZERO);
}
/**
* Set this type's constant.
*
* @param value The value.
* @return This type.
* @throws IllegalArgumentException Signals an invalid value.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type constant(Object value) {
checkNotSealed();
this.constant = new Constant(value);
return this;
}
// =========================================================================
/**
* Determine whether this type or any wrapped type has a shape.
* Calling this method on type <code>t</code> is equivalent to:
* <pre>
* t.hasShape(true)
* </pre>
*
* @see #hasShape(boolean)
*
* @return <code>true</code> if this type or any wrapped type has a
* shape.
*/
public boolean hasShape() {
return hasShape(true);
}
/**
* Determine whether this type or any wrapped type has a shape.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has a
* shape.
*/
public boolean hasShape(boolean forward) {
return null != shape;
}
/**
* Get this type's or any wrapped type's shape. Calling this method
* on type <code>t</code> is equivalent to:
* <pre>
* t.getShape(true)
* </pre>
*
* @see #getShape(boolean)
*
* @return The shape or <code>null</code> if this type or any
* wrapped type does not have a shape.
*/
public Reference getShape() {
return getShape(true);
}
/**
* Get this type's or any wrapped type's shape.
*
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return The shape or <code>null</code> if this type or any
* wrapped type does not have a shape.
*/
public Reference getShape(boolean forward) {
return shape;
}
/**
* Set this type's shape to a variable reference with the specified
* name.
*
* @see StaticReference
* @see DynamicReference
* @see #shape(Reference)
*
* @param isStatic The flag for whether the variable is static.
* @param name The variable name.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type shape(boolean isStatic, String name) {
if (isStatic) {
return shape(new StaticReference(name, resolve()));
} else {
return shape(new DynamicReference(name, resolve()));
}
}
/**
* Set this type's shape.
*
* @param shape The shape represented as a reference.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type shape(Reference shape) {
checkNotSealed();
this.shape = shape;
return this;
}
// =========================================================================
/**
* Determine whether this type has any attributes. Note that this
* method does <em>not</em> check any wrapped types.
*
* @return <code>true</code> if this type has any attributes.
*/
public boolean hasAttributes() {
return ((null != attributes) && (! attributes.isEmpty()));
}
/**
* Get this type's attributes.
*
* @return This type's attributes.
*/
public List<Attribute> attributes() {
if (null == attributes) {
return Collections.emptyList();
} else if (sealed) {
return Collections.unmodifiableList(attributes);
} else {
return attributes;
}
}
// =========================================================================
/**
* Determine whether this type or any wrapped type has the specified
* attribute. Calling this method on type <code>t</code> is
* equivalent to:
* <pre>
* t.hasAttribute(att, true)
* </pre>
*
* @see #hasAttribute(Attribute,boolean)
*
* @param att The attribute.
* @return <code>true</code> if this type or any wrapped type has
* the attribute.
*/
public boolean hasAttribute(Attribute att) {
return hasAttribute(att, true);
}
/**
* Determine whether this type or any wrapped type has the specified
* attribute.
*
* @param att The attribute.
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has
* the attribute.
*/
public boolean hasAttribute(Attribute att, boolean forward) {
return ((null != attributes) && attributes.contains(att));
}
/**
* Determine whether this type has an attribute with the specified
* name. Calling this method on type <code>t</code> is equivalent
* to:
* <pre>
* null != t.getAttribute(name, true)
* </pre>
*
* @see #getAttribute(String,boolean)
*
* @param name The name.
* @return <code>true</code> if this type or any wrapped type has
* an attribute with the specified name.
*/
public boolean hasAttribute(String name) {
return null != getAttribute(name);
}
/**
* Determine whether this type has an attribute with the specified
* name. Calling this method on type <code>t</code> is equivalent
* to:
* <pre>
* null != t.getAttribute(name, forward)
* </pre>
*
* @link #getAttribute(String,boolean)
*
* @param name The name.
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return <code>true</code> if this type or any wrapped type has
* an attribute with the specified name.
*/
public boolean hasAttribute(String name, boolean forward) {
return null != getAttribute(name, forward);
}
/**
* Get the attribute with the specified name. Calling this method
* on type <code>t</code> is equivalent to:
* <pre>
* t.getAttribute(name, true)
* </pre>
*
* @see #getAttribute(String,boolean)
*
* @param name The name.
* @return An attribute with that name or <code>null</code> if this
* type or any wrapped type does not have such an attribute.
*/
public Attribute getAttribute(String name) {
return getAttribute(name, true);
}
/**
* Get the attribute with the specified name.
*
* @param name The name.
* @param forward The flag for whether to forward this method across
* wrapped types.
* @return An attribute with the name or <code>null</code> if this
* or any wrapped type does not have such an attribute.
*/
public Attribute getAttribute(String name, boolean forward) {
return Attribute.get(name, attributes);
}
// =========================================================================
/**
* Add the specified attribute. This method adds the specified
* attribute to this type's list of attributes — without
* checking whether the type already has that attribute. For almost
* all applications of attributes, it is preferable to use {@link
* #attribute(Attribute)}, {@link #attribute(List)}, or {@link
* #attribute(Type)}.
*
* @param att The new attribute.
* @throws IllegalStateException Signals that this type is sealed.
*/
public void addAttribute(Attribute att) {
checkNotSealed();
if (null == attributes) attributes = new ArrayList<Attribute>();
attributes.add(att);
}
/**
* Remove the specified attribute. Note that this method does
* <em>not</em> remove the attribute from any wrapped types.
*
* @param att The attribute.
* @return <code>true</code> if this type had the specified
* attribute.
* @throws IllegalStateException Signals that this type is sealed.
*/
public boolean removeAttribute(Attribute att) {
checkNotSealed();
return null != attributes ? attributes.remove(att) : false;
}
// =========================================================================
/**
* Annotate this type with the specified attribute. If this type or
* any wrapped type does not have the specified attribute, this
* method adds the attribute to this type's list of attributes.
*
* @param att The attribute.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type attribute(Attribute att) {
if (! hasAttribute(att)) {
addAttribute(att);
}
return this;
}
/**
* Annotate this type with the specified attributes.
*
* @see #attribute(Attribute)
*
* @param attributes The attributes.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type attribute(List<Attribute> attributes) {
for (Attribute att : attributes) {
if (! hasAttribute(att)) addAttribute(att);
}
return this;
}
/**
* Annotate this type with the specified type's attributes.
*
* @param template The type whose annotations to copy.
* @return This type.
* @throws IllegalStateException Signals that this type is sealed.
*/
public Type attribute(Type template) {
do {
// If the template has any attributes, copy them.
if (template.hasAttributes()) {
for (Attribute att : template.attributes()) {
if (! hasAttribute(att)) addAttribute(att);
}
}
// If the template is a wrapped type, continue with the wrapped type.
template = template.isWrapped() ? template.toWrapped().getType() : null;
} while (null != template);
// Done.
return this;
}
// =========================================================================
/**
* Mark the specified node as having this type. This method sets
* the node's {@link Constants#TYPE type property} to this type.
*
* @param node The node.
* @throws IllegalArgumentException Signals that the node already
* has a type property.
*/
public void mark(Node node) {
if (node.hasProperty(Constants.TYPE)) {
throw new IllegalArgumentException("Node " + node + " already has type");
} else {
node.setProperty(Constants.TYPE, this);
}
}
// =========================================================================
/**
* Determine whether this type has the specified tag. Invocations
* to this method are forwarded across wrapped types. Calling this
* method on type <code>t</code> is equivalent to:
* <pre>
* tag == t.tag()
* </pre>
*
* @see #tag()
*
* @param tag The tag.
* @return <code>true</code> if this type has the specified tag.
*/
public boolean hasTag(Tag tag) {
return tag == tag();
}
/**
* Get this type's tag. Invocations to this method are forwarded
* across wrapped types.
*
* @see #wtag()
*
* @return This type's tag.
*/
public abstract Tag tag();
/**
* Determine whether this wrapped type has the specified tag.
* Invocations to this method are <em>not</em> forwarded across
* wrapped types. Calling this method on type <code>t</code> is
* equivalent to:
* <pre>
* tag == wtag()
* </pre>
*
* @see #wtag()
*
* @param tag The tag.
* @return <code>true</code> if this wrapped type has the specified
* tag.
*/
public boolean hasWTag(Tag tag) {
return tag == wtag();
}
/**
* Get this wrapped type's tag. Invocations to this method are
* <em>not</em> forwarded across wrapped types.
*
* @see #tag()
*
* @return This wrapped type's tag.
*/
public Tag wtag() {
return tag();
}
// =========================================================================
/**
* Determine whether this type is an error.
*
* @link #hasError()
*
* @return <code>true</code> if this type is internal.
*/
public boolean isError() {
return false;
}
/**
* Determine whether this type has an error. This method identifies
* the {@link ErrorT error type} even if it is wrapped. Calling this
* method on type <code>t</code> is equivalent to:
* <pre>
* Type.Tag.Error == tag()
* </pre>
*
* @see #tag()
*
* @return <code>true</code> if this type has an error.
*/
public boolean hasError() {
return Tag.ERROR == tag();
}
// =========================================================================
/**
* Determine whether this type is a type parameter.
*
* @return <code>true</code> if this type is a parameter.
*/
public boolean isParameter() {
return false;
}
/**
* Get this type as a type parameter.
*
* @return This type as a parameter.
* @throws ClassCastException Signals that this type is not a
* parameter.
*/
public Parameter toParameter() {
throw new ClassCastException("Not a parameter " + this);
}
/**
* Determine whether this type is a named parameter.
*
* @return <code>true</code> if this type is a named parameter.
*/
public boolean isNamedParameter() {
return false;
}
/**
* Get this type as a named parameter.
*
* @return This type as a named parameter.
* @throws ClassCastException Signals that this type is not a
* named parameter.
*/
public NamedParameter toNamedParameter() {
throw new ClassCastException("Not a named parameter " + this);
}
/**
* Determine whether this type is an internal parameter.
*
* @return <code>true</code> if this type is an internal parameter.
*/
public boolean isInternalParameter() {
return false;
}
/**
* Get this type as an internal parameter.
*
* @return This type as an internal parameter.
* @throws ClassCastException Signals that this type is not an
* internal parameter.
*/
public InternalParameter toInternalParameter() {
throw new ClassCastException("Not an internal parameter " + this);
}
/**
* Determine whether this type is a wildcard.
*
* @return <code>true</code> if this type is a wildcard.
*/
public boolean isWildcard() {
return false;
}
/**
* Get this type as a wildcard.
*
* @return This type as a wildcard.
* @throws ClassCastException Signals that this type is not a
* wildcard.
*/
public Wildcard toWildcard() {
throw new ClassCastException("Not a wildcard " + this);
}
// =========================================================================
/**
* Determine whether this type is void.
*
* @return <code>true</code> if this type is void.
*/
public boolean isVoid() {
return false;
}
/**
* Get this type as a void type.
*
* @return This type as a void type.
* @throws ClassCastException Signals that this type is not a void
* type.
*/
public VoidT toVoid() {
throw new ClassCastException("Not a void " + this);
}
/**
* Determine whether this type is the unit type.
*
* @return <code>true</code> if this type is the unit type.
*/
public boolean isUnit() {
return false;
}
/**
* Get this type as a unit type.
*
* @return This type as a unit type.
* @throws ClassCastException Signals that this type is not a unit
* type.
*/
public UnitT toUnit() {
throw new ClassCastException("Not a unit " + this);
}
/**
* Determine whether this type is a boolean.
*
* @return <code>true</code> if this type is a boolean.
*/
public boolean isBoolean() {
return false;
}
/**
* Get this type as a boolean.
*
* @return This type as a boolean.
* @throws ClassCastException Signals that this type is a not a
* boolean.
*/
public BooleanT toBoolean() {
throw new ClassCastException("Not a boolean " + this);
}
/**
* Determine whether this type is a number.
*
* @return <code>true</code> if this type is a number.
*/
public boolean isNumber() {
return false;
}
/**
* Get this type as a number.
*
* @return This type as a number.
* @throws ClassCastException Signals that this type is not a
* number.
*/
public NumberT toNumber() {
throw new ClassCastException("Not a number " + this);
}
/**
* Determine whether this type is an integer.
*
* @return <code>true</code> if this type is an integer.
*/
public boolean isInteger() {
return false;
}
/**
* Get this type as an integer.
*
* @return This type as an integer.
* @throws ClassCastException Signals that this type is not an
* integer.
*/
public IntegerT toInteger() {
throw new ClassCastException("Not an integer " + this);
}
/**
* Determine whether this type is a float.
*
* @return <code>true</code> if this type is a float.
*/
public boolean isFloat() {
return false;
}
/**
* Get this type as a float.
*
* @return This type as a float.
* @throws ClassCastException Signals that this type is not a
* float.
*/
public FloatT toFloat() {
throw new ClassCastException("Not a float " + this);
}
/**
* Determine whether this type is internal.
*
* @return <code>true</code> if this type is internal.
*/
public boolean isInternal() {
return false;
}
/**
* Get this type as an internal type.
*
* @return This type as an internal type.
* @throws ClassCastException Signals that this type is not an
* internal type.
*/
public InternalT toInternal() {
throw new ClassCastException("Not an internal type " + this);
}
/**
* Determine whether this type is a label.
*
* @return <code>true</code> if this type is a label.
*/
public boolean isLabel() {
return false;
}
/**
* Get this type as a label.
*
* @return This type as a label.
* @throws ClassCastException Signals that this type is not a
* label.
*/
public LabelT toLabel() {
throw new ClassCastException("Not a label " + this);
}
/**
* Determine whether this type is a package.
*
* @return <code>true</code> if this type is a package.
*/
public boolean isPackage() {
return false;
}
/**
* Get this type as a package.
*
* @return This type as a package.
* @throws ClassCastException Signals that this type is not a
* package.
*/
public PackageT toPackage() {
throw new ClassCastException("Not a package " + this);
}
/**
* Determine whether this type is derived.
*
* @return <code>true</code> if this type is derived.
*/
public boolean isDerived() {
return false;
}
/**
* Determine whether this type is a pointer.
*
* @return <code>true</code> if this type is a pointer.
*/
public boolean isPointer() {
return false;
}
/**
* Get this type as a pointer.
*
* @return This type as a pointer.
* @throws ClassCastException Signals that this type is not a
* pointer.
*/
public PointerT toPointer() {
throw new ClassCastException("Not a pointer " + this);
}
/**
* Determine whether this type is an array.
*
* @return <code>true</code> if this type is an array.
*/
public boolean isArray() {
return false;
}
/**
* Get this type as an array.
*
* @return This type as an array.
* @throws ClassCastException Signals that this type is not an
* array.
*/
public ArrayT toArray() {
throw new ClassCastException("Not an array " + this);
}
/**
* Determine whether this type contains a struct or union.
*
* @return <code>true</code> if this type contains a struct or
* union.
*/
public boolean hasStructOrUnion() {
switch (tag()) {
case STRUCT:
case UNION:
return true;
default:
return false;
}
}
/**
* Get this type as a struct or union.
*
* @return This type as a struct or union.
* @throws ClassCastException Signals that this type is not a struct
* or union.
*/
public StructOrUnionT toStructOrUnion() {
throw new ClassCastException("Not a struct or union " + this);
}
/**
* Determine whether this type is a struct.
*
* @return <code>true</code> if this type is a struct.
*/
public boolean isStruct() {
return false;
}
/**
* Get this type as a struct.
*
* @return This type as a struct.
* @throws ClassCastException Signas that this type is not a
* struct.
*/
public StructT toStruct() {
throw new ClassCastException("Not a struct " + this);
}
/**
* Determine whether this type is a union.
*
* @return <code>true</code> if this type is a union.
*/
public boolean isUnion() {
return false;
}
/**
* Get this type as a union.
*
* @return This type as a union.
* @throws ClassCastException Signals that this type is not a
* union.
*/
public UnionT toUnion() {
throw new ClassCastException("Not a union " + this);
}
/**
* Determine whether this type is a function.
*
* @return <code>true</code> if this type is a function.
*/
public boolean isFunction() {
return false;
}
/**
* Get this type as a function.
*
* @return This type has a function.
* @throws ClassCastException Signals that this type is not a
* function.
*/
public FunctionT toFunction() {
throw new ClassCastException("Not a function " + this);
}
/**
* Determine whether this type is a method.
*
* @return <code>true</code> if this type is a method.
*/
public boolean isMethod() {
return false;
}
/**
* Get this type as a method.
*
* @return This type as a method.
* @throws ClassCastException Signals that this type is not a
* method.
*/
public MethodT toMethod() {
throw new ClassCastException("Not a method " + this);
}
/**
* Determine whether this type is a class.
*
* @return <code>true</code> if this type is a class.
*/
public boolean isClass() {
return false;
}
/**
* Get this type as a class.
*
* @return This type as a class.
* @throws ClassCastException Signals that this type is not a class.
*/
public ClassT toClass() {
throw new ClassCastException("Not a class " + this);
}
/**
* Determine whether this type is an interface.
*
* @return <code>true</code> if this type is an interface.
*/
public boolean isInterface() {
return false;
}
/**
* Get this type as an interface.
*
* @return This type as an interface.
* @throws ClassCastException Signals that this type is not an
* interface.
*/
public InterfaceT toInterface() {
throw new ClassCastException("Not an interface " + this);
}
/**
* Determine whether this type is an tuple.
*
* @return <code>true</code> if this type is an tuple.
*/
public boolean isTuple() {
return false;
}
/**
* Get this type as an tuple.
*
* @return This type as an tuple.
* @throws ClassCastException Signals that this type is not an tuple.
*/
public TupleT toTuple() {
throw new ClassCastException("Not an tuple " + this);
}
/**
* Determine whether this type is an variant.
*
* @return <code>true</code> if this type is an variant.
*/
public boolean isVariant() {
return false;
}
/**
* Get this type as an variant.
*
* @return This type as an variant.
* @throws ClassCastException Signals that this type is not an variant.
*/
public VariantT toVariant() {
throw new ClassCastException("Not an variant " + this);
}
// =========================================================================
/**
* Determine whether this type is wrapped.
*
* @return <code>true</code> if this type is wrapped.
*/
public boolean isWrapped() {
return false;
}
/**
* Get this type as a wrapped type.
*
* @return This type as a wrapped type.
* @throws ClassCastException Signals that this type is not wrapped.
*/
public WrappedT toWrapped() {
throw new ClassCastException("Not a wrapped type " + this);
}
// =========================================================================
/**
* Determine whether this type is annotated.
*
* @return <code>true</code> if this type is annotated.
*/
public boolean isAnnotated() {
return false;
}
/**
* Determine whether this type has an annotated type.
*
* @return <code>true</code> if this type has an annotated type.
*/
public boolean hasAnnotated() {
return false;
}
/**
* Get this type as an annotated type.
*
* @return This type as an annotated type.
* @throws ClassCastException Signas that this type is not an
* annotated type.
*/
public AnnotatedT toAnnotated() {
throw new ClassCastException("Not an annotated type " + this);
}
/**
* Determine whether this type is an alias.
*
* @return <code>true</code> if this type is an alias.
*/
public boolean isAlias() {
return false;
}
/**
* Determine whether this type contains an alias.
*
* @return <code>true</code> if this type contains an alias.
*/
public boolean hasAlias() {
return false;
}
/**
* Get this type as an alias.
*
* @return This type as an alias.
* @throws ClassCastException Signals that this type is not an
* alias.
*/
public AliasT toAlias() {
throw new ClassCastException("Not an alias " + this);
}
/**
* Determine whether this type is an enum.
*
* @return <code>true</code> if this type is an enum.
*/
public boolean isEnum() {
return false;
}
/**
* Determine whether this type contains an enum.
*
* @return <code>true</code> if this type contains an enum.
*/
public boolean hasEnum() {
return false;
}
/**
* Get this type as an enum.
*
* @return This type as an enum.
* @throws ClassCastException Signals that this type is not an enum.
*/
public EnumT toEnum() {
throw new ClassCastException("Not an enum " + this);
}
/**
* Determine whether this type is an enumerator.
*
* @return <code>true</code> if this type is an enumerator.
*/
public boolean isEnumerator() {
return false;
}
/**
* Determine whether this type contains an enumerator.
*
* @return <code>true</code> if this type contains an enumerator.
*/
public boolean hasEnumerator() {
return false;
}
/**
* Get this type as an enumerator.
*
* @return This type as an enumerator.
* @throws ClassCastException Signals that this type is not an
* enumerator.
*/
public EnumeratorT toEnumerator() {
throw new ClassCastException("Not an enumerator " + this);
}
/**
* Determine whether this type is instantiated.
*
* @return <code>true</code> if this type is instantiated.
*/
public boolean isInstantiated() {
return false;
}
/**
* Determine whether this type has an instantiated type.
*
* @return <code>true</code> if this type has an instantiated type.
*/
public boolean hasInstantiated() {
return false;
}
/**
* Get this type as an instantiated type.
*
* @return This type as an instantiated type.
* @throws ClassCastException Signas that this type is not an
* instantiated type.
*/
public InstantiatedT toInstantiated() {
throw new ClassCastException("Not an instantiated type " + this);
}
/**
* Determine whether this type is parameterized.
*
* @return <code>true</code> if this type is parameterized.
*/
public boolean isParameterized() {
return false;
}
/**
* Determine whether this type has a parameterized type.
*
* @return <code>true</code> if this type has a parameterized type.
*/
public boolean hasParameterized() {
return false;
}
/**
* Get this type as a parameterized type.
*
* @return This type as a parameterized type.
* @throws ClassCastException Signas that this type is not a
* parameterized type.
*/
public ParameterizedT toParameterized() {
throw new ClassCastException("Not a parameterized type " + this);
}
/**
* Determine whether this type is a variable.
*
* @return <code>true</code> if this type is a variable.
*/
public boolean isVariable() {
return false;
}
/**
* Determine whether this type contains a variable.
*
* @return <code>true</code> if this type contains a variable.
*/
public boolean hasVariable() {
return false;
}
/**
* Get this type as a variable.
*
* @return This type as a variable.
* @throws ClassCastException Signals that this type does not
* contain a variable.
*/
public VariableT toVariable() {
throw new ClassCastException("Not a variable " + this);
}
// =========================================================================
/**
* Determine whether this type is tagged.
*
* @return <code>true</code> if this type is tagged.
*/
public boolean hasTagged() {
return false;
}
/**
* Get this type as a tagged type.
*
* @see #hasTagged()
*
* @return This type as a tagged type.
* @throws ClassCastException Signals that this type is not
* tagged.
*/
public Tagged toTagged() {
throw new ClassCastException("Not a tagged type " + this);
}
// =========================================================================
/**
* Determine whether this type is concrete. This method returns
* <code>true</code> if this type is not parameterized or is both
* parameterized and instantiated.
*
* @return <code>true</code> if this type is concrete.
*/
public boolean isConcrete() {
return (! hasParameterized()) || hasInstantiated();
}
// =========================================================================
/**
* Resolve this type. This method removes any symbolic information,
* i.e., wrapped types, and returns the underlying, "raw" type.
*
* @return The resolved type.
*/
public Type resolve() {
return this;
}
// =========================================================================
/**
* Trace this type to the runtime's console. This method prints
* this type to the runtime's console using a new instance of {@link
* TypePrinter}; it is useful for debugging.
*
* @param runtime The runtime.
*/
public void trace(Runtime runtime) {
// Save the registered visitor.
Visitor visitor = runtime.console().visitor();
TypePrinter printer = new TypePrinter(runtime.console());
try {
printer.dispatch(this);
runtime.console().pln();
} finally {
// Restore the previously registered visitor.
runtime.console().register(visitor);
}
runtime.console().flush();
}
// =========================================================================
/**
* Cast the specified object to a type.
*
* @param type The type as an object.
* @return The type as a type.
* @throws ClassCastException Signals that the specified object is
* not a type.
*/
public static Type cast(Object type) {
return (Type)type;
}
/**
* Resolve the specified object as type.
*
* @param type The type.
* @return The resolved type.
* @throws ClassCastException Signals that the specified object is
* not a type.
*/
public static Type resolve(Object type) {
return ((Type)type).resolve();
}
// =========================================================================
/**
* Copy the specified list of types. A null list is ignored.
*
* @param types The list of types.
* @return A new list of the types' copies.
*/
@SuppressWarnings("unchecked")
public static <T extends Type> List<T> copy(List<T> types) {
if (null == types) return null;
List<T> copy = new ArrayList<T>(types.size());
for (T t : types) {
// This cast can never fail in the presence of covariant return
// types for copy().
copy.add((T)t.copy());
}
return copy;
}
/**
* Seal the specified list of types. A null list is ignored.
*
* @param types The list of types.
* @return An unmodifiable list of sealed types.
*/
public static <T extends Type> List<T> seal(List<T> types) {
if (null == types) return null;
for (T t : types) t.seal();
return Collections.unmodifiableList(types);
}
}