/*
* xtc - The eXTensible Compiler
* Copyright (C) 2004-2007 Robert Grimm
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.tree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import xtc.util.Pair;
/**
* A generic node in an abstract syntax tree.
*
* <p />A note on memory conservation: Generic nodes created through
* the {@link #create(String)} or {@link #create(String,int)} methods
* can have a variable number of children. While such nodes provide
* considerable flexibility in creating and managing an abstract
* syntax tree, their implementation also has a relatively high memory
* and thus performance overhead. Consequently, this class provides
* another set of <code>create()</code> methods, which directly take
* the new node's children as arguments and return nodes specialized
* for that number of children. After creation, the number of
* children cannot be changed anymore. Code using generic nodes can
* test whether a node supports a variable number of children through
* {@link #hasVariable()} and convert fixed size nodes into variable
* sized nodes through {@link #ensureVariable(GNode)}.
*
* @author Robert Grimm
* @version $Revision: 1.48 $
*/
public abstract class GNode extends Node {
/**
* The superclass of all generic nodes with a fixed number of
* children.
*/
static abstract class Fixed extends GNode {
/** Create a new fixed node. */
Fixed(String name) {
super(name);
}
public Node add(Object O) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
public Node add(int index, Object o) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
public Node addAll(Pair<?> p) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
public Node addAll(int index, Pair<?> p) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
public Node addAll(Collection<?> c) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
public Node addAll(int index, Collection<?> c) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
public Object remove(int index) {
throw new UnsupportedOperationException("Generic node with a fixed " +
"number of children");
}
}
// =======================================================================
/** A generic node with no children. */
static class Fixed0 extends Fixed {
Fixed0(String name) {
super(name);
}
Fixed0(Fixed0 node) {
super(node.name);
}
public int size() {
return 0;
}
public Object get(int index) {
throw new IndexOutOfBoundsException("Index: "+index+", Size: 0");
}
public Object set(int index, Object value) {
throw new IndexOutOfBoundsException("Index: "+index+", Size: 0");
}
public void addAllTo(Collection<Object> c) {
// Nothing to do.
}
}
// =======================================================================
/** A generic node with one child. */
static class Fixed1 extends Fixed {
Object c1;
Fixed1(String name, Object c1) {
super(name);
this.c1 = c1;
}
Fixed1(Fixed1 node) {
this(node.name, node.c1);
}
public int size() {
return 1;
}
public Object get(int index) {
if (0 == index) {
return c1;
} else {
throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
}
}
public Object set(int index, Object value) {
if (0 == index) {
Object old = c1;
c1 = value;
return old;
} else {
throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
}
}
// =======================================================================
/** A generic node with two children. */
static class Fixed2 extends Fixed {
Object c1;
Object c2;
Fixed2(String name, Object c1, Object c2) {
super(name);
this.c1 = c1;
this.c2 = c2;
}
Fixed2(Fixed2 node) {
this(node.name, node.c1, node.c2);
}
public int size() {
return 2;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 2");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 2");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
}
}
// =======================================================================
/** A generic node with three children. */
static class Fixed3 extends Fixed {
Object c1;
Object c2;
Object c3;
Fixed3(String name, Object c1, Object c2, Object c3) {
super(name);
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
}
Fixed3(Fixed3 node) {
this(node.name, node.c1, node.c2, node.c3);
}
public int size() {
return 3;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
case 2:
return c3;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 3");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
case 2:
old = c3;
c3 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 3");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
c.add(c3);
}
}
// =======================================================================
/** A generic node with four children. */
static class Fixed4 extends Fixed {
Object c1;
Object c2;
Object c3;
Object c4;
Fixed4(String name, Object c1, Object c2, Object c3, Object c4) {
super(name);
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
this.c4 = c4;
}
Fixed4(Fixed4 node) {
this(node.name, node.c1, node.c2, node.c3, node.c4);
}
public int size() {
return 4;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
case 2:
return c3;
case 3:
return c4;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 4");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
case 2:
old = c3;
c3 = value;
return old;
case 3:
old = c4;
c4 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 4");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
c.add(c3);
c.add(c4);
}
}
// =======================================================================
/** A generic node with five children. */
static class Fixed5 extends Fixed {
Object c1;
Object c2;
Object c3;
Object c4;
Object c5;
Fixed5(String name, Object c1, Object c2, Object c3, Object c4, Object c5) {
super(name);
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
this.c4 = c4;
this.c5 = c5;
}
Fixed5(Fixed5 node) {
this(node.name, node.c1, node.c2, node.c3, node.c4, node.c5);
}
public int size() {
return 5;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
case 2:
return c3;
case 3:
return c4;
case 4:
return c5;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 5");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
case 2:
old = c3;
c3 = value;
return old;
case 3:
old = c4;
c4 = value;
return old;
case 4:
old = c5;
c5 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 5");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
c.add(c3);
c.add(c4);
c.add(c5);
}
}
// =======================================================================
/** A generic node with six children. */
static class Fixed6 extends Fixed {
Object c1;
Object c2;
Object c3;
Object c4;
Object c5;
Object c6;
Fixed6(String name, Object c1, Object c2, Object c3, Object c4,
Object c5, Object c6) {
super(name);
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
this.c4 = c4;
this.c5 = c5;
this.c6 = c6;
}
Fixed6(Fixed6 node) {
this(node.name, node.c1, node.c2, node.c3, node.c4, node.c5, node.c6);
}
public int size() {
return 6;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
case 2:
return c3;
case 3:
return c4;
case 4:
return c5;
case 5:
return c6;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 6");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
case 2:
old = c3;
c3 = value;
return old;
case 3:
old = c4;
c4 = value;
return old;
case 4:
old = c5;
c5 = value;
return old;
case 5:
old = c6;
c6 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 6");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
c.add(c3);
c.add(c4);
c.add(c5);
c.add(c6);
}
}
// =======================================================================
/** A generic node with seven children. */
static class Fixed7 extends Fixed {
Object c1;
Object c2;
Object c3;
Object c4;
Object c5;
Object c6;
Object c7;
Fixed7(String name, Object c1, Object c2, Object c3, Object c4,
Object c5, Object c6, Object c7) {
super(name);
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
this.c4 = c4;
this.c5 = c5;
this.c6 = c6;
this.c7 = c7;
}
Fixed7(Fixed7 node) {
this(node.name, node.c1, node.c2, node.c3, node.c4, node.c5, node.c6,
node.c7);
}
public int size() {
return 7;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
case 2:
return c3;
case 3:
return c4;
case 4:
return c5;
case 5:
return c6;
case 6:
return c7;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 7");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
case 2:
old = c3;
c3 = value;
return old;
case 3:
old = c4;
c4 = value;
return old;
case 4:
old = c5;
c5 = value;
return old;
case 5:
old = c6;
c6 = value;
return old;
case 6:
old = c7;
c7 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 7");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
c.add(c3);
c.add(c4);
c.add(c5);
c.add(c6);
c.add(c7);
}
}
// =======================================================================
/** A generic node with eight children. */
static class Fixed8 extends Fixed {
Object c1;
Object c2;
Object c3;
Object c4;
Object c5;
Object c6;
Object c7;
Object c8;
Fixed8(String name, Object c1, Object c2, Object c3, Object c4,
Object c5, Object c6, Object c7, Object c8) {
super(name);
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
this.c4 = c4;
this.c5 = c5;
this.c6 = c6;
this.c7 = c7;
this.c8 = c8;
}
Fixed8(Fixed8 node) {
this(node.name, node.c1, node.c2, node.c3, node.c4, node.c5, node.c6,
node.c7, node.c8);
}
public int size() {
return 8;
}
public Object get(int index) {
switch (index) {
case 0:
return c1;
case 1:
return c2;
case 2:
return c3;
case 3:
return c4;
case 4:
return c5;
case 5:
return c6;
case 6:
return c7;
case 7:
return c8;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 8");
}
}
public Object set(int index, Object value) {
Object old;
switch (index) {
case 0:
old = c1;
c1 = value;
return old;
case 1:
old = c2;
c2 = value;
return old;
case 2:
old = c3;
c3 = value;
return old;
case 3:
old = c4;
c4 = value;
return old;
case 4:
old = c5;
c5 = value;
return old;
case 5:
old = c6;
c6 = value;
return old;
case 6:
old = c7;
c7 = value;
return old;
case 7:
old = c8;
c8 = value;
return old;
default:
throw new IndexOutOfBoundsException("Index: "+index+", Size: 8");
}
}
public void addAllTo(Collection<Object> c) {
c.add(c1);
c.add(c2);
c.add(c3);
c.add(c4);
c.add(c5);
c.add(c6);
c.add(c7);
c.add(c8);
}
}
// =======================================================================
/** A generic node with a variable number of children. */
static class Variable extends GNode {
/** The list of children. */
private ArrayList<Object> children;
/** Create a new variable node. */
Variable(String name) {
super(name);
children = new ArrayList<Object>();
}
/** Create a new variable node. */
Variable(String name, int capacity) {
super(name);
children = new ArrayList<Object>(capacity);
}
/** Create a new variable node. */
Variable(String name, ArrayList<Object> children) {
super(name);
this.children = children;
}
/** Create a new variable node. */
Variable(Variable node) {
super(node.name);
children = new ArrayList<Object>(node.children);
}
public boolean hasVariable() {
return true;
}
public Node add(Object o) {
children.add(o);
return this;
}
public Node add(int index, Object o) {
children.add(index, o);
return this;
}
public Node addAll(Pair<?> p) {
p.addTo(children);
return this;
}
public Node addAll(int index, Pair<?> p) {
p.addTo(children.subList(0, index));
return this;
}
public Node addAll(Collection<?> c) {
children.addAll(c);
return this;
}
public Node addAll(int index, Collection<?> c) {
children.addAll(index, c);
return this;
}
public void addAllTo(Collection<Object> c) {
c.addAll(children);
}
public Iterator<Object> iterator() {
return children.iterator();
}
public int size() {
return children.size();
}
public Object get(int index) {
return children.get(index);
}
public Object set(int index, Object value) {
return children.set(index, value);
}
public Object remove(int index) {
return children.remove(index);
}
}
// =======================================================================
/**
* The maximum number of children for generic nodes that are
* optimized to hold a fixed number of children.
*/
public static final int MAX_FIXED = 8;
/** The name. */
final String name;
/** Create a new generic node with the specified name. */
GNode(String name) {
this.name = name;
}
// =======================================================================
/**
* Get this generic node's hash code.
*
* @return This node's hash code.
*/
public int hashCode() {
int hash = name.hashCode();
int size = size();
for (int i=0; i<size; i++) {
Object child = get(i);
hash = (37 * hash) + (null==child? 0 : child.hashCode());
}
return hash;
}
/**
* Determine whether this generic node equals the specified object.
* This node equals the object, if both are generic nodes with the
* same names and the same number of equal children.
*
* @param o The object to compare to.
* @return <code>true</code> if this generic node equals the object.
*/
public boolean equals(Object o) {
if (this == o) return true;
if (! (o instanceof GNode)) return false;
GNode other = (GNode)o;
if (! name.equals(other.name)) return false;
int size = size();
if (other.size() != size) return false;
for (int i=0; i<size; i++) {
Object child1 = get(i);
Object child2 = other.get(i);
if (! (null==child1? null==child2 : child1.equals(child2))) return false;
}
return true;
}
// =======================================================================
/**
* Determine whether this node is generic.
*
* @return <code>true</code>.
*/
public final boolean isGeneric() {
return true;
}
public final boolean hasTraversal() {
return true;
}
public final String getName() {
return name;
}
public final boolean hasName(String name) {
return this.name.equals(name);
}
// =======================================================================
/**
* Create a new generic node with the specified name. The new node
* supports a variable number of children and has a default
* capacity.
*
* @param name The name.
* @return The corresponding generic node.
*/
public static GNode create(String name) {
return new Variable(name);
}
/**
* Create a new generic node with the specified name. The new node
* supports a variable number of children and has the specified
* capacity.
*
* @param name The name.
* @param capacity The initial capacity.
* @return The corresponding generic node.
* @throws IllegalArgumentException
* Signals that the capacity is negative.
*/
public static GNode create(String name, int capacity) {
return new Variable(name, capacity);
}
/**
* Create a new generic node with the specified name. Invoking this
* method with a true variable flag is equivalent to invoking {@link
* #create(String)}. Invoking this method with a false variabel
* flag results in a generic node with no children.
*
* @param name The name.
* @param variable Flag for whether the new node supports a variable
* number of children.
* @return The corresponding generic node.
*/
public static GNode create(String name, boolean variable) {
if (variable) {
return new Variable(name);
} else {
return new Fixed0(name);
}
}
/**
* Create a new generic node with the specified name and child. The
* new node does not support a variable number of children.
*
* @param name The name.
* @param child The child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object child) {
return new Fixed1(name, child);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2) {
return new Fixed2(name, c1, c2);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @param c3 The third child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2, Object c3) {
return new Fixed3(name, c1, c2, c3);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @param c3 The third child.
* @param c4 The fourth child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2, Object c3,
Object c4) {
return new Fixed4(name, c1, c2, c3, c4);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @param c3 The third child.
* @param c4 The fourth child.
* @param c5 The fifth child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2, Object c3,
Object c4, Object c5) {
return new Fixed5(name, c1, c2, c3, c4, c5);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @param c3 The third child.
* @param c4 The fourth child.
* @param c5 The fifth child.
* @param c6 The sixth child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2, Object c3,
Object c4, Object c5, Object c6) {
return new Fixed6(name, c1, c2, c3, c4, c5, c6);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @param c3 The third child.
* @param c4 The fourth child.
* @param c5 The fifth child.
* @param c6 The sixth child.
* @param c7 The seventh child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2, Object c3,
Object c4, Object c5, Object c6, Object c7) {
return new Fixed7(name, c1, c2, c3, c4, c5, c6, c7);
}
/**
* Create a new generic node with the specified name and children.
* The new node does not support a variable number of children.
*
* @param name The name.
* @param c1 The first child.
* @param c2 The second child.
* @param c3 The third child.
* @param c4 The fourth child.
* @param c5 The fifth child.
* @param c6 The sixth child.
* @param c7 The seventh child.
* @param c8 The eigth child.
* @return The corresponding generic node.
*/
public static GNode create(String name, Object c1, Object c2, Object c3,
Object c4, Object c5, Object c6, Object c7,
Object c8) {
return new Fixed8(name, c1, c2, c3, c4, c5, c6, c7, c8);
}
/**
* Create a new generic node with the list's nodes as its children.
* If possible, this method returns a fixed size node.
*
* @param name The name.
* @param p The list of children.
* @return The corresponding generic node.
*/
public static GNode createFromPair(String name, Pair p) {
final int size = p.size();
Object c1 = null;
Object c2 = null;
Object c3 = null;
Object c4 = null;
Object c5 = null;
Object c6 = null;
Object c7 = null;
Object c8 = null;
switch (size) {
case 8:
c1 = p.head();
p = p.tail();
// Fall through.
case 7:
c2 = p.head();
p = p.tail();
// Fall through.
case 6:
c3 = p.head();
p = p.tail();
// Fall through.
case 5:
c4 = p.head();
p = p.tail();
// Fall through.
case 4:
c5 = p.head();
p = p.tail();
// Fall through.
case 3:
c6 = p.head();
p = p.tail();
// Fall through.
case 2:
c7 = p.head();
p = p.tail();
// Fall through.
case 1:
c8 = p.head();
// Fall through.
case 0:
// Done.
break;
default:
Variable result = new Variable(name, size);
result.addAll(p);
return result;
}
switch (size) {
case 8:
return new Fixed8(name, c1, c2, c3, c4, c5, c6, c7, c8);
case 7:
return new Fixed7(name, c2, c3, c4, c5, c6, c7, c8);
case 6:
return new Fixed6(name, c3, c4, c5, c6, c7, c8);
case 5:
return new Fixed5(name, c4, c5, c6, c7, c8);
case 4:
return new Fixed4(name, c5, c6, c7, c8);
case 3:
return new Fixed3(name, c6, c7, c8);
case 2:
return new Fixed2(name, c7, c8);
case 1:
return new Fixed1(name, c8);
case 0:
return new Fixed0(name);
default:
throw new AssertionError("Internal error");
}
}
/**
* Create a new generic node with the specified children. If
* possible, this method returns a fixed size node.
*
* @param name The name.
* @param base The first child.
* @param rest The rest of the children.
* @return The corresponding generic node.
*/
public static GNode createFromPair(String name, Object base, Pair rest) {
final int size = rest.size();
Object c2 = null;
Object c3 = null;
Object c4 = null;
Object c5 = null;
Object c6 = null;
Object c7 = null;
Object c8 = null;
switch (size) {
case 7:
c2 = rest.head();
rest = rest.tail();
// Fall through.
case 6:
c3 = rest.head();
rest = rest.tail();
// Fall through.
case 5:
c4 = rest.head();
rest = rest.tail();
// Fall through.
case 4:
c5 = rest.head();
rest = rest.tail();
// Fall through.
case 3:
c6 = rest.head();
rest = rest.tail();
// Fall through.
case 2:
c7 = rest.head();
rest = rest.tail();
// Fall through.
case 1:
c8 = rest.head();
rest = rest.tail();
// Fall through.
case 0:
// Done.
break;
default:
Variable result = new Variable(name, size + 1);
result.add(base);
result.addAll(rest);
return result;
}
switch (size) {
case 7:
return new Fixed8(name, base, c2, c3, c4, c5, c6, c7, c8);
case 6:
return new Fixed7(name, base, c3, c4, c5, c6, c7, c8);
case 5:
return new Fixed6(name, base, c4, c5, c6, c7, c8);
case 4:
return new Fixed5(name, base, c5, c6, c7, c8);
case 3:
return new Fixed4(name, base, c6, c7, c8);
case 2:
return new Fixed3(name, base, c7, c8);
case 1:
return new Fixed2(name, base, c8);
case 0:
return new Fixed1(name, base);
default:
throw new AssertionError("Internal error");
}
}
/**
* Create a new generic node that is a (shallow) copy of the
* specified node.
*
* @param node The node to copy.
* @return The copy.
*/
public static GNode create(GNode node) {
if (node instanceof Variable) {
return new Variable((Variable)node);
} else {
switch (node.size()) {
case 0:
return new Fixed0((Fixed0)node);
case 1:
return new Fixed1((Fixed1)node);
case 2:
return new Fixed2((Fixed2)node);
case 3:
return new Fixed3((Fixed3)node);
case 4:
return new Fixed4((Fixed4)node);
case 5:
return new Fixed5((Fixed5)node);
case 6:
return new Fixed6((Fixed6)node);
case 7:
return new Fixed7((Fixed7)node);
case 8:
return new Fixed8((Fixed8)node);
default:
throw new AssertionError("Internal error");
}
}
}
// =======================================================================
/**
* Ensure that the specified node supports a variable number of
* children.
*
* @param node The generic node.
* @return A shallow copy of the specified node if it does not
* support a variable number of children; otherwise, the specified
* node.
*/
public static GNode ensureVariable(GNode node) {
if (node instanceof Variable) {
return node;
} else {
ArrayList<Object> children = new ArrayList<Object>(node.size());
node.addAllTo(children);
return new Variable(node.name, children);
}
}
/**
* Test whether the specified object is a generic node, possibly
* wrapped in annotations.
*
* @param o The object.
* @return <code>true</code> if the object is a possibly annotated
* generic node.
*/
public static final boolean test(Object o) {
return ((o instanceof Node) && ((Node)o).strip().isGeneric());
}
/**
* Cast the specified object to a generic node. If the specified
* object has any {@link Annotation annotations}, they are {@link
* Node#strip() stripped} before returning the object as a generic
* node.
*
* @see #test(Object)
*
* @param o The object.
* @return The object as a stripped generic node.
*/
public static final GNode cast(Object o) {
Node n = (Node)o;
return (null == n)? null : (GNode)n.strip();
}
}