9c205d8670c78212a5024cdc3388c5f0690edf80
[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 new TargetMethod(m).makeSequence(p);
74             for(Class c : _inner)
75                 for(Constructor con : c.getConstructors())
76                     if (new TargetConstructor(con).isCompatible(p))
77                         return new TargetConstructor(con).makeSequence(p);
78             for(Class c : _inner)
79                 if (new TargetClass(c).isCompatible(p))
80                     return new TargetClass(c).makeSequence(p);
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 abstract Sequence makeSequence(Production p);
160         public boolean isCompatible(Production p) {
161             tag t = getTag();
162             if (t != null &&
163                 (t.value().equals(p.tag) ||
164                  (t.value().equals("") && p.tag.equals(getName()))))
165                 return buildSequence(p);
166
167             nonterminal n = getNonTerminal();
168             if (n != null &&
169                 (n.value().equals(p.nonTerminal) ||
170                  (n.value().equals("") && p.nonTerminal.equals(getName()))))
171                 return buildSequence(p);
172
173             return false;
174         }
175         public int[] buildSequence(Production p, String[] names, arg[] argtags) {
176             int argTagged = 0;
177             for(int i=0; i<argtags.length; i++)
178                 if (argtags[i] != null)
179                     argTagged++;
180
181             // FIXME: can be smarter here
182             if (names.length==p.count) {
183                 int[] ret = new int[p.count];
184                 for(int i=0; i<p.count; i++) ret[i] = i;
185                 return ret;
186             } else if (argTagged==p.count) {
187                 int[] ret = new int[argTagged];
188                 int j = 0;
189                 for(int i=0; i<argtags.length; i++)
190                     if (argtags[i]!=null)
191                         ret[j++] = i;
192                 return ret;
193             } else {
194                 return null;
195             }
196         }
197     }
198     public static class TargetClass extends Target {
199         public final Class _class;
200         public TargetClass(Class _class) { this._class = _class; }
201         public String getName() { return _class.getSimpleName(); }
202         public tag getTag() { return (tag)_class.getAnnotation(tag.class); }
203         public nonterminal getNonTerminal() { return (nonterminal)_class.getAnnotation(nonterminal.class); }
204         public boolean buildSequence(Production p) {
205             Field[]  f       = _class.getDeclaredFields();
206             String[] names   = new String[f.length];
207             arg[]    argtags = new arg[f.length];
208             for(int i=0; i<f.length; i++) {
209                 names[i]   = f[i].getName();
210                 argtags[i] = f[i].getAnnotation(arg.class);
211             }
212             int[] ret = buildSequence(p, names, argtags);
213             if (ret!=null) return true;
214             for(Constructor c : _class.getConstructors())
215                 if (new TargetConstructor(c).buildSequence(p))
216                     return true;
217             return false;
218         }
219         public Sequence makeSequence(Production p) {
220             return Sequence.rewritingSequence(_class, p.elements, p.labels, p.drops);
221         }
222     }
223     public static class TargetConstructor extends Target {
224         public final Constructor _ctor;
225         public TargetConstructor(Constructor _ctor) { this._ctor = _ctor; }
226         public String getName() { return _ctor.getName(); }
227         public tag getTag() { return (tag)_ctor.getAnnotation(tag.class); }
228         public nonterminal getNonTerminal() { return (nonterminal)_ctor.getAnnotation(nonterminal.class); }
229         public boolean buildSequence(Production p) {
230             Annotation[][] annotations = _ctor.getParameterAnnotations();
231             int len = annotations.length;
232             int ofs = 0;
233             String name = _ctor.getDeclaringClass().getName();
234             if (name.indexOf('$') > name.lastIndexOf('.')) {
235                 len--;
236                 ofs++;
237             }
238             String[] names   = new String[len];
239             arg[]    argtags = new arg[len];
240             for(int i=0; i<names.length; i++)
241                 for(Annotation a : annotations[i+ofs])
242                     if (a instanceof arg)
243                         argtags[i+ofs] = (arg)a;
244             int[] ret = buildSequence(p, names, argtags);
245             if (ret!=null) return true;
246             return false;
247         }
248         public Sequence makeSequence(Production p) {
249             return Sequence.rewritingSequence(_ctor, p.elements, p.labels, p.drops);
250         }
251     }
252     public static class TargetMethod extends Target {
253         public final Method _method;
254         public TargetMethod(Method _method) { this._method = _method; }
255         public String getName() { return _method.getName(); }
256         public tag getTag() { return (tag)_method.getAnnotation(tag.class); }
257         public nonterminal getNonTerminal() { return (nonterminal)_method.getAnnotation(nonterminal.class); }
258         public boolean buildSequence(Production p) {
259             Annotation[][] annotations = _method.getParameterAnnotations();
260             String[] names   = new String[annotations.length];
261             arg[]    argtags = new arg[annotations.length];
262             for(int i=0; i<names.length; i++)
263                 for(Annotation a : annotations[i])
264                     if (a instanceof arg)
265                         argtags[i] = (arg)a;
266             int[] ret = buildSequence(p, names, argtags);
267             if (ret!=null) return true;
268             return false;
269         }
270         public Sequence makeSequence(Production p) {
271             return Sequence.rewritingSequence(_method, p.elements, p.labels, p.drops);
272         }
273     }
274
275     public class MG {
276         public @tag void grammar(Grammar g) { }
277         public @nonterminal void Grammar(NonTerminal[] n) { }
278         public @nonterminal class Grammar {
279             public @arg("NonTerminal") NonTerminal[] nonterminals;
280         }
281         public @nonterminal class NonTerminal {
282             public @arg("Word") String  name;
283             public @arg("RHS")  Seq[][] sequences;
284         }
285
286         public @tag void range(char c) { }
287         public @nonterminal class Range {
288             public @tag("range") Range(char only) { first = only; last = only; }
289             public @arg char first;
290             public @arg char last;
291         }
292         public class El { }
293         public abstract @nonterminal("Sequence") class Seq { }
294         public @tag("&")   Seq and(Sequence s,    Element[] elements) { return null; }
295         public @tag("&~")  Seq andnot(Sequence s, Element[] elements) { return null; }
296         public @tag        Seq ps(Element[] elements) { return null; }
297         public @tag("::")  Seq tag(String tagname, Seq seq) { return null; }
298         public @tag(":")   void colon(String s, Element e) { }
299         public @tag(")")   void close(String foo) { }
300         public @tag("/")   Seq slash(Seq s, Element e) { return null; }
301         public @tag("->")  Seq arrow(Seq s, Element e) { return null; }
302
303         public @tag("nonTerminal") class NonTerminalReference { public @arg String nonTerminal; }
304         public @tag("literal")     class StringLiteral        { public @arg String string; }
305         public @tag("()")          class Epsilon              { }
306         public @tag("{")           class Tree                 { @arg Seq body; }
307         public @tag("[")           class CharClass            { public CharClass(Range[] ranges) { } }
308
309         public @tag("++")  void plusmax(El e) { }
310         public @tag("+")   void plus(El e) { }
311         public @tag("++/") void plusmaxfollow(El e, El sep) { }
312         public @tag("+/")  void plusfollow(El e, El sep) { }
313         public @tag("**")  void starmax(El e) { }
314         public @tag("*")   void star(El e) { }
315         public @tag("**/") void starmaxfollow(El e, El sep) { }
316         public @tag("*/")  void starfollow(El e, El sep) { }
317         public @tag("!")   void bang(El e) { }
318         public @tag("?")   void question(El e) { }
319         public @tag("^")   void caret(String s) { }
320         public @tag("~")   void tilde(El e) { }
321         public @tag("^^")  void doublecaret(El e) { }
322         public @tag("(")   void subexpression(Seq[][] rhs) { }
323
324         public @nonterminal("Word")    String word(String s) { return null; }
325         public @nonterminal("Quoted")  String quoted(String s) { return null; }
326         public @nonterminal("escaped") String c(char c) { return null; }
327         public @tag("\"\"")            String emptystring() { return null; }
328         public @tag("\r")              String lf() { return null; }
329         public @tag("\n")              String cr() { return null; }
330     }
331
332 }