1 package org.gnunet.seaspider.parser;
3 import java.lang.reflect.Field;
4 import java.util.Enumeration;
5 import java.util.WeakHashMap;
8 * Obtain line number information for any JTB node. Note that
9 * "any" really means any -- we use reflection to overcome the
10 * problem that we do not know the full name of the AST root
11 * (in particular, there maybe multiple AST hierarchies in the
12 * project with multiple root "Node" classes).<p>
14 * Essentially, pass a JTB node to the static "get" method
15 * and (if it is a JTB node and there is source corresponding
16 * to it), a LineNumberInfo object with the scope of the
17 * subtree is returned. Otherwise null.<p>
22 * void semanticError(String message, Node n) {
23 * throw new Error(message + " at " + LineNumberInfo.get(n));
28 * This code is dual licensed under both BSD and LGPL.
30 * @author Christian Grothoff
32 public class LineNumberInfo {
34 private static final Object NULL = new Object();
35 private static final Object SELF = new Object();
36 private static final WeakHashMap<Object, Object> cacheF_ = new WeakHashMap<Object,Object>();
37 private static final WeakHashMap<Object, Object> cacheL_ = new WeakHashMap<Object,Object>();
39 public final int lineStart;
40 public final int lineEnd;
41 public final int colStart;
42 public final int colEnd;
44 public LineNumberInfo(int s, int e, int cs, int ce) {
51 public String toString() {
52 return "["+lineStart+":"+colStart+","+lineEnd+":"+colEnd+"]";
56 * Compute line number information for the given JTB node.
58 * @param o any JTB node (the type should be node, but since this
59 * code handles any JTB AST we cannot hardwire the
60 * type ("Node" -- but which package?)
63 public static LineNumberInfo get(Object o) {
66 Object p = firstMatch(o);
67 Object q = lastMatch(o);
69 int lstart = ((Integer)p.getClass().getField("beginLine").get(p)).intValue();
70 int cstart = ((Integer)p.getClass().getField("beginColumn").get(p)).intValue();
71 int lend = ((Integer)p.getClass().getField("endLine").get(q)).intValue();
72 int cend = ((Integer)p.getClass().getField("endColumn").get(q)).intValue();
73 return new LineNumberInfo(lstart, lend, cstart, cend);
74 } catch (Throwable t) {
75 return null; // failed
79 private static Object firstMatch(Object o) {
80 synchronized(cacheF_) {
81 Object r = cacheF_.get(o);
83 return (r == SELF) ? o : (r == NULL) ? null : r;
85 Object r = firstMatch_(o);
86 synchronized(cacheF_) {
87 cacheF_.put(o, r == o ? SELF : r == null ? NULL : r);
93 private static Object lastMatch(Object o) {
94 synchronized(cacheL_) {
95 Object r = cacheL_.get(o);
97 return (r == SELF) ? o : (r == NULL) ? null : r;
99 Object r = lastMatch_(o);
100 synchronized(cacheL_) {
101 cacheL_.put(o, r == o ? SELF : r == null ? NULL : r);
106 private static Object firstMatch_(Object o) {
109 Class c = o.getClass();
110 if (c.getName().endsWith("NodeToken"))
117 f = c.getField("f" + i);
118 } catch (Throwable t) {
120 if ( (f == null) && (i == 0) && (c.getName().endsWith("NodeChoice")) ) {
121 f = c.getField("choice");
122 } else if ( (f == null) && (i == 0) && (c.getName().endsWith("NodeOptional")) ) {
123 f = c.getField("node");
124 } else if ( (f == null) && (i == 0) ) {
125 // special cases: node sequence, etc.
126 Enumeration e = (Enumeration) c.getMethod("elements").invoke(o);
127 while (e.hasMoreElements()) {
128 Object x = firstMatch(e.nextElement());
134 Object r = firstMatch(f.get(o));
142 } catch (Throwable t) {
147 private static Object lastMatch_(Object o) {
150 Class c = o.getClass();
151 if (c.getName().endsWith("NodeToken"))
160 f = c.getField("f" + i);
161 } catch (Throwable t) {
163 if ( (f == null) && (i == 0) && (c.getName().endsWith("NodeChoice")) ) {
164 f = c.getField("choice");
165 } else if ( (f == null) && (i == 0) && (c.getName().endsWith("NodeOptional")) ) {
166 f = c.getField("node");
167 } else if ( (f == null) && (i == 0) ) {
168 // special cases: node sequence, etc.
169 Enumeration e = (Enumeration) o.getClass().getMethod("elements").invoke(o);
170 while (e.hasMoreElements()) {
171 Object x = lastMatch(e.nextElement());
178 Object r = lastMatch(f.get(o));
186 } catch (Throwable t) {