0001: /*
0002: * xtc - The eXTensible Compiler
0003: * Copyright (C) 2004-2007 Robert Grimm
0004: *
0005: * This library is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU Lesser General Public License
0007: * version 2.1 as published by the Free Software Foundation.
0008: *
0009: * This library is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: * Lesser General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU Lesser General Public
0015: * License along with this library; if not, write to the Free Software
0016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0017: * USA.
0018: */
0019: package xtc.tree;
0020:
0021: import java.util.ArrayList;
0022: import java.util.Collection;
0023: import java.util.Iterator;
0024:
0025: import xtc.util.Pair;
0026:
0027: /**
0028: * A generic node in an abstract syntax tree.
0029: *
0030: * <p />A note on memory conservation: Generic nodes created through
0031: * the {@link #create(String)} or {@link #create(String,int)} methods
0032: * can have a variable number of children. While such nodes provide
0033: * considerable flexibility in creating and managing an abstract
0034: * syntax tree, their implementation also has a relatively high memory
0035: * and thus performance overhead. Consequently, this class provides
0036: * another set of <code>create()</code> methods, which directly take
0037: * the new node's children as arguments and return nodes specialized
0038: * for that number of children. After creation, the number of
0039: * children cannot be changed anymore. Code using generic nodes can
0040: * test whether a node supports a variable number of children through
0041: * {@link #hasVariable()} and convert fixed size nodes into variable
0042: * sized nodes through {@link #ensureVariable(GNode)}.
0043: *
0044: * @author Robert Grimm
0045: * @version $Revision: 1.48 $
0046: */
0047: public abstract class GNode extends Node {
0048:
0049: /**
0050: * The superclass of all generic nodes with a fixed number of
0051: * children.
0052: */
0053: static abstract class Fixed extends GNode {
0054:
0055: /** Create a new fixed node. */
0056: Fixed(String name) {
0057: super (name);
0058: }
0059:
0060: public Node add(Object O) {
0061: throw new UnsupportedOperationException(
0062: "Generic node with a fixed " + "number of children");
0063: }
0064:
0065: public Node add(int index, Object o) {
0066: throw new UnsupportedOperationException(
0067: "Generic node with a fixed " + "number of children");
0068: }
0069:
0070: public Node addAll(Pair<?> p) {
0071: throw new UnsupportedOperationException(
0072: "Generic node with a fixed " + "number of children");
0073: }
0074:
0075: public Node addAll(int index, Pair<?> p) {
0076: throw new UnsupportedOperationException(
0077: "Generic node with a fixed " + "number of children");
0078: }
0079:
0080: public Node addAll(Collection<?> c) {
0081: throw new UnsupportedOperationException(
0082: "Generic node with a fixed " + "number of children");
0083: }
0084:
0085: public Node addAll(int index, Collection<?> c) {
0086: throw new UnsupportedOperationException(
0087: "Generic node with a fixed " + "number of children");
0088: }
0089:
0090: public Object remove(int index) {
0091: throw new UnsupportedOperationException(
0092: "Generic node with a fixed " + "number of children");
0093: }
0094:
0095: }
0096:
0097: // =======================================================================
0098:
0099: /** A generic node with no children. */
0100: static class Fixed0 extends Fixed {
0101:
0102: Fixed0(String name) {
0103: super (name);
0104: }
0105:
0106: Fixed0(Fixed0 node) {
0107: super (node.name);
0108: }
0109:
0110: public int size() {
0111: return 0;
0112: }
0113:
0114: public Object get(int index) {
0115: throw new IndexOutOfBoundsException("Index: " + index
0116: + ", Size: 0");
0117: }
0118:
0119: public Object set(int index, Object value) {
0120: throw new IndexOutOfBoundsException("Index: " + index
0121: + ", Size: 0");
0122: }
0123:
0124: public void addAllTo(Collection<Object> c) {
0125: // Nothing to do.
0126: }
0127:
0128: }
0129:
0130: // =======================================================================
0131:
0132: /** A generic node with one child. */
0133: static class Fixed1 extends Fixed {
0134:
0135: Object c1;
0136:
0137: Fixed1(String name, Object c1) {
0138: super (name);
0139: this .c1 = c1;
0140: }
0141:
0142: Fixed1(Fixed1 node) {
0143: this (node.name, node.c1);
0144: }
0145:
0146: public int size() {
0147: return 1;
0148: }
0149:
0150: public Object get(int index) {
0151: if (0 == index) {
0152: return c1;
0153: } else {
0154: throw new IndexOutOfBoundsException("Index: " + index
0155: + ", Size: 1");
0156: }
0157: }
0158:
0159: public Object set(int index, Object value) {
0160: if (0 == index) {
0161: Object old = c1;
0162: c1 = value;
0163: return old;
0164: } else {
0165: throw new IndexOutOfBoundsException("Index: " + index
0166: + ", Size: 1");
0167: }
0168: }
0169:
0170: public void addAllTo(Collection<Object> c) {
0171: c.add(c1);
0172: }
0173:
0174: }
0175:
0176: // =======================================================================
0177:
0178: /** A generic node with two children. */
0179: static class Fixed2 extends Fixed {
0180:
0181: Object c1;
0182: Object c2;
0183:
0184: Fixed2(String name, Object c1, Object c2) {
0185: super (name);
0186: this .c1 = c1;
0187: this .c2 = c2;
0188: }
0189:
0190: Fixed2(Fixed2 node) {
0191: this (node.name, node.c1, node.c2);
0192: }
0193:
0194: public int size() {
0195: return 2;
0196: }
0197:
0198: public Object get(int index) {
0199: switch (index) {
0200: case 0:
0201: return c1;
0202: case 1:
0203: return c2;
0204: default:
0205: throw new IndexOutOfBoundsException("Index: " + index
0206: + ", Size: 2");
0207: }
0208: }
0209:
0210: public Object set(int index, Object value) {
0211: Object old;
0212:
0213: switch (index) {
0214: case 0:
0215: old = c1;
0216: c1 = value;
0217: return old;
0218: case 1:
0219: old = c2;
0220: c2 = value;
0221: return old;
0222: default:
0223: throw new IndexOutOfBoundsException("Index: " + index
0224: + ", Size: 2");
0225: }
0226: }
0227:
0228: public void addAllTo(Collection<Object> c) {
0229: c.add(c1);
0230: c.add(c2);
0231: }
0232:
0233: }
0234:
0235: // =======================================================================
0236:
0237: /** A generic node with three children. */
0238: static class Fixed3 extends Fixed {
0239:
0240: Object c1;
0241: Object c2;
0242: Object c3;
0243:
0244: Fixed3(String name, Object c1, Object c2, Object c3) {
0245: super (name);
0246: this .c1 = c1;
0247: this .c2 = c2;
0248: this .c3 = c3;
0249: }
0250:
0251: Fixed3(Fixed3 node) {
0252: this (node.name, node.c1, node.c2, node.c3);
0253: }
0254:
0255: public int size() {
0256: return 3;
0257: }
0258:
0259: public Object get(int index) {
0260: switch (index) {
0261: case 0:
0262: return c1;
0263: case 1:
0264: return c2;
0265: case 2:
0266: return c3;
0267: default:
0268: throw new IndexOutOfBoundsException("Index: " + index
0269: + ", Size: 3");
0270: }
0271: }
0272:
0273: public Object set(int index, Object value) {
0274: Object old;
0275:
0276: switch (index) {
0277: case 0:
0278: old = c1;
0279: c1 = value;
0280: return old;
0281: case 1:
0282: old = c2;
0283: c2 = value;
0284: return old;
0285: case 2:
0286: old = c3;
0287: c3 = value;
0288: return old;
0289: default:
0290: throw new IndexOutOfBoundsException("Index: " + index
0291: + ", Size: 3");
0292: }
0293: }
0294:
0295: public void addAllTo(Collection<Object> c) {
0296: c.add(c1);
0297: c.add(c2);
0298: c.add(c3);
0299: }
0300:
0301: }
0302:
0303: // =======================================================================
0304:
0305: /** A generic node with four children. */
0306: static class Fixed4 extends Fixed {
0307:
0308: Object c1;
0309: Object c2;
0310: Object c3;
0311: Object c4;
0312:
0313: Fixed4(String name, Object c1, Object c2, Object c3, Object c4) {
0314: super (name);
0315: this .c1 = c1;
0316: this .c2 = c2;
0317: this .c3 = c3;
0318: this .c4 = c4;
0319: }
0320:
0321: Fixed4(Fixed4 node) {
0322: this (node.name, node.c1, node.c2, node.c3, node.c4);
0323: }
0324:
0325: public int size() {
0326: return 4;
0327: }
0328:
0329: public Object get(int index) {
0330: switch (index) {
0331: case 0:
0332: return c1;
0333: case 1:
0334: return c2;
0335: case 2:
0336: return c3;
0337: case 3:
0338: return c4;
0339: default:
0340: throw new IndexOutOfBoundsException("Index: " + index
0341: + ", Size: 4");
0342: }
0343: }
0344:
0345: public Object set(int index, Object value) {
0346: Object old;
0347:
0348: switch (index) {
0349: case 0:
0350: old = c1;
0351: c1 = value;
0352: return old;
0353: case 1:
0354: old = c2;
0355: c2 = value;
0356: return old;
0357: case 2:
0358: old = c3;
0359: c3 = value;
0360: return old;
0361: case 3:
0362: old = c4;
0363: c4 = value;
0364: return old;
0365: default:
0366: throw new IndexOutOfBoundsException("Index: " + index
0367: + ", Size: 4");
0368: }
0369: }
0370:
0371: public void addAllTo(Collection<Object> c) {
0372: c.add(c1);
0373: c.add(c2);
0374: c.add(c3);
0375: c.add(c4);
0376: }
0377:
0378: }
0379:
0380: // =======================================================================
0381:
0382: /** A generic node with five children. */
0383: static class Fixed5 extends Fixed {
0384:
0385: Object c1;
0386: Object c2;
0387: Object c3;
0388: Object c4;
0389: Object c5;
0390:
0391: Fixed5(String name, Object c1, Object c2, Object c3, Object c4,
0392: Object c5) {
0393: super (name);
0394: this .c1 = c1;
0395: this .c2 = c2;
0396: this .c3 = c3;
0397: this .c4 = c4;
0398: this .c5 = c5;
0399: }
0400:
0401: Fixed5(Fixed5 node) {
0402: this (node.name, node.c1, node.c2, node.c3, node.c4, node.c5);
0403: }
0404:
0405: public int size() {
0406: return 5;
0407: }
0408:
0409: public Object get(int index) {
0410: switch (index) {
0411: case 0:
0412: return c1;
0413: case 1:
0414: return c2;
0415: case 2:
0416: return c3;
0417: case 3:
0418: return c4;
0419: case 4:
0420: return c5;
0421: default:
0422: throw new IndexOutOfBoundsException("Index: " + index
0423: + ", Size: 5");
0424: }
0425: }
0426:
0427: public Object set(int index, Object value) {
0428: Object old;
0429:
0430: switch (index) {
0431: case 0:
0432: old = c1;
0433: c1 = value;
0434: return old;
0435: case 1:
0436: old = c2;
0437: c2 = value;
0438: return old;
0439: case 2:
0440: old = c3;
0441: c3 = value;
0442: return old;
0443: case 3:
0444: old = c4;
0445: c4 = value;
0446: return old;
0447: case 4:
0448: old = c5;
0449: c5 = value;
0450: return old;
0451: default:
0452: throw new IndexOutOfBoundsException("Index: " + index
0453: + ", Size: 5");
0454: }
0455: }
0456:
0457: public void addAllTo(Collection<Object> c) {
0458: c.add(c1);
0459: c.add(c2);
0460: c.add(c3);
0461: c.add(c4);
0462: c.add(c5);
0463: }
0464:
0465: }
0466:
0467: // =======================================================================
0468:
0469: /** A generic node with six children. */
0470: static class Fixed6 extends Fixed {
0471:
0472: Object c1;
0473: Object c2;
0474: Object c3;
0475: Object c4;
0476: Object c5;
0477: Object c6;
0478:
0479: Fixed6(String name, Object c1, Object c2, Object c3, Object c4,
0480: Object c5, Object c6) {
0481: super (name);
0482: this .c1 = c1;
0483: this .c2 = c2;
0484: this .c3 = c3;
0485: this .c4 = c4;
0486: this .c5 = c5;
0487: this .c6 = c6;
0488: }
0489:
0490: Fixed6(Fixed6 node) {
0491: this (node.name, node.c1, node.c2, node.c3, node.c4,
0492: node.c5, node.c6);
0493: }
0494:
0495: public int size() {
0496: return 6;
0497: }
0498:
0499: public Object get(int index) {
0500: switch (index) {
0501: case 0:
0502: return c1;
0503: case 1:
0504: return c2;
0505: case 2:
0506: return c3;
0507: case 3:
0508: return c4;
0509: case 4:
0510: return c5;
0511: case 5:
0512: return c6;
0513: default:
0514: throw new IndexOutOfBoundsException("Index: " + index
0515: + ", Size: 6");
0516: }
0517: }
0518:
0519: public Object set(int index, Object value) {
0520: Object old;
0521:
0522: switch (index) {
0523: case 0:
0524: old = c1;
0525: c1 = value;
0526: return old;
0527: case 1:
0528: old = c2;
0529: c2 = value;
0530: return old;
0531: case 2:
0532: old = c3;
0533: c3 = value;
0534: return old;
0535: case 3:
0536: old = c4;
0537: c4 = value;
0538: return old;
0539: case 4:
0540: old = c5;
0541: c5 = value;
0542: return old;
0543: case 5:
0544: old = c6;
0545: c6 = value;
0546: return old;
0547: default:
0548: throw new IndexOutOfBoundsException("Index: " + index
0549: + ", Size: 6");
0550: }
0551: }
0552:
0553: public void addAllTo(Collection<Object> c) {
0554: c.add(c1);
0555: c.add(c2);
0556: c.add(c3);
0557: c.add(c4);
0558: c.add(c5);
0559: c.add(c6);
0560: }
0561:
0562: }
0563:
0564: // =======================================================================
0565:
0566: /** A generic node with seven children. */
0567: static class Fixed7 extends Fixed {
0568:
0569: Object c1;
0570: Object c2;
0571: Object c3;
0572: Object c4;
0573: Object c5;
0574: Object c6;
0575: Object c7;
0576:
0577: Fixed7(String name, Object c1, Object c2, Object c3, Object c4,
0578: Object c5, Object c6, Object c7) {
0579: super (name);
0580: this .c1 = c1;
0581: this .c2 = c2;
0582: this .c3 = c3;
0583: this .c4 = c4;
0584: this .c5 = c5;
0585: this .c6 = c6;
0586: this .c7 = c7;
0587: }
0588:
0589: Fixed7(Fixed7 node) {
0590: this (node.name, node.c1, node.c2, node.c3, node.c4,
0591: node.c5, node.c6, node.c7);
0592: }
0593:
0594: public int size() {
0595: return 7;
0596: }
0597:
0598: public Object get(int index) {
0599: switch (index) {
0600: case 0:
0601: return c1;
0602: case 1:
0603: return c2;
0604: case 2:
0605: return c3;
0606: case 3:
0607: return c4;
0608: case 4:
0609: return c5;
0610: case 5:
0611: return c6;
0612: case 6:
0613: return c7;
0614: default:
0615: throw new IndexOutOfBoundsException("Index: " + index
0616: + ", Size: 7");
0617: }
0618: }
0619:
0620: public Object set(int index, Object value) {
0621: Object old;
0622:
0623: switch (index) {
0624: case 0:
0625: old = c1;
0626: c1 = value;
0627: return old;
0628: case 1:
0629: old = c2;
0630: c2 = value;
0631: return old;
0632: case 2:
0633: old = c3;
0634: c3 = value;
0635: return old;
0636: case 3:
0637: old = c4;
0638: c4 = value;
0639: return old;
0640: case 4:
0641: old = c5;
0642: c5 = value;
0643: return old;
0644: case 5:
0645: old = c6;
0646: c6 = value;
0647: return old;
0648: case 6:
0649: old = c7;
0650: c7 = value;
0651: return old;
0652: default:
0653: throw new IndexOutOfBoundsException("Index: " + index
0654: + ", Size: 7");
0655: }
0656: }
0657:
0658: public void addAllTo(Collection<Object> c) {
0659: c.add(c1);
0660: c.add(c2);
0661: c.add(c3);
0662: c.add(c4);
0663: c.add(c5);
0664: c.add(c6);
0665: c.add(c7);
0666: }
0667:
0668: }
0669:
0670: // =======================================================================
0671:
0672: /** A generic node with eight children. */
0673: static class Fixed8 extends Fixed {
0674:
0675: Object c1;
0676: Object c2;
0677: Object c3;
0678: Object c4;
0679: Object c5;
0680: Object c6;
0681: Object c7;
0682: Object c8;
0683:
0684: Fixed8(String name, Object c1, Object c2, Object c3, Object c4,
0685: Object c5, Object c6, Object c7, Object c8) {
0686: super (name);
0687: this .c1 = c1;
0688: this .c2 = c2;
0689: this .c3 = c3;
0690: this .c4 = c4;
0691: this .c5 = c5;
0692: this .c6 = c6;
0693: this .c7 = c7;
0694: this .c8 = c8;
0695: }
0696:
0697: Fixed8(Fixed8 node) {
0698: this (node.name, node.c1, node.c2, node.c3, node.c4,
0699: node.c5, node.c6, node.c7, node.c8);
0700: }
0701:
0702: public int size() {
0703: return 8;
0704: }
0705:
0706: public Object get(int index) {
0707: switch (index) {
0708: case 0:
0709: return c1;
0710: case 1:
0711: return c2;
0712: case 2:
0713: return c3;
0714: case 3:
0715: return c4;
0716: case 4:
0717: return c5;
0718: case 5:
0719: return c6;
0720: case 6:
0721: return c7;
0722: case 7:
0723: return c8;
0724: default:
0725: throw new IndexOutOfBoundsException("Index: " + index
0726: + ", Size: 8");
0727: }
0728: }
0729:
0730: public Object set(int index, Object value) {
0731: Object old;
0732:
0733: switch (index) {
0734: case 0:
0735: old = c1;
0736: c1 = value;
0737: return old;
0738: case 1:
0739: old = c2;
0740: c2 = value;
0741: return old;
0742: case 2:
0743: old = c3;
0744: c3 = value;
0745: return old;
0746: case 3:
0747: old = c4;
0748: c4 = value;
0749: return old;
0750: case 4:
0751: old = c5;
0752: c5 = value;
0753: return old;
0754: case 5:
0755: old = c6;
0756: c6 = value;
0757: return old;
0758: case 6:
0759: old = c7;
0760: c7 = value;
0761: return old;
0762: case 7:
0763: old = c8;
0764: c8 = value;
0765: return old;
0766: default:
0767: throw new IndexOutOfBoundsException("Index: " + index
0768: + ", Size: 8");
0769: }
0770: }
0771:
0772: public void addAllTo(Collection<Object> c) {
0773: c.add(c1);
0774: c.add(c2);
0775: c.add(c3);
0776: c.add(c4);
0777: c.add(c5);
0778: c.add(c6);
0779: c.add(c7);
0780: c.add(c8);
0781: }
0782:
0783: }
0784:
0785: // =======================================================================
0786:
0787: /** A generic node with a variable number of children. */
0788: static class Variable extends GNode {
0789:
0790: /** The list of children. */
0791: private ArrayList<Object> children;
0792:
0793: /** Create a new variable node. */
0794: Variable(String name) {
0795: super (name);
0796: children = new ArrayList<Object>();
0797: }
0798:
0799: /** Create a new variable node. */
0800: Variable(String name, int capacity) {
0801: super (name);
0802: children = new ArrayList<Object>(capacity);
0803: }
0804:
0805: /** Create a new variable node. */
0806: Variable(String name, ArrayList<Object> children) {
0807: super (name);
0808: this .children = children;
0809: }
0810:
0811: /** Create a new variable node. */
0812: Variable(Variable node) {
0813: super (node.name);
0814: children = new ArrayList<Object>(node.children);
0815: }
0816:
0817: public boolean hasVariable() {
0818: return true;
0819: }
0820:
0821: public Node add(Object o) {
0822: children.add(o);
0823: return this ;
0824: }
0825:
0826: public Node add(int index, Object o) {
0827: children.add(index, o);
0828: return this ;
0829: }
0830:
0831: public Node addAll(Pair<?> p) {
0832: p.addTo(children);
0833: return this ;
0834: }
0835:
0836: public Node addAll(int index, Pair<?> p) {
0837: p.addTo(children.subList(0, index));
0838: return this ;
0839: }
0840:
0841: public Node addAll(Collection<?> c) {
0842: children.addAll(c);
0843: return this ;
0844: }
0845:
0846: public Node addAll(int index, Collection<?> c) {
0847: children.addAll(index, c);
0848: return this ;
0849: }
0850:
0851: public void addAllTo(Collection<Object> c) {
0852: c.addAll(children);
0853: }
0854:
0855: public Iterator<Object> iterator() {
0856: return children.iterator();
0857: }
0858:
0859: public int size() {
0860: return children.size();
0861: }
0862:
0863: public Object get(int index) {
0864: return children.get(index);
0865: }
0866:
0867: public Object set(int index, Object value) {
0868: return children.set(index, value);
0869: }
0870:
0871: public Object remove(int index) {
0872: return children.remove(index);
0873: }
0874:
0875: }
0876:
0877: // =======================================================================
0878:
0879: /**
0880: * The maximum number of children for generic nodes that are
0881: * optimized to hold a fixed number of children.
0882: */
0883: public static final int MAX_FIXED = 8;
0884:
0885: /** The name. */
0886: final String name;
0887:
0888: /** Create a new generic node with the specified name. */
0889: GNode(String name) {
0890: this .name = name;
0891: }
0892:
0893: // =======================================================================
0894:
0895: /**
0896: * Get this generic node's hash code.
0897: *
0898: * @return This node's hash code.
0899: */
0900: public int hashCode() {
0901: int hash = name.hashCode();
0902: int size = size();
0903: for (int i = 0; i < size; i++) {
0904: Object child = get(i);
0905: hash = (37 * hash) + (null == child ? 0 : child.hashCode());
0906: }
0907: return hash;
0908: }
0909:
0910: /**
0911: * Determine whether this generic node equals the specified object.
0912: * This node equals the object, if both are generic nodes with the
0913: * same names and the same number of equal children.
0914: *
0915: * @param o The object to compare to.
0916: * @return <code>true</code> if this generic node equals the object.
0917: */
0918: public boolean equals(Object o) {
0919: if (this == o)
0920: return true;
0921: if (!(o instanceof GNode))
0922: return false;
0923: GNode other = (GNode) o;
0924: if (!name.equals(other.name))
0925: return false;
0926: int size = size();
0927: if (other.size() != size)
0928: return false;
0929: for (int i = 0; i < size; i++) {
0930: Object child1 = get(i);
0931: Object child2 = other.get(i);
0932: if (!(null == child1 ? null == child2 : child1
0933: .equals(child2)))
0934: return false;
0935: }
0936: return true;
0937: }
0938:
0939: // =======================================================================
0940:
0941: /**
0942: * Determine whether this node is generic.
0943: *
0944: * @return <code>true</code>.
0945: */
0946: public final boolean isGeneric() {
0947: return true;
0948: }
0949:
0950: public final boolean hasTraversal() {
0951: return true;
0952: }
0953:
0954: public final String getName() {
0955: return name;
0956: }
0957:
0958: public final boolean hasName(String name) {
0959: return this .name.equals(name);
0960: }
0961:
0962: // =======================================================================
0963:
0964: /**
0965: * Create a new generic node with the specified name. The new node
0966: * supports a variable number of children and has a default
0967: * capacity.
0968: *
0969: * @param name The name.
0970: * @return The corresponding generic node.
0971: */
0972: public static GNode create(String name) {
0973: return new Variable(name);
0974: }
0975:
0976: /**
0977: * Create a new generic node with the specified name. The new node
0978: * supports a variable number of children and has the specified
0979: * capacity.
0980: *
0981: * @param name The name.
0982: * @param capacity The initial capacity.
0983: * @return The corresponding generic node.
0984: * @throws IllegalArgumentException
0985: * Signals that the capacity is negative.
0986: */
0987: public static GNode create(String name, int capacity) {
0988: return new Variable(name, capacity);
0989: }
0990:
0991: /**
0992: * Create a new generic node with the specified name. Invoking this
0993: * method with a true variable flag is equivalent to invoking {@link
0994: * #create(String)}. Invoking this method with a false variabel
0995: * flag results in a generic node with no children.
0996: *
0997: * @param name The name.
0998: * @param variable Flag for whether the new node supports a variable
0999: * number of children.
1000: * @return The corresponding generic node.
1001: */
1002: public static GNode create(String name, boolean variable) {
1003: if (variable) {
1004: return new Variable(name);
1005: } else {
1006: return new Fixed0(name);
1007: }
1008: }
1009:
1010: /**
1011: * Create a new generic node with the specified name and child. The
1012: * new node does not support a variable number of children.
1013: *
1014: * @param name The name.
1015: * @param child The child.
1016: * @return The corresponding generic node.
1017: */
1018: public static GNode create(String name, Object child) {
1019: return new Fixed1(name, child);
1020: }
1021:
1022: /**
1023: * Create a new generic node with the specified name and children.
1024: * The new node does not support a variable number of children.
1025: *
1026: * @param name The name.
1027: * @param c1 The first child.
1028: * @param c2 The second child.
1029: * @return The corresponding generic node.
1030: */
1031: public static GNode create(String name, Object c1, Object c2) {
1032: return new Fixed2(name, c1, c2);
1033: }
1034:
1035: /**
1036: * Create a new generic node with the specified name and children.
1037: * The new node does not support a variable number of children.
1038: *
1039: * @param name The name.
1040: * @param c1 The first child.
1041: * @param c2 The second child.
1042: * @param c3 The third child.
1043: * @return The corresponding generic node.
1044: */
1045: public static GNode create(String name, Object c1, Object c2,
1046: Object c3) {
1047: return new Fixed3(name, c1, c2, c3);
1048: }
1049:
1050: /**
1051: * Create a new generic node with the specified name and children.
1052: * The new node does not support a variable number of children.
1053: *
1054: * @param name The name.
1055: * @param c1 The first child.
1056: * @param c2 The second child.
1057: * @param c3 The third child.
1058: * @param c4 The fourth child.
1059: * @return The corresponding generic node.
1060: */
1061: public static GNode create(String name, Object c1, Object c2,
1062: Object c3, Object c4) {
1063: return new Fixed4(name, c1, c2, c3, c4);
1064: }
1065:
1066: /**
1067: * Create a new generic node with the specified name and children.
1068: * The new node does not support a variable number of children.
1069: *
1070: * @param name The name.
1071: * @param c1 The first child.
1072: * @param c2 The second child.
1073: * @param c3 The third child.
1074: * @param c4 The fourth child.
1075: * @param c5 The fifth child.
1076: * @return The corresponding generic node.
1077: */
1078: public static GNode create(String name, Object c1, Object c2,
1079: Object c3, Object c4, Object c5) {
1080: return new Fixed5(name, c1, c2, c3, c4, c5);
1081: }
1082:
1083: /**
1084: * Create a new generic node with the specified name and children.
1085: * The new node does not support a variable number of children.
1086: *
1087: * @param name The name.
1088: * @param c1 The first child.
1089: * @param c2 The second child.
1090: * @param c3 The third child.
1091: * @param c4 The fourth child.
1092: * @param c5 The fifth child.
1093: * @param c6 The sixth child.
1094: * @return The corresponding generic node.
1095: */
1096: public static GNode create(String name, Object c1, Object c2,
1097: Object c3, Object c4, Object c5, Object c6) {
1098: return new Fixed6(name, c1, c2, c3, c4, c5, c6);
1099: }
1100:
1101: /**
1102: * Create a new generic node with the specified name and children.
1103: * The new node does not support a variable number of children.
1104: *
1105: * @param name The name.
1106: * @param c1 The first child.
1107: * @param c2 The second child.
1108: * @param c3 The third child.
1109: * @param c4 The fourth child.
1110: * @param c5 The fifth child.
1111: * @param c6 The sixth child.
1112: * @param c7 The seventh child.
1113: * @return The corresponding generic node.
1114: */
1115: public static GNode create(String name, Object c1, Object c2,
1116: Object c3, Object c4, Object c5, Object c6, Object c7) {
1117: return new Fixed7(name, c1, c2, c3, c4, c5, c6, c7);
1118: }
1119:
1120: /**
1121: * Create a new generic node with the specified name and children.
1122: * The new node does not support a variable number of children.
1123: *
1124: * @param name The name.
1125: * @param c1 The first child.
1126: * @param c2 The second child.
1127: * @param c3 The third child.
1128: * @param c4 The fourth child.
1129: * @param c5 The fifth child.
1130: * @param c6 The sixth child.
1131: * @param c7 The seventh child.
1132: * @param c8 The eigth child.
1133: * @return The corresponding generic node.
1134: */
1135: public static GNode create(String name, Object c1, Object c2,
1136: Object c3, Object c4, Object c5, Object c6, Object c7,
1137: Object c8) {
1138: return new Fixed8(name, c1, c2, c3, c4, c5, c6, c7, c8);
1139: }
1140:
1141: /**
1142: * Create a new generic node with the list's nodes as its children.
1143: * If possible, this method returns a fixed size node.
1144: *
1145: * @param name The name.
1146: * @param p The list of children.
1147: * @return The corresponding generic node.
1148: */
1149: public static GNode createFromPair(String name, Pair p) {
1150: final int size = p.size();
1151: Object c1 = null;
1152: Object c2 = null;
1153: Object c3 = null;
1154: Object c4 = null;
1155: Object c5 = null;
1156: Object c6 = null;
1157: Object c7 = null;
1158: Object c8 = null;
1159:
1160: switch (size) {
1161: case 8:
1162: c1 = p.head();
1163: p = p.tail();
1164: // Fall through.
1165: case 7:
1166: c2 = p.head();
1167: p = p.tail();
1168: // Fall through.
1169: case 6:
1170: c3 = p.head();
1171: p = p.tail();
1172: // Fall through.
1173: case 5:
1174: c4 = p.head();
1175: p = p.tail();
1176: // Fall through.
1177: case 4:
1178: c5 = p.head();
1179: p = p.tail();
1180: // Fall through.
1181: case 3:
1182: c6 = p.head();
1183: p = p.tail();
1184: // Fall through.
1185: case 2:
1186: c7 = p.head();
1187: p = p.tail();
1188: // Fall through.
1189: case 1:
1190: c8 = p.head();
1191: // Fall through.
1192: case 0:
1193: // Done.
1194: break;
1195: default:
1196: Variable result = new Variable(name, size);
1197: result.addAll(p);
1198: return result;
1199: }
1200:
1201: switch (size) {
1202: case 8:
1203: return new Fixed8(name, c1, c2, c3, c4, c5, c6, c7, c8);
1204: case 7:
1205: return new Fixed7(name, c2, c3, c4, c5, c6, c7, c8);
1206: case 6:
1207: return new Fixed6(name, c3, c4, c5, c6, c7, c8);
1208: case 5:
1209: return new Fixed5(name, c4, c5, c6, c7, c8);
1210: case 4:
1211: return new Fixed4(name, c5, c6, c7, c8);
1212: case 3:
1213: return new Fixed3(name, c6, c7, c8);
1214: case 2:
1215: return new Fixed2(name, c7, c8);
1216: case 1:
1217: return new Fixed1(name, c8);
1218: case 0:
1219: return new Fixed0(name);
1220: default:
1221: throw new AssertionError("Internal error");
1222: }
1223: }
1224:
1225: /**
1226: * Create a new generic node with the specified children. If
1227: * possible, this method returns a fixed size node.
1228: *
1229: * @param name The name.
1230: * @param base The first child.
1231: * @param rest The rest of the children.
1232: * @return The corresponding generic node.
1233: */
1234: public static GNode createFromPair(String name, Object base,
1235: Pair rest) {
1236: final int size = rest.size();
1237: Object c2 = null;
1238: Object c3 = null;
1239: Object c4 = null;
1240: Object c5 = null;
1241: Object c6 = null;
1242: Object c7 = null;
1243: Object c8 = null;
1244:
1245: switch (size) {
1246: case 7:
1247: c2 = rest.head();
1248: rest = rest.tail();
1249: // Fall through.
1250: case 6:
1251: c3 = rest.head();
1252: rest = rest.tail();
1253: // Fall through.
1254: case 5:
1255: c4 = rest.head();
1256: rest = rest.tail();
1257: // Fall through.
1258: case 4:
1259: c5 = rest.head();
1260: rest = rest.tail();
1261: // Fall through.
1262: case 3:
1263: c6 = rest.head();
1264: rest = rest.tail();
1265: // Fall through.
1266: case 2:
1267: c7 = rest.head();
1268: rest = rest.tail();
1269: // Fall through.
1270: case 1:
1271: c8 = rest.head();
1272: rest = rest.tail();
1273: // Fall through.
1274: case 0:
1275: // Done.
1276: break;
1277: default:
1278: Variable result = new Variable(name, size + 1);
1279: result.add(base);
1280: result.addAll(rest);
1281: return result;
1282: }
1283:
1284: switch (size) {
1285: case 7:
1286: return new Fixed8(name, base, c2, c3, c4, c5, c6, c7, c8);
1287: case 6:
1288: return new Fixed7(name, base, c3, c4, c5, c6, c7, c8);
1289: case 5:
1290: return new Fixed6(name, base, c4, c5, c6, c7, c8);
1291: case 4:
1292: return new Fixed5(name, base, c5, c6, c7, c8);
1293: case 3:
1294: return new Fixed4(name, base, c6, c7, c8);
1295: case 2:
1296: return new Fixed3(name, base, c7, c8);
1297: case 1:
1298: return new Fixed2(name, base, c8);
1299: case 0:
1300: return new Fixed1(name, base);
1301: default:
1302: throw new AssertionError("Internal error");
1303: }
1304: }
1305:
1306: /**
1307: * Create a new generic node that is a (shallow) copy of the
1308: * specified node.
1309: *
1310: * @param node The node to copy.
1311: * @return The copy.
1312: */
1313: public static GNode create(GNode node) {
1314: if (node instanceof Variable) {
1315: return new Variable((Variable) node);
1316: } else {
1317: switch (node.size()) {
1318: case 0:
1319: return new Fixed0((Fixed0) node);
1320: case 1:
1321: return new Fixed1((Fixed1) node);
1322: case 2:
1323: return new Fixed2((Fixed2) node);
1324: case 3:
1325: return new Fixed3((Fixed3) node);
1326: case 4:
1327: return new Fixed4((Fixed4) node);
1328: case 5:
1329: return new Fixed5((Fixed5) node);
1330: case 6:
1331: return new Fixed6((Fixed6) node);
1332: case 7:
1333: return new Fixed7((Fixed7) node);
1334: case 8:
1335: return new Fixed8((Fixed8) node);
1336: default:
1337: throw new AssertionError("Internal error");
1338: }
1339: }
1340: }
1341:
1342: // =======================================================================
1343:
1344: /**
1345: * Ensure that the specified node supports a variable number of
1346: * children.
1347: *
1348: * @param node The generic node.
1349: * @return A shallow copy of the specified node if it does not
1350: * support a variable number of children; otherwise, the specified
1351: * node.
1352: */
1353: public static GNode ensureVariable(GNode node) {
1354: if (node instanceof Variable) {
1355: return node;
1356: } else {
1357: ArrayList<Object> children = new ArrayList<Object>(node
1358: .size());
1359: node.addAllTo(children);
1360: return new Variable(node.name, children);
1361: }
1362: }
1363:
1364: /**
1365: * Test whether the specified object is a generic node, possibly
1366: * wrapped in annotations.
1367: *
1368: * @param o The object.
1369: * @return <code>true</code> if the object is a possibly annotated
1370: * generic node.
1371: */
1372: public static final boolean test(Object o) {
1373: return ((o instanceof Node) && ((Node) o).strip().isGeneric());
1374: }
1375:
1376: /**
1377: * Cast the specified object to a generic node. If the specified
1378: * object has any {@link Annotation annotations}, they are {@link
1379: * Node#strip() stripped} before returning the object as a generic
1380: * node.
1381: *
1382: * @see #test(Object)
1383: *
1384: * @param o The object.
1385: * @return The object as a stripped generic node.
1386: */
1387: public static final GNode cast(Object o) {
1388: Node n = (Node) o;
1389: return (null == n) ? null : (GNode) n.strip();
1390: }
1391:
1392: }
|