001: /*
002: * Author: Mike Atkinson
003: *
004: * This software has been developed under the copyleft
005: * rules of the GNU General Public License. Please
006: * consult the GNU General Public License for more
007: * details about use and distribution of this software.
008: */
009: package net.sourceforge.jrefactory.ast;
010:
011: import java.util.ArrayList;
012: import java.util.List;
013: import java.util.Vector;
014: import net.sourceforge.jrefactory.parser.JavaParser;
015: import net.sourceforge.jrefactory.parser.JavaParserTreeConstants;
016: import net.sourceforge.jrefactory.parser.JavaParserVisitor;
017: import net.sourceforge.jrefactory.parser.NamedToken;
018: import net.sourceforge.jrefactory.parser.Token;
019:
020: /**
021: * This object is the base class for all items in the AST (abstract syntax tree).
022: *
023: * @author Mike Atkinson
024: * @since jRefactory 2.9.0, created October 16, 2003
025: */
026: public class SimpleNode implements Node {
027:
028: /** Description of the Field */
029: protected Node parent;
030: /** Description of the Field */
031: protected Node[] children;
032: /** Description of the Field */
033: protected int id;
034: /** Description of the Field */
035: protected JavaParser parser;
036: /** Description of the Field */
037: public Vector specials;
038: private int beginLine = -1;
039: private int endLine;
040: private int beginColumn = -1;
041: private int endColumn;
042:
043: private Scope scope;
044:
045: /**
046: * Constructor for the SimpleNode object
047: *
048: * @param i Description of Parameter
049: */
050: public SimpleNode(int i) {
051: id = i;
052: specials = null;
053: }
054:
055: /**
056: * Constructor for the SimpleNode object
057: *
058: * @param parser Description of Parameter
059: * @param i Description of Parameter
060: */
061: public SimpleNode(JavaParser parser, int i) {
062: this (i);
063: this .parser = parser;
064: }
065:
066: /**
067: * Sets the scope attribute of the SimpleNode object
068: *
069: * @param scope The new scope value
070: */
071: public void setScope(Scope scope) {
072: this .scope = scope;
073: }
074:
075: /**
076: * Gets the beginLine attribute of the SimpleNode object
077: *
078: * @return The beginLine value
079: */
080: public int getBeginLine() {
081: if (beginLine != -1) {
082: return beginLine;
083: } else {
084: if ((children != null) && (children.length > 0)) {
085: return ((SimpleNode) children[0]).getBeginLine();
086: } else {
087: throw new RuntimeException(
088: "Unable to determine begining line of Node.");
089: }
090: }
091: }
092:
093: /**
094: * Gets the beginColumn attribute of the SimpleNode object
095: *
096: * @return The beginColumn value
097: */
098: public int getBeginColumn() {
099: if (beginColumn != -1) {
100: return beginColumn;
101: } else {
102: if ((children != null) && (children.length > 0)) {
103: return ((SimpleNode) children[0]).getBeginColumn();
104: } else {
105: throw new RuntimeException(
106: "Unable to determine begining line of Node.");
107: }
108: }
109: }
110:
111: /**
112: * Gets the endLine attribute of the SimpleNode object
113: *
114: * @return The endLine value
115: */
116: public int getEndLine() {
117: return endLine;
118: }
119:
120: /**
121: * Gets the endColumn attribute of the SimpleNode object
122: *
123: * @return The endColumn value
124: */
125: public int getEndColumn() {
126: return endColumn;
127: }
128:
129: /**
130: * Gets the special associated with a particular key
131: *
132: * @param key the key
133: * @return the value
134: */
135: public Token getSpecial(String key) {
136: if ((specials == null) || (key == null)) {
137: return null;
138: }
139:
140: int last = specials.size();
141: for (int ndx = 0; ndx < last; ndx++) {
142: NamedToken named = (NamedToken) specials.elementAt(ndx);
143: if (named.check(key)) {
144: return named.getToken();
145: }
146: }
147:
148: return null;
149: }
150:
151: /**
152: * Is javadoc required?
153: *
154: * @return The required value
155: */
156: public boolean isRequired() {
157: return false;
158: }
159:
160: /**
161: * Gets the scope attribute of the SimpleNode object
162: *
163: * @return The scope value
164: */
165: public Scope getScope() {
166: if (scope == null) {
167: return ((SimpleNode) parent).getScope();
168: }
169: return scope;
170: }
171:
172: /**
173: * Gets the name attribute of the SimpleNode object
174: *
175: * @return The name value
176: */
177: public String getName() {
178: return "";
179: //throw new Error("should not occur");
180: }
181:
182: /**
183: * Gets the image attribute of the SimpleNode object
184: *
185: * @return The image value
186: */
187: public String getImage() {
188: return getName();
189: }
190:
191: /** Description of the Method */
192: public void jjtOpen() {
193: if (parser.token.next != null) {
194: beginLine = parser.token.next.beginLine;
195: beginColumn = parser.token.next.beginColumn;
196: }
197: }
198:
199: /** Description of the Method */
200: public void jjtClose() {
201: if (beginLine == -1
202: && (children == null || children.length == 0)) {
203: beginColumn = parser.token.beginColumn;
204: }
205: if (beginLine == -1) {
206: beginLine = parser.token.beginLine;
207: }
208: endLine = parser.token.endLine;
209: endColumn = parser.token.endColumn;
210: }
211:
212: public void setLineAndColumnInfo(int beginLine, int beginColumn,
213: int endLine, int endColumn) {
214: this .beginLine = beginLine;
215: this .beginColumn = beginColumn;
216: this .endLine = endLine;
217: this .endColumn = endColumn;
218: }
219:
220: /**
221: * A unit test for JUnit
222: *
223: * @param i Description of Parameter
224: */
225: public void testingOnly__setBeginLine(int i) {
226: this .beginLine = i;
227: }
228:
229: /**
230: * A unit test for JUnit
231: *
232: * @param i Description of Parameter
233: */
234: public void testingOnly__setBeginColumn(int i) {
235: this .beginColumn = i;
236: }
237:
238: /**
239: * Return the id for this node
240: *
241: * @return the id
242: */
243: public int jjtGetID() {
244: return id;
245: }
246:
247: /**
248: * Description of the Method
249: *
250: * @param n Description of Parameter
251: */
252: public void jjtSetParent(Node n) {
253: parent = n;
254: }
255:
256: /**
257: * Description of the Method
258: *
259: * @return Description of the Returned Value
260: */
261: public Node jjtGetParent() {
262: return parent;
263: }
264:
265: /**
266: * Description of the Method
267: *
268: * @param n Description of Parameter
269: * @param i Description of Parameter
270: */
271: public void jjtAddChild(Node n, int i) {
272: if (children == null) {
273: children = new Node[i + 1];
274: } else if (i >= children.length) {
275: Node[] c = new Node[i + 1];
276: System.arraycopy(children, 0, c, 0, children.length);
277: children = c;
278: }
279: children[i] = n;
280: n.jjtSetParent(this );
281: }
282:
283: /**
284: * Description of the Method
285: *
286: * @param n Description of Parameter
287: */
288: public void jjtAddFirstChild(Node n) {
289: if (children == null) {
290: children = new Node[1];
291: }
292: children[0] = n;
293: n.jjtSetParent(this );
294: }
295:
296: /**
297: * Insert the node numbered i
298: *
299: * @param n Description of Parameter
300: * @param i The index of the node to remove
301: */
302: public void jjtInsertChild(Node n, int i) {
303: if (children == null) {
304: children = new Node[i + 1];
305: } else {
306: Node[] c = new Node[Math.max(children.length + 1, i + 1)];
307: System.arraycopy(children, 0, c, 0, i);
308: System
309: .arraycopy(children, i, c, i + 1, children.length
310: - i);
311: children = c;
312: }
313:
314: // Store the node
315: children[i] = n;
316: n.jjtSetParent(this );
317: }
318:
319: /**
320: * Description of the Method
321: *
322: * @param i Description of Parameter
323: * @return Description of the Returned Value
324: */
325: public Node jjtGetChild(int i) {
326: return children[i];
327: }
328:
329: /**
330: * This method returns a child node. The children are numbered from zero, left to right.<p>
331: *
332: * Same as jjtGetFirstChild();
333: *
334: * @return Description of the Returned Value
335: */
336: public Node jjtGetFirstChild() {
337: return children[0];
338: }
339:
340: /**
341: * Description of the Method
342: *
343: * @return Description of the Returned Value
344: */
345: public int jjtGetNumChildren() {
346: return (children == null) ? 0 : children.length;
347: }
348:
349: /**
350: * Description of the Method
351: *
352: * @return Description of the Returned Value
353: */
354: public boolean hasAnyChildren() {
355: return ((children != null) && (children.length > 0));
356: }
357:
358: /**
359: * Remove the node numbered i
360: *
361: * @param i The index of the node to remove
362: */
363: public void jjtDeleteChild(int i) {
364: if ((children == null) || (children.length < i) || (i < 0)) {
365: System.out.println("Skipping this delete operation");
366: } else {
367: Node[] c = new Node[children.length - 1];
368: System.arraycopy(children, 0, c, 0, i);
369: System.arraycopy(children, i + 1, c, i, children.length - i
370: - 1);
371: children = c;
372: }
373: }
374:
375: /**
376: * Description of the Method
377: *
378: * @param key Description of Parameter
379: * @param value Description of Parameter
380: */
381: public void addSpecial(String key, Token value) {
382: if (value == null) {
383: return;
384: }
385:
386: if (specials == null) {
387: init();
388: }
389:
390: specials.addElement(new NamedToken(key, value));
391: }
392:
393: /**
394: * Removes a special associated with a key
395: *
396: * @param key the special to remove
397: */
398: public void removeSpecial(String key) {
399: if ((specials == null) || (key == null)) {
400: return;
401: }
402:
403: int last = specials.size();
404: for (int ndx = 0; ndx < last; ndx++) {
405: NamedToken named = (NamedToken) specials.elementAt(ndx);
406: if (named.check(key)) {
407: specials.removeElementAt(ndx);
408: return;
409: }
410: }
411: }
412:
413: /**
414: * Accept the visitor.
415: *
416: * @param visitor Description of Parameter
417: * @param data Description of Parameter
418: * @return Description of the Returned Value
419: */
420: public Object jjtAccept(JavaParserVisitor visitor, Object data) {
421: return visitor.visit(this , data);
422: }
423:
424: /**
425: * Accept the visitor.
426: *
427: * @param visitor Description of Parameter
428: * @param data Description of Parameter
429: * @return Description of the Returned Value
430: */
431: public Object childrenAccept(JavaParserVisitor visitor, Object data) {
432: if (children != null) {
433: for (int i = 0; i < children.length; ++i) {
434: if (children[i] != null) {
435: children[i].jjtAccept(visitor, data);
436: } else {
437: // FIXME warn
438: }
439: }
440: }
441: return data;
442: }
443:
444: /**
445: * You can override these two methods in subclasses of SimpleNode to
446: * customize the way the node appears when the tree is dumped. If
447: * your output uses more than one line you should override
448: * toString(String), otherwise overriding toString() is probably all
449: * you need to do.
450: *
451: * @return Description of the Returned Value
452: */
453: public String toString() {
454: return JavaParserTreeConstants.jjtNodeName[id];
455: }
456:
457: /**
458: * You can override these two methods in subclasses of SimpleNode to
459: * customize the way the node appears when the tree is dumped. If
460: * your output uses more than one line you should override
461: * toString(String), otherwise overriding toString() is probably all
462: * you need to do.
463: *
464: * @param prefix Description of Parameter
465: * @return Description of the Returned Value
466: */
467: public String toString(String prefix) {
468: return prefix + toString();
469: }
470:
471: /**
472: * Dump the node data (including the special tokens) to <code>System.err</code>
473: *
474: * Override this method if you want to customize how the node dumps
475: * out its children.
476: *
477: * @param prefix prefixed to every line of the output
478: */
479: public void dump(String prefix) {
480: System.err.println(dumpString(prefix));
481: }
482:
483: /**
484: * Dump the node data (including the special tokens) to a String.
485: *
486: * @param prefix prefixed to every line of the output
487: * @return dump of the Node data.
488: * @since JRefactory 2.7.00
489: */
490: public String dumpString(String prefix) {
491: StringBuffer sb = new StringBuffer(toString(prefix));
492: sb.append(prefix + "parent=" + parent + "\n");
493: sb.append(prefix + "specials={\n");
494: java.util.Iterator i = specials.iterator();
495: while (i.hasNext()) {
496: sb.append(prefix + " " + i.next() + "\n");
497: }
498: sb.append(prefix + "}\n");
499: dumper(this , sb, prefix + " ");
500: return sb.toString();
501: }
502:
503: /**
504: * Description of the Method
505: *
506: * @param targetType Description of the Parameter
507: * @return Description of the Return Value
508: */
509: public List findChildrenOfType(Class targetType) {
510: List list = new ArrayList();
511: findChildrenOfType(targetType, list);
512: return list;
513: }
514:
515: /**
516: * Description of the Method
517: *
518: * @param targetType Description of the Parameter
519: * @param results Description of the Parameter
520: */
521: public void findChildrenOfType(Class targetType, List results) {
522: findChildrenOfType(this , targetType, results, true);
523: }
524:
525: /**
526: * Description of the Method
527: *
528: * @param targetType Description of the Parameter
529: * @param results Description of the Parameter
530: * @param descendIntoNestedClasses Description of the Parameter
531: */
532: public void findChildrenOfType(Class targetType, List results,
533: boolean descendIntoNestedClasses) {
534: this .findChildrenOfType(this , targetType, results,
535: descendIntoNestedClasses);
536: }
537:
538: /**
539: * Description of the Method
540: *
541: * @return Description of the Returned Value
542: */
543: protected String printModifiers() {
544: return "";
545: }
546:
547: /** Initializes any variables that are not required */
548: protected void init() {
549: if (specials == null) {
550: specials = new Vector();
551: }
552: }
553:
554: /**
555: * Description of the Method
556: *
557: * @param node Description of the Parameter
558: * @param targetType Description of the Parameter
559: * @param results Description of the Parameter
560: * @param descendIntoNestedClasses Description of the Parameter
561: */
562: private void findChildrenOfType(Node node, Class targetType,
563: List results, boolean descendIntoNestedClasses) {
564: if (node.getClass().equals(targetType)) {
565: results.add(node);
566: }
567: if (node.getClass().equals(ASTNestedClassDeclaration.class)
568: && !descendIntoNestedClasses) {
569: return;
570: }
571: if (node.getClass().equals(ASTClassBodyDeclaration.class)
572: && ((ASTClassBodyDeclaration) node)
573: .isAnonymousInnerClass()
574: && !descendIntoNestedClasses) {
575: return;
576: }
577: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
578: Node child = node.jjtGetChild(i);
579: if (child.jjtGetNumChildren() > 0) {
580: findChildrenOfType(child, targetType, results,
581: descendIntoNestedClasses);
582: } else {
583: if (child.getClass().equals(targetType)) {
584: results.add(child);
585: }
586: }
587: }
588: }
589:
590: /**
591: * Description of the Method
592: *
593: * @param node Description of Parameter
594: * @param sb Description of Parameter
595: * @param prefix Description of Parameter
596: */
597: private static void dumper(SimpleNode node, StringBuffer sb,
598: String prefix) {
599: if (node.children != null) {
600: for (int i = 0; i < node.children.length; ++i) {
601: SimpleNode n = (SimpleNode) node.children[i];
602: if (n != null) {
603: sb.append(n.toString(prefix)).append(" ").append(
604: n.getImage());
605: sb.append(n.printModifiers());
606: dumper(n, sb, prefix + " ");
607: }
608: }
609: }
610: }
611:
612: }
|