/*
* 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.util.List;
import xtc.util.Nonce;
/**
* The superclass of struct and union types.
*
* @author Robert Grimm
* @version $Revision: 1.42 $
*/
public abstract class StructOrUnionT extends DerivedT implements Tagged {
/** The nonce. */
protected final Nonce nonce;
/** The name. */
protected final String name;
/** The list of members represents as {@link VariableT}. */
protected List<VariableT> members;
/**
* Create a new struct or union type.
*
* @param template The type whose annotations to copy.
* @param nonce The nonce.
* @param name The name.
* @param members The members.
* @throws NullPointerException Signals a null name.
*/
public StructOrUnionT(Type template, Nonce nonce, String name,
List<VariableT> members) {
super(template);
if (null == name) throw new NullPointerException("Null name");
this.nonce = nonce;
this.name = name;
this.members = members;
}
/**
* Seal this struct or union. If this struct or union is
* incomplete, i.e., does not have any members, invocations to this
* method have no effect.
*/
public Type seal() {
if (null != members) {
if (! isSealed()) {
super.seal();
members = Type.seal(members);
}
}
return this;
}
public StructOrUnionT toStructOrUnion() {
return this;
}
public boolean hasTagged() {
return true;
}
public Tagged toTagged() {
return this;
}
public Nonce getNonce() {
return nonce;
}
public boolean isUnnamed() {
return name.startsWith("tag(");
}
public boolean hasName(String name) {
return name.equals(this.name);
}
public String getName() {
return name;
}
public Type lookup(String name) {
for (VariableT member : members) {
if (member.hasName(name)) return member;
if ((! member.hasName()) && (! member.hasWidth())) {
// The member is an unnamed struct or union.
Type nested = ((StructOrUnionT)member.resolve()).lookup(name);
if (! nested.isError()) return nested;
}
}
return ErrorT.TYPE;
}
public int getMemberCount() {
if (null == members) {
return -1;
} else {
int count = 0;
for (VariableT member : members) {
// If the member has a name, it counts. If the member does
// not have a name and does not have a width, it is an
// unnamed struct/union and counts.
if (member.hasName() || (! member.hasWidth())) count++;
}
return count;
}
}
public VariableT getMember(int index) {
int count = -1;
for (VariableT member: members) {
if (member.hasName() || (! member.hasWidth())) {
count++;
if (index == count) return member;
}
}
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+(count+1));
}
public List<VariableT> getMembers() {
return members;
}
/**
* Set the members.
*
* @param members The members.
* @throws IllegalStateException Signals that this type is sealed.
*/
public void setMembers(List<VariableT> members) {
checkNotSealed();
this.members = members;
}
public int hashCode() {
return name.hashCode();
}
/**
* Determine whether this type equals the specified object. A
* struct or union equals the specified object if the specified
* object is a struct or union with the same nonce.
*
* @param o The object.
* @return <code>true</code> if this type equals the object.
*/
public boolean equals(Object o) {
if (! (o instanceof Type)) return false;
Type t = (Type)o;
return t.hasTagged() && (nonce == t.toTagged().getNonce());
}
}