- private boolean match(Method m, String s) { return match(m.getAnnotation(tag.class), null, s); }
- private boolean match(tag t, Class c, String s) {
- if (t==null) return false;
- if (t.value().equals(s)) return true;
- if (c != null && t.equals("") && c.getSimpleName().equals(s)) return true;
- return false;
- }
- private boolean match(nonterminal t, Class c, String s) {
- if (t==null) return false;
- if (t.value().equals(s)) return true;
- if (c != null && t.equals("") && c.getSimpleName().equals(s)) return true;
- return false;
- }
- private boolean match(Class c, String s, String nonTerminalName) {
- if (match((tag)c.getAnnotation(tag.class), c, s)) return true;
- if (match((nonterminal)c.getAnnotation(nonterminal.class), c, nonTerminalName)) return true;
- return false;
- }
- public boolean match(Constructor con, String s, String nonTerminalName) {
- Class c = con.getDeclaringClass();
- if (match((tag)con.getAnnotation(tag.class), null, s)) return true;
- if (match((nonterminal)con.getAnnotation(nonterminal.class), c, s)) return true;
- return false;
- }
- public Object repeatTag() {
- return new Reducer() {
- public String toString() { return "[**]"; }
- public Object reduce(Tree t) {
- Object[] ret = new Object[t.numChildren()];
- for(int i=0; i<t.numChildren(); i++) {
- Tree tc = t.child(i);
- if (tc.head() != null && tc.head() instanceof Reducer)
- ret[i] = ((Reducer)tc.head()).reduce(tc);
- else if (tc.numChildren() == 0)
- ret[i] = tc.head();
- else {
- System.err.println("FIXME: don't know what to do about " + tc);
- ret[i] = null;
- }
- }
- return ret;
- }
- };
- }
- public Sequence tryResolveTag(String tag, String nonTerminalName, Element[] els, Object[] labels, boolean[] drops) {
- Production p = new Production(tag, nonTerminalName, els, labels, drops);
- for(Method m : _cl.getMethods())
- if (new TargetMethod(m).isCompatible(p))
- return new TargetMethod(m).makeSequence(p);
- for(Class c : _inner)
- for(Constructor con : c.getConstructors())
- if (new TargetConstructor(con).isCompatible(p))
- return new TargetConstructor(con).makeSequence(p);
- for(Class c : _inner)
- if (new TargetClass(c).isCompatible(p))
- return new TargetClass(c).makeSequence(p);
- return null;
- }
- public Sequence resolveTag(String tag, String nonTerminalName, Element[] els, Object[] labels, boolean[] drops) {
- Sequence ret = tryResolveTag(tag, nonTerminalName, els, labels, drops);
- if (ret != null) return ret;
- String message = "could not find a Java method/class/ctor matching tag \""+tag+
- "\", nonterminal \""+nonTerminalName+"\" with " + els.length + " arguments";
- if (harsh) {
- throw new RuntimeException(message);
- } else {
- System.err.println(message);
- return Sequence.rewritingSequence(tag, els, labels, drops);
- }
- }
- }
-
-
- /**
- * Constructors, classes, and methods with this attribute will
- * match every production of the nonterminal called "value()"
- * that is arg-compatible. If value() is undefined, then the
- * class/constructor/method name is used.
- */
- @Retention(RetentionPolicy.RUNTIME) public static @interface nonterminal { String value() default ""; }
-
- /**
- * Constructors, classes, and methods with this attribute will
- * match every tree tagged with "value()" that is arg-compatible.
- * If value() is undefined, then the class/constructor/method
- * name is used.
- */
- @Retention(RetentionPolicy.RUNTIME) public static @interface tag { String value() default ""; }
-
- /**
- * If any parameter to a method or field in a class has a named
- * arg-tag, that parameter/field matches the child of the tree
- * which either has that label or else is a reference to a
- * nonterminal with the corresponding name.
- *
- * The remaining non-named arg-tags match the remaining children
- * of the tree in sequential order.
- *
- * If any arg-tagged parameters/fields remain, the match fails.
- * If there were no arg-tagged parameters-fields, it is as if all
- * of them were non-named and arg-tagged.
- *
- * A method/constructor is arg-compatible if all of its arguments
- * are arg-compatible.
- *
- * A class is arg-compatible if all of its fields are
- * arg-compatible, or if one of its constructors is arg-compatible.
- *
- */
- @Retention(RetentionPolicy.RUNTIME) public static @interface arg { String value() default ""; }
-
- public static class Production {
- public String tag;
- public String nonTerminal;
- public Object[] labels;
- public boolean[] drops;
- public Element[] elements;
- public int count = 0;
- public Production(String tag, String nonTerminal, Element[] elements, Object[] labels, boolean[] drops) {
- this.tag = tag;
- this.elements = elements;
- this.nonTerminal = nonTerminal;
- this.labels = labels;
- this.drops = drops;
- for(int i=0; i<drops.length; i++)
- if (!drops[i])
- count++;
- }
- }
-
- public static abstract class Target {
- public abstract String getName();
- public abstract tag getTag();
- public abstract nonterminal getNonTerminal();
- public abstract int[] buildSequence(Production p);
- public boolean isCompatible(Production p) {
- tag t = getTag();
- if (t != null &&
- (t.value().equals(p.tag) ||
- (t.value().equals("") && p.tag.equals(getName()))))
- return buildSequence(p)!=null;
-
- nonterminal n = getNonTerminal();
- if (n != null &&
- (n.value().equals(p.nonTerminal) ||
- (n.value().equals("") && getName().equals(p.nonTerminal))))
- return buildSequence(p)!=null;
-
- return false;
- }
- public int[] buildSequence(Production p, String[] names, arg[] argtags) {
- int argTagged = 0;
- for(int i=0; i<argtags.length; i++)
- if (argtags[i] != null)
- argTagged++;
-
- // FIXME: can be smarter here
- if (names.length==p.count) {
- int[] ret = new int[p.count];
- for(int i=0; i<p.count; i++) ret[i] = i;
- return ret;
- } else if (argTagged==p.count) {
- int[] ret = new int[argtags.length];
- int j = 0;
- for(int i=0; i<argtags.length; i++)
- ret[i] = argtags[i]==null ? -1 : (j++);
- return ret;
- } else {
- return null;
- }
- }
- public Sequence makeSequence(Production p) {
- return Sequence.rewritingSequence(new TargetReducer(p), p.elements, p.labels, p.drops);
- }
- public abstract Object plant(Object[] fields, int[] map);
- public class TargetReducer implements Reducer {
- private Production p;
- private int[] map;
- public TargetReducer(Production p) {
- this.p = p;
- this.map = buildSequence(p);
- }
- public String toString() { return "reducer-"+Target.this; }
- public Object reduce(Tree t) {
- Object[] objects = new Object[t.numChildren()];
- for(int i=0; i<t.numChildren(); i++) {
- Tree tc = t.child(i);
- if (tc.head() != null && tc.head() instanceof Reducer)
- objects[i] = ((Reducer)tc.head()).reduce(tc);
- else if (tc.numChildren() == 0)
- objects[i] = tc.head();
- else {
- System.err.println("FIXME: don't know what to do about " + tc);
- objects[i] = null;
- }
- }
- System.err.println("input tree: " + t);
- return plant(objects, map);
- }
- }
- }
-
- public static interface Reducer {
- public Object reduce(Tree t);
- }
-
- public static class TargetClass extends Target {
- public final Class _class;
- public TargetClass(Class _class) { this._class = _class; }
- public String getName() { return _class.getSimpleName(); }
- public tag getTag() { return (tag)_class.getAnnotation(tag.class); }
- public nonterminal getNonTerminal() { return (nonterminal)_class.getAnnotation(nonterminal.class); }
- public String toString() { return _class.getSimpleName(); }
- public int[] buildSequence(Production p) {
- Field[] f = _class.getDeclaredFields();
- String[] names = new String[f.length];
- arg[] argtags = new arg[f.length];
- for(int i=0; i<f.length; i++) {
- names[i] = f[i].getName();
- argtags[i] = f[i].getAnnotation(arg.class);
- }
- int[] ret = buildSequence(p, names, argtags);
- if (ret!=null) return ret;
- for(Constructor c : _class.getConstructors())
- if (new TargetConstructor(c).buildSequence(p)!=null)
- return new TargetConstructor(c).buildSequence(p);
- return null;
- }
- public Object plant(Object[] fields, int[] map) {
- try {
- Object ret = _class.newInstance();
- Field[] f = _class.getFields();
- int j = 0;
- for(int i=0; i<f.length; i++)
- if (map[i] != -1) {
- Object tgt = Reflection.lub(fields[map[i]]);
- if (f[i].getType() == String.class) tgt = stringify(tgt);
- // FUGLY
- tgt = coerce(tgt, f[i].getType());
- System.err.println("setting a " + f[i].getType().getName() + " to " + Reflection.show(tgt));
- f[i].set(ret, tgt);
- }
- return ret;
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
- }
-
- public static String stringify(Object o) {
- if (o==null) return "";
- if (!(o instanceof Object[])) return o.toString();
- Object[] arr = (Object[])o;
- StringBuffer ret = new StringBuffer();
- for(int i=0; i<arr.length; i++)
- ret.append(arr[i]);
- return ret.toString();
- }