propose-patch
[org.ibex.core.git] / src / org / xwt / util / Grammar.java
1 package org.xwt.util;
2
3 import java.util.*;
4 import java.io.*;
5 import org.xwt.js.*;
6
7 public abstract class Grammar extends JS {
8
9     public JS action = null;
10     public Grammar() { }
11
12     // means we call()ed a Grammar that hasn't been bound to a scope yet
13     public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
14         throw new Error("this should never happen");
15     }
16
17     private static Object NULL = new Object();
18     
19     public abstract int match(String s, int start, Hash v, JSScope scope) throws JSExn;
20     public int matchAndWrite(final String s, final int start, Hash v, JSScope scope, String key) throws JSExn {
21         final Hash v2 = new Hash();
22         final int ret = match(s, start, v2, scope);
23         Object result = ret == -1 ? NULL : action == null ?
24             s.substring(start, ret) :
25             JS.cloneWithNewParentScope(action, new JSScope(scope) {
26                     public Object get(Object key) throws JSExn {
27                         Object val = v2.get(key);
28                         if (val == NULL) return null;
29                         if (val != null) return val;
30                         if (key.equals("whole")) return s.substring(start, ret);
31                         return super.get(key);
32                     }
33                 }).call(null, null, null, null, 0);
34         if (key != null) {
35             Object old = v.get(key);
36             if (old == null || old == NULL) { }
37             else if (old instanceof JSArray) { if (result != NULL) { ((JSArray)old).addElement(result); result = old; } }
38             else if (result != NULL) { JSArray j = new JSArray(); j.addElement(old); j.addElement(result); result = j; }
39             v.put(key, result);
40         }
41         return ret;
42     }
43
44     public static class Alternative extends Grammar {
45         private Grammar r1, r2;
46         public Alternative(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; }
47         public int match(String s, int start, Hash v, JSScope r) throws JSExn {
48             int s1 = r1.match(s, start, v, r);
49             if (s1 != -1) return s1;
50             int s2 = r2.match(s, start, v, r);
51             if (s2 != -1) return s2;
52             return -1;
53         }
54     }
55
56     public static class Juxtaposition extends Grammar {
57         private Grammar r1, r2;
58         public Juxtaposition(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; }
59         public int match(String s, int start, Hash v, JSScope r) throws JSExn {
60             int s1 = r1.match(s, start, v, r);
61             if (s1 == -1) return -1;
62             int s2 = r2.match(s, s1, v, r);
63             if (s2 == -1) return -1;
64             return s2;
65         }
66     }
67
68     public static class Repetition extends Grammar {
69         private Grammar r1;
70         private int min, max;
71         public Repetition(Grammar r1, int min, int max) { this.r1 = r1; this.min = min; this.max = max; }
72         public int match(String s, int start, Hash v, JSScope r) throws JSExn {
73             int i;
74             for(i=0; i<max; i++) {
75                 start = r1.match(s, start, v, r);
76                 if (start == -1) return -1;
77             }
78             if (i < min) return -1;
79             return start;
80         }
81     }
82
83     public static class Literal extends Grammar {
84         String str;
85         public Literal(String str) { this.str = str; }
86         public int match(String s, int start, Hash v, JSScope r) {
87             if (!s.regionMatches(start, str, 0, str.length())) return -1;
88             return start + str.length();
89         }
90     }
91
92     public static class Range extends Grammar {
93         char min, max;
94         public Range(char min, char max) { this.min = min; this.max = max; }
95         public int match(String s, int start, Hash v, JSScope r) throws JSExn {
96             if (!(s.charAt(start) >= min && s.charAt(start) <= max)) return -1;
97             return start + 1;
98         }
99     }
100
101     public static class Reference extends Grammar {
102         String key;
103         public Reference(String key) { this.key = key; }
104         public int match(String s, int start, Hash v, JSScope scope) throws JSExn {
105             return ((Grammar)scope.get(key)).matchAndWrite(s, start, v, scope, key);
106         }
107     }
108 }