/*
* xtc - The eXTensible Compiler
* Copyright (C) 2004-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.tree;
import java.io.IOException;
import java.util.List;
import xtc.util.Pair;
/**
* A name/value pair.
*
* @author Robert Grimm
* @version $Revision: 1.12 $
*/
public class Attribute extends Node {
/** The name. */
final String name;
/** The value. */
final Object value;
/**
* Create a new attribute with the specified name. The new
* attribute's value is <code>null</code>.
*
* @param name The name.
*/
public Attribute(String name) {
this(name, null);
}
/**
* Create a new attribute with the specified name and value.
*
* @param name The name.
* @param value The value.
*/
public Attribute(String name, Object value) {
this.name = name;
this.value = value;
}
public boolean hasTraversal() {
return true;
}
public int size() {
return null == value ? 1 : 2;
}
public Object get(int index) {
if (0 == index) return name;
if ((null != value) && (1 == index)) return value;
throw new IndexOutOfBoundsException("Index : " + index + ", Size: " +
(null == value ? 1 : 2));
}
public Object set(int index, Object value) {
throw new IllegalStateException("Attributes are immutable");
}
/**
* Get the name.
*
* @return The name.
*/
public String getName() {
return name;
}
/**
* Get the value.
*
* @return The value.
*/
public Object getValue() {
return value;
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Object o) {
if (this == o) return true;
if (! (o instanceof Attribute)) return false;
Attribute other = (Attribute)o;
if (! name.equals(other.name)) return false;
if (null == value) return (null == other.value);
return value.equals(other.value);
}
public void write(Appendable out) throws IOException {
out.append(name);
if (null != value) {
out.append('(');
if ((value instanceof List) || (value instanceof Pair)) {
boolean first = true;
for (Object o : (Iterable<?>)value) {
if (first) {
first = false;
} else {
out.append(", ");
}
if (o instanceof Node) {
((Node)o).write(out);
} else {
out.append(o.toString());
}
}
} else if (value instanceof Node) {
((Node)value).write(out);
} else {
out.append(value.toString());
}
out.append(')');
}
}
/**
* Get the attribute with the specified name from the specified list.
*
* @param name The name.
* @param list The list.
* @return The corresponding attribute or <code>null</code> if the
* list is <code>null</code> or contains no such attribute.
*/
public static Attribute get(String name, List<Attribute> list) {
if (null == list) return null;
for (Attribute att : list) {
if (name.equals(att.name)) return att;
}
return null;
}
/**
* Determine whether the specified lists of attributes are equivalent.
*
* @param l1 The first list.
* @param l2 The second list.
* @return <code>true</code> if the two lists are equivalent, that is,
* contain the same attributes in some order.
*/
public static boolean areEquivalent(List<Attribute> l1, List<Attribute> l2) {
if (null == l1) {
return (null == l2) || (0 == l2.size());
} else if (null == l2) {
return (0 == l1.size());
} else {
return l1.containsAll(l2) && l2.containsAll(l1);
}
}
}