001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.type;
020:
021: import java.io.IOException;
022:
023: import java.util.ArrayList;
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import xtc.util.Utilities;
028:
029: /**
030: * A variant type. Variants can be monomorphic or polymorphic, with
031: * the latter possibly sharing tuples with other variants.
032: * Monomorphic variants must be named and are compared through name
033: * equivalence. Polymorphic variants may be anonymous and are
034: * compared through structural equivalence.
035: *
036: * @author Robert Grimm
037: * @version $Revision: 1.12 $
038: */
039: public class VariantT extends DerivedT {
040:
041: /** The qualified name. */
042: final private String qname;
043:
044: /** The qualifier. */
045: final private String qualifier;
046:
047: /** The simple name. */
048: final private String sname;
049:
050: /** The flag for whether the variant is polymorphic. */
051: final private boolean polymorphic;
052:
053: /** The list of tuples. */
054: private List<TupleT> tuples;
055:
056: /**
057: * Create a new incomplete variant type. The new variant type is
058: * not polymorphic.
059: *
060: * @param name The name.
061: * @throws NullPointerException Signals that the name is null.
062: */
063: public VariantT(String name) {
064: this (null, name, false, null);
065: }
066:
067: /**
068: * Create a new variant type. The new variant type is not
069: * polymorphic.
070: *
071: * @param name The name.
072: * @param tuples The tuples.
073: * @throws NullPointerException Signals that the name is null.
074: */
075: public VariantT(String name, List<TupleT> tuples) {
076: this (null, name, false, tuples);
077: }
078:
079: /**
080: * Create a new variant type. Note that polymorphic variants may be
081: * anonymous, i.e., have a null name.
082: *
083: * @param name The name.
084: * @param polymorphic The flag for polymorphic variants.
085: * @param tuples The tuples.
086: * @throws NullPointerException Signals that the name is null for a
087: * monomorphic variant.
088: */
089: public VariantT(String name, boolean polymorphic,
090: List<TupleT> tuples) {
091: this (null, name, polymorphic, tuples);
092: }
093:
094: /**
095: * Create a new variant type.
096: *
097: * @param template The type whose annotations to copy.
098: * @param name The name.
099: * @param polymorphic The flag for polymorphic variants.
100: * @param tuples The tuples.
101: * @throws NullPointerException Signals that the name is null for a
102: * monomorphic variant.
103: */
104: public VariantT(Type template, String name, boolean polymorphic,
105: List<TupleT> tuples) {
106: super (template);
107: this .qname = name;
108: this .qualifier = (null == name) ? null : Utilities
109: .getQualifier(name);
110: this .sname = (null == name) ? null : Utilities.unqualify(name);
111: this .polymorphic = polymorphic;
112: this .tuples = tuples;
113: if (null == name && !polymorphic) {
114: throw new NullPointerException("Null name");
115: }
116: }
117:
118: public Type seal() {
119: if (!isSealed()) {
120: super .seal();
121: tuples = Type.seal(tuples);
122: }
123: return this ;
124: }
125:
126: public VariantT copy() {
127: return new VariantT(this , qname, polymorphic, copy(tuples));
128: }
129:
130: public Type.Tag tag() {
131: return Type.Tag.VARIANT;
132: }
133:
134: public boolean isVariant() {
135: return true;
136: }
137:
138: public VariantT toVariant() {
139: return this ;
140: }
141:
142: /**
143: * Get this variant's name.
144: *
145: * @return The name or <code>null</code> if this variant is anonymous.
146: */
147: public String getName() {
148: return qname;
149: }
150:
151: /**
152: * Get this variant's qualifier.
153: *
154: * @return The qualifier or <code>null</code> if this variant does
155: * not have a qualified name.
156: */
157: public String getQualifier() {
158: return qualifier;
159: }
160:
161: /**
162: * Get this variant's simple name.
163: *
164: * @return The simple name or <code>null</code> if this variant is
165: * anonymous.
166: */
167: public String getSimpleName() {
168: return sname;
169: }
170:
171: /**
172: * Determine whether the variant is polymorphic.
173: *
174: * @return <code>true</code> if the variant is polymorphic.
175: */
176: public boolean isPolymorphic() {
177: return polymorphic;
178: }
179:
180: /**
181: * Look up the tuple with the specified name.
182: *
183: * @param name The name.
184: * @return The tuple or {@link ErrorT#TYPE} if this variant has no
185: * such tuple.
186: */
187: public Type lookup(String name) {
188: for (TupleT tuple : tuples)
189: if (tuple.hasName(name))
190: return tuple;
191: return ErrorT.TYPE;
192: }
193:
194: /**
195: * Look up the tuple with the specified simple name.
196: *
197: * @param name The simple name.
198: * @return The first such tuple or {@link ErrorT#TYPE} if this
199: * variant has no such tuple.
200: */
201: public Type lookupSimple(String name) {
202: for (TupleT tuple : tuples)
203: if (tuple.hasSimpleName(name))
204: return tuple;
205: return ErrorT.TYPE;
206: }
207:
208: /**
209: * Get this variant's tuples.
210: *
211: * @return The list of tuples.
212: */
213: public List<TupleT> getTuples() {
214: return tuples;
215: }
216:
217: /**
218: * Set this variant's tuples.
219: *
220: * @param tuples The new list of tuples.
221: */
222: public void setTuples(List<TupleT> tuples) {
223: checkNotSealed();
224: this .tuples = tuples;
225: }
226:
227: public int hashCode() {
228: if (polymorphic) {
229: return null == tuples ? 0 : tuples.hashCode();
230: } else {
231: return qname.hashCode();
232: }
233: }
234:
235: /**
236: * Determine whether this variant equals the specified object. This
237: * method implements name equivalence for non-polymorphic variants
238: * and structural equivalence for polymorphic variants.
239: *
240: * @param o The object.
241: * @return <code>true</code> if this variant equals the object.
242: */
243: public boolean equals(Object o) {
244: if (!(o instanceof Type))
245: return false;
246: Type t = resolve(o);
247:
248: if (this == t)
249: return true;
250: if (!t.isVariant())
251: return false;
252: VariantT other = t.toVariant();
253:
254: if (polymorphic != other.polymorphic)
255: return false;
256: if (!polymorphic)
257: return qname.equals(other.qname);
258: if (null == tuples)
259: return null == other.tuples;
260: if (tuples.size() != other.tuples.size())
261: return false;
262:
263: for (TupleT tuple : tuples) {
264: if (!other.tuples.contains(tuple))
265: return false;
266: }
267:
268: for (TupleT tuple : other.tuples) {
269: if (!tuples.contains(tuple))
270: return false;
271: }
272:
273: return true;
274: }
275:
276: public void write(Appendable out) throws IOException {
277: if (null != qname) {
278: out.append("variant ");
279: out.append(qname);
280:
281: } else {
282: out.append("variant(");
283: for (Iterator<TupleT> iter = tuples.iterator(); iter
284: .hasNext();) {
285: out.append('`');
286: iter.next().write(out);
287: if (iter.hasNext())
288: out.append(", ");
289: }
290: out.append(')');
291: }
292: }
293:
294: }
|