001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2007 Robert Grimm
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public License
007: * version 2.1 as published by the Free Software Foundation.
008: *
009: * This library 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 GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.tree;
020:
021: import java.util.Collection;
022: import java.util.ArrayList;
023:
024: import xtc.util.Pair;
025:
026: /**
027: * An annotation capturing source code formatting.
028: *
029: * @author Robert Grimm
030: * @version $Revision: 1.2 $
031: */
032: public abstract class Formatting extends Annotation {
033:
034: /** A formatting annotation with one node before the annotated node. */
035: static class Before1 extends Formatting {
036:
037: Object b1;
038:
039: Before1(Object b1, Node node) {
040: super (node);
041: this .b1 = b1;
042: }
043:
044: public int size() {
045: return 2;
046: }
047:
048: public Object get(int index) {
049: switch (index) {
050: case 0:
051: return b1;
052: case 1:
053: return node;
054: default:
055: throw new IndexOutOfBoundsException("Index: " + index
056: + ", Size: 2");
057: }
058: }
059:
060: public Object set(int index, Object value) {
061: Object old;
062:
063: switch (index) {
064: case 0:
065: old = b1;
066: b1 = value;
067: return old;
068: case 1:
069: old = node;
070: node = (Node) value;
071: return old;
072: default:
073: throw new IndexOutOfBoundsException("Index: " + index
074: + ", Size: 2");
075: }
076: }
077:
078: }
079:
080: // =======================================================================
081:
082: /** A formatting annotation with one node after the annotated node. */
083: static class After1 extends Formatting {
084:
085: Object a1;
086:
087: After1(Node node, Object a1) {
088: super (node);
089: this .a1 = a1;
090: }
091:
092: public int size() {
093: return 2;
094: }
095:
096: public Object get(int index) {
097: switch (index) {
098: case 0:
099: return node;
100: case 1:
101: return a1;
102: default:
103: throw new IndexOutOfBoundsException("Index: " + index
104: + ", Size: 2");
105: }
106: }
107:
108: public Object set(int index, Object value) {
109: Object old;
110:
111: switch (index) {
112: case 0:
113: old = node;
114: node = (Node) value;
115: return old;
116: case 1:
117: old = a1;
118: a1 = value;
119: return old;
120: default:
121: throw new IndexOutOfBoundsException("Index: " + index
122: + ", Size: 2");
123: }
124: }
125:
126: }
127:
128: // =======================================================================
129:
130: /**
131: * A formatting annotation with one node before and after the
132: * annotated node.
133: */
134: static class Round1 extends Formatting {
135:
136: Object b1;
137: Object a1;
138:
139: Round1(Object b1, Node node, Object a1) {
140: super (node);
141: this .b1 = b1;
142: this .a1 = a1;
143: }
144:
145: public int size() {
146: return 3;
147: }
148:
149: public Object get(int index) {
150: switch (index) {
151: case 0:
152: return b1;
153: case 1:
154: return node;
155: case 2:
156: return a1;
157: default:
158: throw new IndexOutOfBoundsException("Index: " + index
159: + ", Size: 3");
160: }
161: }
162:
163: public Object set(int index, Object value) {
164: Object old;
165:
166: switch (index) {
167: case 0:
168: old = b1;
169: b1 = value;
170: return old;
171: case 1:
172: old = node;
173: node = (Node) value;
174: return old;
175: case 2:
176: old = a1;
177: a1 = value;
178: return old;
179: default:
180: throw new IndexOutOfBoundsException("Index: " + index
181: + ", Size: 3");
182: }
183: }
184:
185: }
186:
187: // =======================================================================
188:
189: /** A generic formatting annotation. */
190: static class RoundN extends Formatting {
191:
192: private boolean hasNode;
193: private ArrayList<Object> before;
194: private ArrayList<Object> after;
195:
196: public RoundN() {
197: hasNode = false;
198: before = new ArrayList<Object>();
199: after = new ArrayList<Object>();
200: }
201:
202: public boolean hasVariable() {
203: return true;
204: }
205:
206: public void setNode(Node node) {
207: this .node = node;
208: hasNode = true;
209: }
210:
211: public int size() {
212: return hasNode ? before.size() + 1 + after.size() : before
213: .size();
214: }
215:
216: public Object get(int index) {
217: if (!hasNode) {
218: return before.get(index);
219: } else {
220: final int size1 = before.size();
221: final int size2 = after.size();
222: final int total = size1 + 1 + size2;
223:
224: if (0 <= index) {
225: if (index < size1) {
226: return before.get(index);
227: } else if (index == size1) {
228: return node;
229: } else if (index < total) {
230: return after.get(index - size1 - 1);
231: }
232: }
233:
234: throw new IndexOutOfBoundsException("Index: " + index
235: + ", Size: " + total);
236: }
237: }
238:
239: public Object set(int index, Object value) {
240: if (!hasNode) {
241: return before.set(index, value);
242: } else {
243: final int size1 = before.size();
244: final int size2 = after.size();
245: final int total = size1 + 1 + size2;
246:
247: if (0 <= index) {
248: if (index < size1) {
249: return before.set(index, value);
250: } else if (index == size1) {
251: Node old = node;
252: node = (Node) value;
253: return old;
254: } else if (index < total) {
255: return after.set(index - size1 - 1, value);
256: }
257: }
258:
259: throw new IndexOutOfBoundsException("Index: " + index
260: + ", Size: " + total);
261: }
262: }
263:
264: public Node add(Object o) {
265: if (!hasNode) {
266: before.add(o);
267: } else {
268: after.add(o);
269: }
270: return this ;
271: }
272:
273: public Node addNode(Node node) {
274: if (hasNode) {
275: throw new IllegalStateException(
276: "Already has annotated node");
277: }
278:
279: this .node = node;
280: hasNode = true;
281: return this ;
282: }
283:
284: public Node add(int index, Object o) {
285: if (!hasNode) {
286: before.add(index, o);
287: return this ;
288:
289: } else {
290: final int size1 = before.size();
291: final int size2 = after.size();
292: final int total = size1 + 1 + size2;
293:
294: if (0 <= index) {
295: if (index < size1) {
296: before.add(index, o);
297: return this ;
298: } else if (index == size1) {
299: throw new IllegalArgumentException(
300: "Can't add to annotated node");
301: } else if (index < total) {
302: after.add(index - size1 - 1, o);
303: return this ;
304: }
305: }
306:
307: throw new IndexOutOfBoundsException("Index: " + index
308: + ", Size: " + total);
309: }
310: }
311:
312: public Node addAll(Pair<?> p) {
313: if (!hasNode) {
314: p.addTo(before);
315: } else {
316: p.addTo(after);
317: }
318: return this ;
319: }
320:
321: public Node addAll(Collection<?> c) {
322: if (!hasNode) {
323: before.addAll(c);
324: } else {
325: after.addAll(c);
326: }
327: return this ;
328: }
329:
330: public Object remove(int index) {
331: if (!hasNode) {
332: return before.remove(index);
333:
334: } else {
335: final int size1 = before.size();
336: final int size2 = after.size();
337: final int total = size1 + 1 + size2;
338:
339: if (0 <= index) {
340: if (index < size1) {
341: return before.remove(index);
342: } else if (size1 == index) {
343: throw new IllegalArgumentException(
344: "Can't remove annotated node");
345: } else if (index < total) {
346: return after.remove(index - size1 - 1);
347: }
348: }
349:
350: throw new IndexOutOfBoundsException("Index: " + index
351: + ", Size: " + total);
352: }
353: }
354:
355: }
356:
357: // =======================================================================
358:
359: /** Create a new, empty formatting annotation. */
360: Formatting() { /* Nothing to do. */
361: }
362:
363: /**
364: * Create a new formatting annotation for the specified node.
365: *
366: * @param node The node.
367: */
368: Formatting(Node node) {
369: this .node = node;
370: }
371:
372: public boolean hasTraversal() {
373: return true;
374: }
375:
376: // =======================================================================
377:
378: /**
379: * Create a formatting annotation. This method returns an
380: * annotation supporting generic traversal.
381: *
382: * @param before The object before the node.
383: * @param node The annotated node.
384: * @return The formatting annotation.
385: */
386: public static Formatting before1(Object before, Node node) {
387: return new Before1(before, node);
388: }
389:
390: /**
391: * Create a formatting annotation. This method returns an
392: * annotation supporting generic traversal.
393: *
394: * @param node The annotated node.
395: * @param after The object after the node.
396: * @return The formatting annotation.
397: */
398: public static Formatting after1(Node node, Object after) {
399: return new After1(node, after);
400: }
401:
402: /**
403: * Create a formatting annotation. This method returns an
404: * annotation supporting generic traversal.
405: *
406: * @param before The object before the node.
407: * @param node The annotated node.
408: * @param after The object after the node.
409: * @return The formatting annotation.
410: */
411: public static Formatting round1(Object before, Node node,
412: Object after) {
413: return new Round1(before, node, after);
414: }
415:
416: /**
417: * Create a formatting annotation. This method returns an
418: * annotation supporting generic traversal and adding/removing
419: * children. All children added before a call to {@link
420: * #addNode(Node)} or {@link #setNode(Node)} are treated as nodes
421: * preceding the annotated node, and all children added after such a
422: * call are treated as nodes succeeding the annotated node.
423: *
424: * @return The formatting annotation.
425: */
426: public static Formatting variable() {
427: return new RoundN();
428: }
429:
430: }
|