checkpoint
[sbp.git] / src / edu / berkeley / sbp / misc / Demo.java
1 package edu.berkeley.sbp.misc;
2 import edu.berkeley.sbp.util.*;
3 import edu.berkeley.sbp.*;
4 import edu.berkeley.sbp.chr.*;
5 import java.util.*;
6 import java.lang.annotation.*;
7 import java.lang.reflect.*;
8 import java.io.*;
9
10 public class Demo {
11     public static void main(String[] s) throws Exception {
12         Tree<String> res = new CharParser(MetaGrammar.make()).parse(new FileInputStream(s[0])).expand1();
13         
14         MetaGrammar.Meta m =
15             new ReflectiveMeta(MG.class,
16                                new Class[] {
17                                    MG.Grammar.class,
18                                    MG.NonTerminal.class,
19                                    MG.Range.class,
20                                    MG.El.class,
21                                    MG.Seq.class,
22                                    MG.NonTerminalReference.class,
23                                    MG.StringLiteral.class,
24                                    MG.Epsilon.class,
25                                    MG.Tree.class,
26                                    MG.CharClass.class
27                                });
28         MetaGrammar.Meta.MetaGrammarFile mgf = m.new MetaGrammarFile(res);
29         MetaGrammar.BuildContext bc = new MetaGrammar.BuildContext(mgf);
30         Union meta = mgf.get("s").build(bc);
31
32         System.err.println("parsing " + s[1]);
33         res = new CharParser(meta).parse(new FileInputStream(s[1])).expand1();
34
35         System.out.println(res);
36     }
37
38     public static class ReflectiveMeta extends MetaGrammar.Meta {
39         private final Class _cl;
40         private final Class[] _inner;
41         public ReflectiveMeta(Class c, Class[] inner) {
42             this._cl = c;
43             this._inner = inner;
44         }
45         private boolean match(Method m, String s) { return match(m.getAnnotation(tag.class), null, s); }
46         private boolean match(tag t, Class c, String s) {
47             if (t==null) return false;
48             if (t.value().equals(s)) return true;
49             if (c != null && t.equals("") && c.getSimpleName().equals(s)) return true;
50             return false;
51         }
52         private boolean match(nonterminal t, Class c, String s) {
53             if (t==null) return false;
54             if (t.value().equals(s)) return true;
55             if (c != null && t.equals("") && c.getSimpleName().equals(s)) return true;
56             return false;
57         }
58         private boolean match(Class c, String s, String nonTerminalName) {
59             if (match((tag)c.getAnnotation(tag.class), c, s)) return true;
60             if (match((nonterminal)c.getAnnotation(nonterminal.class), c, nonTerminalName)) return true;
61             return false;
62         }
63         public boolean match(Constructor con, String s, String nonTerminalName) {
64             Class c = con.getDeclaringClass();
65             if (match((tag)con.getAnnotation(tag.class), null, s)) return true;
66             if (match((nonterminal)con.getAnnotation(nonterminal.class), c, s)) return true;
67             return false;
68         }
69         public Sequence resolveTag(String tag, String nonTerminalName, Element[] els, Object[] labels, boolean[] drops) {
70             Production p = new Production(tag, nonTerminalName, els, labels, drops);
71             for(Method m : _cl.getMethods())
72                 if (new TargetMethod(m).isCompatible(p))
73                     return Sequence.rewritingSequence(m, els, labels, drops);
74             for(Class c : _inner)
75                 for(Constructor con : c.getConstructors())
76                     if (new TargetConstructor(con).isCompatible(p))
77                         return Sequence.rewritingSequence(con, els, labels, drops);
78             for(Class c : _inner)
79                 if (new TargetClass(c).isCompatible(p))
80                     return Sequence.rewritingSequence(c, els, labels, drops);
81             throw new RuntimeException("could not find a Java method/class/ctor matching tag \""+tag+"\", nonterminal \""+nonTerminalName+"\"");
82         }
83     }
84     /*
85     public static Object makeFlattener(final Method m, final Element[] els, final Object[] labels, final boolean[] drops) {
86         return new Reducer() {
87                 public Object reduce(Tree t) {
88                     Object[] o = new Object[m.getParameterTypes()];
89                     int j = 0;
90                     for(int i=0; i<els.length; i++)
91                 }
92             };
93     }
94     */
95
96     
97     /**
98      *  Constructors, classes, and methods with this attribute will
99      *  match every production of the nonterminal called "value()"
100      *  that is arg-compatible.  If value() is undefined, then the
101      *  class/constructor/method name is used.
102      */ 
103     @Retention(RetentionPolicy.RUNTIME) public static @interface nonterminal { String value() default ""; }
104
105     /**
106      *  Constructors, classes, and methods with this attribute will
107      *  match every tree tagged with "value()" that is arg-compatible.
108      *  If value() is undefined, then the class/constructor/method
109      *  name is used.
110      */ 
111     @Retention(RetentionPolicy.RUNTIME) public static @interface tag         { String value() default ""; }
112
113     /**
114      *  If any parameter to a method or field in a class has a named
115      *  arg-tag, that parameter/field matches the child of the tree
116      *  which either has that label or else is a reference to a
117      *  nonterminal with the corresponding name.
118      *  
119      *  The remaining non-named arg-tags match the remaining children
120      *  of the tree in sequential order.
121      *
122      *  If any arg-tagged parameters/fields remain, the match fails.
123      *  If there were no arg-tagged parameters-fields, it is as if all
124      *  of them were non-named and arg-tagged.
125      *
126      *  A method/constructor is arg-compatible if all of its arguments
127      *  are arg-compatible.
128      *
129      *  A class is arg-compatible if all of its fields are
130      *  arg-compatible, or if one of its constructors is arg-compatible.
131      *
132      */
133     @Retention(RetentionPolicy.RUNTIME) public static @interface arg         { String value() default ""; }
134
135     public static class Production {
136         public String tag;
137         public String nonTerminal;
138         public Object[] labels;
139         public boolean[] drops;
140         public Element[] elements;
141         public int count = 0;
142         public Production(String tag, String nonTerminal, Element[] elements, Object[] labels, boolean[] drops) {
143             this.tag = tag;
144             this.elements = elements; // FIXME: use this
145             this.nonTerminal = nonTerminal;
146             this.labels = labels;
147             this.drops = drops;
148             for(int i=0; i<drops.length; i++)
149                 if (!drops[i])
150                     count++;
151         }
152     }
153
154     public static abstract class Target {
155         public abstract String getName();
156         public abstract tag getTag();
157         public abstract nonterminal getNonTerminal();
158         public abstract boolean buildSequence(Production p);
159         public boolean isCompatible(Production p) {
160             tag t = getTag();
161             if (t != null &&
162                 (t.value().equals(p.tag) ||
163                  (t.value().equals("") && p.tag.equals(getName()))))
164                 return buildSequence(p);
165
166             nonterminal n = getNonTerminal();
167             if (n != null &&
168                 (n.value().equals(p.nonTerminal) ||
169                  (n.value().equals("") && p.nonTerminal.equals(getName()))))
170                 return buildSequence(p);
171
172             return false;
173         }
174         public int[] buildSequence(Production p, String[] names, arg[] argtags) {
175             int argTagged = 0;
176             for(int i=0; i<argtags.length; i++)
177                 if (argtags[i] != null)
178                     argTagged++;
179
180             // FIXME: can be smarter here
181             if (names.length==p.count) {
182                 int[] ret = new int[p.count];
183                 for(int i=0; i<p.count; i++) ret[i] = i;
184                 return ret;
185             } else if (argTagged==p.count) {
186                 int[] ret = new int[argTagged];
187                 int j = 0;
188                 for(int i=0; i<argtags.length; i++)
189                     if (argtags[i]!=null)
190                         ret[j++] = i;
191                 return ret;
192             } else {
193                 return null;
194             }
195         }
196     }
197     public static class TargetClass extends Target {
198         public final Class _class;
199         public TargetClass(Class _class) { this._class = _class; }
200         public String getName() { return _class.getSimpleName(); }
201         public tag getTag() { return (tag)_class.getAnnotation(tag.class); }
202         public nonterminal getNonTerminal() { return (nonterminal)_class.getAnnotation(nonterminal.class); }
203         public boolean buildSequence(Production p) {
204             Field[]  f       = _class.getDeclaredFields();
205             String[] names   = new String[f.length];
206             arg[]    argtags = new arg[f.length];
207             for(int i=0; i<f.length; i++) {
208                 names[i]   = f[i].getName();
209                 argtags[i] = f[i].getAnnotation(arg.class);
210             }
211             int[] ret = buildSequence(p, names, argtags);
212             if (ret!=null) return true;
213             for(Constructor c : _class.getConstructors())
214                 if (new TargetConstructor(c).buildSequence(p))
215                     return true;
216             return false;
217         }
218     }
219     public static class TargetConstructor extends Target {
220         public final Constructor _ctor;
221         public TargetConstructor(Constructor _ctor) { this._ctor = _ctor; }
222         public String getName() { return _ctor.getName(); }
223         public tag getTag() { return (tag)_ctor.getAnnotation(tag.class); }
224         public nonterminal getNonTerminal() { return (nonterminal)_ctor.getAnnotation(nonterminal.class); }
225         public boolean buildSequence(Production p) {
226             Annotation[][] annotations = _ctor.getParameterAnnotations();
227             int len = annotations.length;
228             int ofs = 0;
229             String name = _ctor.getDeclaringClass().getName();
230             if (name.indexOf('$') > name.lastIndexOf('.')) {
231                 len--;
232                 ofs++;
233             }
234             String[] names   = new String[len];
235             arg[]    argtags = new arg[len];
236             for(int i=0; i<names.length; i++)
237                 for(Annotation a : annotations[i+ofs])
238                     if (a instanceof arg)
239                         argtags[i+ofs] = (arg)a;
240             int[] ret = buildSequence(p, names, argtags);
241             if (ret!=null) return true;
242             return false;
243         }
244     }
245     public static class TargetMethod extends Target {
246         public final Method _method;
247         public TargetMethod(Method _method) { this._method = _method; }
248         public String getName() { return _method.getName(); }
249         public tag getTag() { return (tag)_method.getAnnotation(tag.class); }
250         public nonterminal getNonTerminal() { return (nonterminal)_method.getAnnotation(nonterminal.class); }
251         public boolean buildSequence(Production p) {
252             Annotation[][] annotations = _method.getParameterAnnotations();
253             String[] names   = new String[annotations.length];
254             arg[]    argtags = new arg[annotations.length];
255             for(int i=0; i<names.length; i++)
256                 for(Annotation a : annotations[i])
257                     if (a instanceof arg)
258                         argtags[i] = (arg)a;
259             int[] ret = buildSequence(p, names, argtags);
260             if (ret!=null) return true;
261             return false;
262         }
263     }
264
265     public class MG {
266         public @tag void grammar(Grammar g) { }
267         public @nonterminal void Grammar(NonTerminal[] n) { }
268         public @nonterminal class Grammar {
269             public @arg("NonTerminal") NonTerminal[] nonterminals;
270         }
271         public @nonterminal class NonTerminal {
272             public @arg("Word") String  name;
273             public @arg("RHS")  Seq[][] sequences;
274         }
275
276         public @tag void range(char c) { }
277         public @nonterminal class Range {
278             public @tag("range") Range(char only) { first = only; last = only; }
279             public @arg char first;
280             public @arg char last;
281         }
282         public class El { }
283         public abstract @nonterminal("Sequence") class Seq { }
284         public @tag("&")   Seq and(Sequence s,    Element[] elements) { return null; }
285         public @tag("&~")  Seq andnot(Sequence s, Element[] elements) { return null; }
286         public @tag        Seq ps(Element[] elements) { return null; }
287         public @tag("::")  Seq tag(String tagname, Seq seq) { return null; }
288         public @tag(":")   void colon(String s, Element e) { }
289         public @tag(")")   void close(String foo) { }
290         public @tag("/")   Seq slash(Seq s, Element e) { return null; }
291         public @tag("->")  Seq arrow(Seq s, Element e) { return null; }
292
293         public @tag("nonTerminal") class NonTerminalReference { public @arg String nonTerminal; }
294         public @tag("literal")     class StringLiteral        { public @arg String string; }
295         public @tag("()")          class Epsilon              { }
296         public @tag("{")           class Tree                 { @arg Seq body; }
297         public @tag("[")           class CharClass            { public CharClass(Range[] ranges) { } }
298
299         public @tag("++")  void plusmax(El e) { }
300         public @tag("+")   void plus(El e) { }
301         public @tag("++/") void plusmaxfollow(El e, El sep) { }
302         public @tag("+/")  void plusfollow(El e, El sep) { }
303         public @tag("**")  void starmax(El e) { }
304         public @tag("*")   void star(El e) { }
305         public @tag("**/") void starmaxfollow(El e, El sep) { }
306         public @tag("*/")  void starfollow(El e, El sep) { }
307         public @tag("!")   void bang(El e) { }
308         public @tag("?")   void question(El e) { }
309         public @tag("^")   void caret(String s) { }
310         public @tag("~")   void tilde(El e) { }
311         public @tag("^^")  void doublecaret(El e) { }
312         public @tag("(")   void subexpression(Seq[][] rhs) { }
313
314         public @nonterminal("Word")    String word(String s) { return null; }
315         public @nonterminal("Quoted")  String quoted(String s) { return null; }
316         public @nonterminal("escaped") String c(char c) { return null; }
317         public @tag("\"\"")            String emptystring() { return null; }
318         public @tag("\r")              String lf() { return null; }
319         public @tag("\n")              String cr() { return null; }
320     }
321
322 }