2004/01/08 05:02:19
[org.ibex.core.git] / src / org / xwt / util / Grammar.java
diff --git a/src/org/xwt/util/Grammar.java b/src/org/xwt/util/Grammar.java
new file mode 100644 (file)
index 0000000..678a63a
--- /dev/null
@@ -0,0 +1,105 @@
+package org.xwt.util;
+
+import java.util.*;
+import java.io.*;
+import org.xwt.js.*;
+
+public abstract class Grammar extends JS {
+
+    public JSFunction action = null;
+    public Grammar() { }
+
+    // means we call()ed a Grammar that hasn't been bound to a scope yet
+    public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+        throw new Error("this should never happen");
+    }
+
+    public abstract int match(String s, int start, Hash v, JSScope scope) throws JSExn;
+    public int matchAndWrite(final String s, final int start, Hash v, JSScope scope, String key) throws JSExn {
+        final Hash v2 = new Hash();
+        final int ret = match(s, start, v2, scope);
+        if (ret == -1) return -1;
+        Object result = action == null ?
+            s.substring(start, ret) :
+            action.cloneWithNewParentScope(new JSScope(scope) {
+                    public Object get(Object key) throws JSExn {
+                        if (v2.get(key) != null) return v2.get(key);
+                        if (key.equals("whole")) return s.substring(start, ret);
+                        return super.get(key);
+                    }
+                }).call(null, null, null, null, 0);
+        if (key != null) {
+            Object old = v.get(key);
+            if (old == null) { }
+            else if (old instanceof JSArray) { ((JSArray)old).addElement(result); result = old; }
+            else { JSArray j = new JSArray(); j.addElement(old); j.addElement(result); result = j; }
+            v.put(key, result);
+        }
+        return ret;
+    }
+
+    public static class Alternative extends Grammar {
+        private Grammar r1, r2;
+        public Alternative(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; }
+        public int match(String s, int start, Hash v, JSScope r) throws JSExn {
+            int s1 = r1.match(s, start, v, r);
+            if (s1 != -1) return s1;
+            int s2 = r2.match(s, start, v, r);
+            if (s2 != -1) return s2;
+            return -1;
+        }
+    }
+
+    public static class Juxtaposition extends Grammar {
+        private Grammar r1, r2;
+        public Juxtaposition(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; }
+        public int match(String s, int start, Hash v, JSScope r) throws JSExn {
+            int s1 = r1.match(s, start, v, r);
+            if (s1 == -1) return -1;
+            int s2 = r2.match(s, s1, v, r);
+            if (s2 == -1) return -1;
+            return s2;
+        }
+    }
+
+    public static class Repetition extends Grammar {
+        private Grammar r1;
+        private int min, max;
+        public Repetition(Grammar r1, int min, int max) { this.r1 = r1; this.min = min; this.max = max; }
+        public int match(String s, int start, Hash v, JSScope r) throws JSExn {
+            int i;
+            for(i=0; i<max; i++) {
+                start = r1.match(s, start, v, r);
+                if (start == -1) return -1;
+            }
+            if (i < min) return -1;
+            return start;
+        }
+    }
+
+    public static class Literal extends Grammar {
+        String str;
+        public Literal(String str) { this.str = str; }
+        public int match(String s, int start, Hash v, JSScope r) {
+            if (!s.regionMatches(start, str, 0, str.length())) return -1;
+            return start + str.length();
+        }
+    }
+
+    public static class Range extends Grammar {
+        char min, max;
+        public Range(char min, char max) { this.min = min; this.max = max; }
+        public int match(String s, int start, Hash v, JSScope r) throws JSExn {
+            if (!(s.charAt(start) >= min && s.charAt(start) <= max)) return -1;
+            return start + 1;
+        }
+    }
+
+    public static class Reference extends Grammar {
+        String key;
+        public Reference(String key) { this.key = key; }
+        public int match(String s, int start, Hash v, JSScope scope) throws JSExn {
+            return ((Grammar)scope.get(key)).matchAndWrite(s, start, v, scope, key);
+        }
+    }
+}