checkpoint
[sbp.git] / src / edu / berkeley / sbp / misc / ReflectiveGrammar.java
1 package edu.berkeley.sbp.misc;
2 import java.io.*;
3 import java.util.*;
4 import java.lang.reflect.*;
5 import edu.berkeley.sbp.*;
6 import edu.berkeley.sbp.misc.*;
7 import edu.berkeley.sbp.tib.*;
8 import edu.berkeley.sbp.chr.*;
9 import edu.berkeley.sbp.util.*;
10
11 public class ReflectiveGrammar extends MetaGrammar {
12
13     final Class baseClass;
14     public ReflectiveGrammar(Class baseClass) { this.baseClass = baseClass; }
15
16     public Object convertLabel(String label) { return new ClassMark(label); }
17
18     private static class ClassMark {
19         public final String clazz;
20         public ClassMark(String clazz) { this.clazz = clazz; }
21         public String toString() { return clazz+"$"; }
22     }
23
24     public String stringify(Tree<Object> t) throws Exception {
25         StringBuffer ret = new StringBuffer();
26         for(int i=0; i<t.numChildren(); i++) {
27             Tree<Object> child = t.child(i);
28             Object head = child.numChildren() > 0 ? buildHead(child, String.class) : child.head();
29             if (head!=null) ret.append(head);
30         }
31         return ret.toString();
32     }
33
34     public Object build(Tree<Object> t) throws Exception { return buildHead(t, null); }
35     public Object buildHead(Tree<Object> t, Class c) throws Exception {
36         System.out.println("buildHead " + (c==null?null:c.getName()) + " " + t);
37         Object h = t.head();
38
39         if (h != null && h instanceof ClassMark) return buildBody(t, Class.forName(baseClass.getName()+"$"+((ClassMark)h).clazz));
40         if (c.isArray()) {
41             Object[] ret = new Object[t.numChildren()];
42             for(int i=0; i<ret.length; i++)
43                 ret[i] = buildHead(t.child(i), c.getComponentType());
44             return Reflection.lub(ret);
45         }
46         if (h==null)                return buildBody(t, c);
47         
48         if (c==String.class) return stringify(t);
49         if (c==int.class)    return new Integer(stringify(t));
50
51         if (t.numChildren() > 0) throw new RuntimeException("can't buildHead() on a tree with children when the head is of type " + h.getClass().getName());
52         return h;
53     }
54
55     public Object buildBody(Tree<Object> t, Class c) throws Exception {
56         System.out.println("buildBody " + (c==null?null:c.getName()) + " " + t);
57         c = resolveClass(t, c);
58         Object o = c.newInstance();
59         Field[] f = c.getFields();
60         OUTER: for(int i=0; i<t.numChildren(); i++) {
61             Object label = t.label(i);
62             Field field = null;
63             if (label!=null) try { field = c.getField(label+""); } catch (NoSuchFieldException _) { }
64             if (field==null && label != null)
65                 for(Method m : c.getMethods())
66                     if (m.getName().equals(label)) {
67                         m.invoke(o, new Object[] { buildHead(t.child(i), m.getParameterTypes()[0]) });
68                         continue OUTER;
69                     }
70             if (field==null) System.err.println("warning: skipping field " + label + " ("+i+") on class " + c.getName());
71             else {
72                 Object tgt = Reflection.rebuild(buildHead(t.child(i), field.getType()), field.getType());
73                 if (tgt instanceof Object[]) tgt = Reflection.lub(tgt);
74                 System.err.println("setting field " + field.getName() + " on " + c.getName() + " to " + tgt);
75                 try {
76                     field.set(o, tgt);
77                 } catch (Exception e) {
78                     e.printStackTrace();
79                 }
80             }
81         }
82         return o;
83     }
84
85     public Class resolveClass(Tree<Object> t, Class c) throws Exception {
86         if (c==null) return null;
87         System.out.println("resolving " + c.getName());
88         if (Reflection.isConcrete(c)) return c;
89         Class ret = null;
90         Class[] subs = (Class[])c.getField("subclasses").get(null);
91         OUTER: for(int i=0; i<subs.length; i++) {
92             System.err.println("trying " + subs[i].getName());
93             for(int j=0; j<t.numChildren(); j++)
94                 if (Reflection.getField(subs[i], t.label(j)+"")==null) {
95                     System.err.println("skipping due to " + t.label(j));
96                     continue OUTER;
97                 }
98             if (ret != null)
99                 throw new RuntimeException("couldn't decide between two classes:\n  " + subs[i].getName() + "\n  " + ret.getName());
100             ret = subs[i];
101         }
102         if (ret==null) throw new RuntimeException("couldn't find a class to match tree: " + t);
103         return ret;
104     }
105
106 }