checkpoint
[sbp.git] / src / edu / berkeley / sbp / misc / ReflectiveGrammar.java
diff --git a/src/edu/berkeley/sbp/misc/ReflectiveGrammar.java b/src/edu/berkeley/sbp/misc/ReflectiveGrammar.java
new file mode 100644 (file)
index 0000000..ecf186d
--- /dev/null
@@ -0,0 +1,106 @@
+package edu.berkeley.sbp.misc;
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+import edu.berkeley.sbp.*;
+import edu.berkeley.sbp.misc.*;
+import edu.berkeley.sbp.tib.*;
+import edu.berkeley.sbp.chr.*;
+import edu.berkeley.sbp.util.*;
+
+public class ReflectiveGrammar extends MetaGrammar {
+
+    final Class baseClass;
+    public ReflectiveGrammar(Class baseClass) { this.baseClass = baseClass; }
+
+    public Object convertLabel(String label) { return new ClassMark(label); }
+
+    private static class ClassMark {
+        public final String clazz;
+        public ClassMark(String clazz) { this.clazz = clazz; }
+        public String toString() { return clazz+"$"; }
+    }
+
+    public String stringify(Tree<Object> t) throws Exception {
+        StringBuffer ret = new StringBuffer();
+        for(int i=0; i<t.numChildren(); i++) {
+            Tree<Object> child = t.child(i);
+            Object head = child.numChildren() > 0 ? buildHead(child, String.class) : child.head();
+            if (head!=null) ret.append(head);
+        }
+        return ret.toString();
+    }
+
+    public Object build(Tree<Object> t) throws Exception { return buildHead(t, null); }
+    public Object buildHead(Tree<Object> t, Class c) throws Exception {
+        System.out.println("buildHead " + (c==null?null:c.getName()) + " " + t);
+        Object h = t.head();
+
+        if (h != null && h instanceof ClassMark) return buildBody(t, Class.forName(baseClass.getName()+"$"+((ClassMark)h).clazz));
+        if (c.isArray()) {
+            Object[] ret = new Object[t.numChildren()];
+            for(int i=0; i<ret.length; i++)
+                ret[i] = buildHead(t.child(i), c.getComponentType());
+            return Reflection.lub(ret);
+        }
+        if (h==null)                return buildBody(t, c);
+        
+        if (c==String.class) return stringify(t);
+        if (c==int.class)    return new Integer(stringify(t));
+
+        if (t.numChildren() > 0) throw new RuntimeException("can't buildHead() on a tree with children when the head is of type " + h.getClass().getName());
+        return h;
+    }
+
+    public Object buildBody(Tree<Object> t, Class c) throws Exception {
+        System.out.println("buildBody " + (c==null?null:c.getName()) + " " + t);
+        c = resolveClass(t, c);
+        Object o = c.newInstance();
+        Field[] f = c.getFields();
+        OUTER: for(int i=0; i<t.numChildren(); i++) {
+            Object label = t.label(i);
+            Field field = null;
+            if (label!=null) try { field = c.getField(label+""); } catch (NoSuchFieldException _) { }
+            if (field==null && label != null)
+                for(Method m : c.getMethods())
+                    if (m.getName().equals(label)) {
+                        m.invoke(o, new Object[] { buildHead(t.child(i), m.getParameterTypes()[0]) });
+                        continue OUTER;
+                    }
+            if (field==null) System.err.println("warning: skipping field " + label + " ("+i+") on class " + c.getName());
+            else {
+                Object tgt = Reflection.rebuild(buildHead(t.child(i), field.getType()), field.getType());
+                if (tgt instanceof Object[]) tgt = Reflection.lub(tgt);
+                System.err.println("setting field " + field.getName() + " on " + c.getName() + " to " + tgt);
+                try {
+                    field.set(o, tgt);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return o;
+    }
+
+    public Class resolveClass(Tree<Object> t, Class c) throws Exception {
+        if (c==null) return null;
+        System.out.println("resolving " + c.getName());
+        if (Reflection.isConcrete(c)) return c;
+        Class ret = null;
+        Class[] subs = (Class[])c.getField("subclasses").get(null);
+        OUTER: for(int i=0; i<subs.length; i++) {
+            System.err.println("trying " + subs[i].getName());
+            for(int j=0; j<t.numChildren(); j++)
+                if (Reflection.getField(subs[i], t.label(j)+"")==null) {
+                    System.err.println("skipping due to " + t.label(j));
+                    continue OUTER;
+                }
+            if (ret != null)
+                throw new RuntimeException("couldn't decide between two classes:\n  " + subs[i].getName() + "\n  " + ret.getName());
+            ret = subs[i];
+        }
+        if (ret==null) throw new RuntimeException("couldn't find a class to match tree: " + t);
+        return ret;
+    }
+
+}