2004/01/03 04:27:27
[org.ibex.core.git] / src / org / xwt / js / JSRegexp.java
index b0359ba..3bb5ab9 100644 (file)
@@ -1,20 +1,22 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt.js;
 
 import gnu.regexp.*;
 
-public class JSRegexp extends JSCallable {
+/** A JavaScript regular expression object */
+public class JSRegexp extends JS {
     private boolean global;
     private RE re;
     private int lastIndex;
     
-    public JSRegexp(Object arg0, Object arg1) throws JS.Exn {
+    public JSRegexp(Object arg0, Object arg1) throws JSExn {
         if(arg0 instanceof JSRegexp) {
             JSRegexp r = (JSRegexp) arg0;
             this.global = r.global;
             this.re = r.re;
             this.lastIndex = r.lastIndex;
         } else {
-            String pattern = arg0.toString();
+            String pattern = (String)arg0;
             String sFlags = null;
             int flags = 0;
             if(arg1 != null) sFlags = (String)arg1;
@@ -24,110 +26,100 @@ public class JSRegexp extends JSCallable {
                     case 'i': flags |= RE.REG_ICASE; break;
                     case 'm': flags |= RE.REG_MULTILINE; break;
                     case 'g': global = true; break;
-                    default: throw new JS.Exn("Invalid flag in regexp \"" + sFlags.charAt(i) + "\"");
+                    default: throw new JSExn("Invalid flag in regexp \"" + sFlags.charAt(i) + "\"");
                 }
             }
             re = newRE(pattern,flags);
-            _put("source",pattern);
-            _put("global",wrapBool(global));
-            _put("ignoreCase",wrapBool(flags & RE.REG_ICASE));
-            _put("multiline",wrapBool(flags & RE.REG_MULTILINE));
+            put("source", pattern);
+            put("global", B(global));
+            put("ignoreCase", B(flags & RE.REG_ICASE));
+            put("multiline", B(flags & RE.REG_MULTILINE));
         }
     }
 
-    public Object call(Object method, JSArray args) throws JS.Exn {
-        if (method.equals("exec")) {
-            return exec(args);
-        } else if (method.equals("test")) {
-            return test(args);
-        } else if (method.equals("toString")) {
-            return toString();
+    public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+        switch(nargs) {
+            case 1: {
+                //#switch(method)
+                case "exec": {
+                    String s = (String)a0;
+                    int start = global ? lastIndex : 0;
+                    if(start < 0 || start >= s.length()) { lastIndex = 0; return null; }
+                    REMatch match = re.getMatch(s,start);
+                    if(global) lastIndex = match == null ? s.length() : match.getEndIndex();
+                    return match == null ? null : matchToExecResult(match,re,s);
+                }
+                case "test": {
+                    String s = (String)a0;
+                    if (!global) return B(re.getMatch(s) != null);
+                    int start = global ? lastIndex : 0;
+                    if(start < 0 || start >= s.length()) { lastIndex = 0; return null; }
+                    REMatch match = re.getMatch(s,start);
+                    lastIndex = match != null ? s.length() : match.getEndIndex();
+                    return B(match != null);
+                }
+                case "toString": return toString(a0);
+                case "stringMatch": return stringMatch(a0,a1);
+                case "stringSearch": return stringSearch(a0,a1);
+                //#end
+                break;
+            }
+            case 2: {
+                //#switch(method)
+                case "stringReplace": return stringReplace(a0, a1,a2);
+                //#end
+                break;
+            }
         }
-        return null;
+        return super.callMethod(method, a0, a1, a2, rest, nargs);
     }
     
-    // gcj bug...
-    public Object get(Object key) { return _get(key); }
-    public void put(Object key,Object value) { _put(key,value); }
-
-    public Object _get(Object key) {
-        if(key.equals("lastIndex")) return new Integer(lastIndex);
+    public Object get(Object key) throws JSExn {
+        //#switch(key)
+        case "exec": return METHOD;
+        case "test": return METHOD;
+        case "toString": return METHOD;
+        case "lastIndex": return N(lastIndex);
+        //#end
         return super.get(key);
     }
     
-    public void _put(Object key, Object value) {
+    public void put(Object key, Object value) throws JSExn {
         if(key.equals("lastIndex")) lastIndex = JS.toNumber(value).intValue();
         super.put(key,value);
     }
-    
-    private Object exec(String s) throws JS.Exn  {
-        int start = global ? lastIndex : 0;
-        if(start < 0 || start >= s.length()) {
-            lastIndex = 0;
-            return null;
-        }
-        
-        REMatch match = re.getMatch(s,start);
-        if(global)
-            lastIndex = match == null ? s.length() : match.getEndIndex();
-        if(match == null)
-            return null;
-        else
-            return matchToExecResult(match,re,s);
-    }
-    
+  
     private static Object matchToExecResult(REMatch match, RE re, String s) {
-        JSObj ret = new JSObj();
-        ret.put("index",new Integer(match.getStartIndex()));
-        ret.put("input",s);
-        int n = re.getNumSubs();
-        ret.put("length",new Integer(n+1));
-        ret.put("0",match.toString());
-        for(int i=1;i<=n;i++)
-            ret.put(Integer.toString(i),match.toString(i));
-        return ret;
-    }
-    
-    
-    private Object exec(JSArray args) throws JS.Exn  {
-        if(args.length() < 1) throw new JS.Exn("Not enough args to exec");
-        String s = args.elementAt(0).toString();
-        return exec(s);
-    }
-    
-    private Object test(JSArray args)  throws JS.Exn {
-        if(args.length() < 1) throw new JS.Exn("Not enough args to match");
-        String s = args.elementAt(0).toString();
-        
-        if(global) {
-            int start = global ? lastIndex : 0;
-            if(start < 0 || start >= s.length()) {
-                lastIndex = 0;
-                return null;
-            }
-        
-            REMatch match = re.getMatch(s,start);
-            lastIndex = match != null ? s.length() : match.getEndIndex();
-            return wrapBool(match != null);
-        } else {
-            return wrapBool(re.getMatch(s) != null);
+        try {
+            JS ret = new JS();
+            ret.put("index", N(match.getStartIndex()));
+            ret.put("input",s);
+            int n = re.getNumSubs();
+            ret.put("length", N(n+1));
+            ret.put("0",match.toString());
+            for(int i=1;i<=n;i++) ret.put(Integer.toString(i),match.toString(i));
+            return ret;
+        } catch (JSExn e) {
+            throw new Error("this should never happen");
         }
     }
     
     public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append('/');
-        sb.append(_get("source"));
-        sb.append('/');
-        if(global) sb.append('g');
-        if(Boolean.TRUE.equals(_get("ignoreCase"))) sb.append('i');
-        if(Boolean.TRUE.equals(_get("multiline"))) sb.append('m');
-        return sb.toString();
+        try {
+            StringBuffer sb = new StringBuffer();
+            sb.append('/');
+            sb.append(get("source"));
+            sb.append('/');
+            if(global) sb.append('g');
+            if(Boolean.TRUE.equals(get("ignoreCase"))) sb.append('i');
+            if(Boolean.TRUE.equals(get("multiline"))) sb.append('m');
+            return sb.toString();
+        } catch (JSExn e) {
+            throw new Error("this should never happen");
+        }
     }
     
-    public static Object stringMatch(Object o, JSArray args) throws JS.Exn {
-        if(args.length() < 1) throw new JS.Exn("not enough args to match");
-        Object arg0 = args.elementAt(0);
+    public static Object stringMatch(Object o, Object arg0) throws JSExn {
         String s = o.toString();
         RE re;
         JSRegexp regexp = null;
@@ -142,41 +134,26 @@ public class JSRegexp extends JSCallable {
             REMatch match = re.getMatch(s);
             return matchToExecResult(match,re,s);
         }
-        if(!regexp.global)
-            return regexp.exec(s);
+        if(!regexp.global) return regexp.callMethod("exec", s, null, null, null, 1);
         
         JSArray ret = new JSArray();
         REMatch[] matches = re.getAllMatches(s);
-        for(int i=0;i<matches.length;i++)
-            ret.addElement(matches[i].toString());
-        if(matches.length > 0)
-            regexp.lastIndex = matches[matches.length-1].getEndIndex();
-        else
-            regexp.lastIndex = s.length();
+        for(int i=0;i<matches.length;i++) ret.addElement(matches[i].toString());
+        regexp.lastIndex = matches.length > 0 ? matches[matches.length-1].getEndIndex() : s.length();
         return ret;
     }
     
-    public static Object stringSearch(Object o, JSArray args) throws JS.Exn  {
-        if(args.length() < 1) throw new JS.Exn("not enough args to match");
-        Object arg0 = args.elementAt(0);
+    public static Object stringSearch(Object o, Object arg0) throws JSExn  {
         String s = o.toString();
-        RE re;
-        if(arg0 instanceof JSRegexp)
-            re = ((JSRegexp)arg0).re;
-        else
-            re = newRE(arg0.toString(),0);
+        RE re = arg0 instanceof JSRegexp ? ((JSRegexp)arg0).re : newRE(arg0.toString(),0);
         REMatch match = re.getMatch(s);
-        if(match == null) return new Integer(-1);
-        return new Integer(match.getStartIndex());
+        return match == null ? N(-1) : N(match.getStartIndex());
     }
     
-    public static Object stringReplace(Object o, JSArray args) throws JS.Exn {
-        if(args.length() < 2) throw new JS.Exn("not enough args to replace");
-        Object arg0 = args.elementAt(0);
-        Object arg1 = args.elementAt(1);
+    public static Object stringReplace(Object o, Object arg0, Object arg1) throws JSExn {
         String s = o.toString();
         RE re;
-        JSCallable replaceFunc = null;
+        JS replaceFunc = null;
         String replaceString = null;
         JSRegexp regexp = null;
         if(arg0 instanceof JSRegexp) {
@@ -185,8 +162,8 @@ public class JSRegexp extends JSCallable {
         } else {
             re = newRE(arg0.toString(),0);
         }
-        if(arg1 instanceof JSCallable)
-            replaceFunc = (JSCallable) arg1;
+        if(arg1 instanceof JS)
+            replaceFunc = (JS) arg1;
         else
             replaceString = arg1.toString();
         REMatch[] matches;
@@ -214,21 +191,35 @@ public class JSRegexp extends JSCallable {
             sb.append(sa,pos,match.getStartIndex()-pos);
             pos = match.getEndIndex();
             if(replaceFunc != null) {
-                // FEATURE: reintroduce
-                throw new JS.Exn("stringReplace() with a replacement function is temporarily disabled");
-                /*
-                JSArray a = new JSArray();
-                a.addElement(match.toString());
-                if(regexp != null) {
-                    int n = re.getNumSubs();
-                    for(int j=1;j<=n;j++)
-                        a.addElement(match.toString(j));
+                int n = (regexp == null ? 0 : re.getNumSubs());
+                int numArgs = 3 + n;
+                Object[] rest = new Object[numArgs - 3];
+                Object a0 = match.toString();
+                Object a1 = null;
+                Object a2 = null;
+                for(int j=1;j<=n;j++)
+                    switch(j) {
+                        case 1: a1 = match.toString(j); break;
+                        case 2: a2 = match.toString(j); break;
+                        default: rest[j - 3] = match.toString(j); break;
+                    }
+                switch(numArgs) {
+                    case 3:
+                        a1 = N(match.getStartIndex());
+                        a2 = s;
+                        break;
+                    case 4:
+                        a2 = N(match.getStartIndex());
+                        rest[0] = s;
+                        break;
+                    default:
+                        rest[rest.length - 2] = N(match.getStartIndex());
+                        rest[rest.length - 1] = s;
                 }
-                a.addElement(new Integer(match.getStartIndex()));
-                a.addElement(s);
-                Object ret = replaceFunc.call(a, null);
-                sb.append(ret.toString());
-                */
+
+                // note: can't perform pausing operations in here
+                sb.append((String)replaceFunc.call(a0, a1, a2, rest, numArgs));
+
             } else {
                 sb.append(mySubstitute(match,replaceString,s));
             }
@@ -280,16 +271,8 @@ public class JSRegexp extends JSCallable {
     }
                     
     
-    public static Object stringSplit(Object o,JSArray args) {
-        String s = o.toString();
-        if(args.length() < 1 || args.elementAt(0) == null || s.length() == 0) {
-            JSArray ret = new JSArray();
-            ret.addElement(s);
-            return ret;
-        }
-        Object arg0 = args.elementAt(0);
-        
-        int limit = args.length() < 2 ? Integer.MAX_VALUE : JS.toInt(args.elementAt(1));
+    public static Object stringSplit(String s, Object arg0, Object arg1, int nargs) {
+        int limit = nargs < 2 ? Integer.MAX_VALUE : JS.toInt(arg1);
         if(limit < 0) limit = Integer.MAX_VALUE;
         if(limit == 0) return new JSArray();
         
@@ -341,21 +324,13 @@ public class JSRegexp extends JSCallable {
         return ret;
     }
     
-    public static RE newRE(String pattern, int flags) throws JS.Exn {
+    public static RE newRE(String pattern, int flags) throws JSExn {
         try {
             return new RE(pattern,flags,RESyntax.RE_SYNTAX_PERL5);
         } catch(REException e) {
-            throw new JS.Exn(e.toString());
+            throw new JSExn(e.toString());
         }
     }
     
-    private static Boolean wrapBool(boolean b) {
-        return b ? Boolean.TRUE : Boolean.FALSE;
-    }
-    
-    private static Boolean wrapBool(int n) {
-        return wrapBool(n != 0);
-    }
-    
     public String typeName() { return "regexp"; }
 }