2003/07/05 03:23:21
authorbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:02:47 +0000 (07:02 +0000)
committerbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:02:47 +0000 (07:02 +0000)
darcs-hash:20040130070247-aa32f-a833065fd8321407e92d83822176c0e7567ef034.gz

src/org/xwt/js/Internal.java [new file with mode: 0644]

diff --git a/src/org/xwt/js/Internal.java b/src/org/xwt/js/Internal.java
new file mode 100644 (file)
index 0000000..93aae21
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] 
+
+package org.xwt.js; 
+import org.xwt.util.*; 
+
+/**
+ * Misc static methods used internally by the JS engine
+ */
+class Internal {
+    // Package Helper Methods //////////////////////////////////////////////////////////////
+
+    private static Object wrapInt(int i) { return new Integer(i); }
+    static Object callMethodOnPrimitive(Object o, Object method, JS.Array args) {
+        int alength = args.length();
+        String s;
+        if(o instanceof Number) {
+            if(method.equals("toFixed")) throw new JS.Exn("toFixed() not implemented");
+            if(method.equals("toExponential")) throw new JS.Exn("toExponential() not implemented");
+            if(method.equals("toPrecision")) throw new JS.Exn("toPrecision() not implemented");
+            if(method.equals("toString")) {
+                int radix = alength >= 1 ? JS.toInt(args.elementAt(0)) : 10;
+                return Long.toString(((Number)o).longValue(),radix);
+            }
+        } else if(o instanceof Boolean) {
+            // No methods for Booleans
+        }
+        s = o.toString();
+        int slength = s.length();
+        if(method.equals("substring")) {
+            int a = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
+            int b = alength >= 2 ? JS.toInt(args.elementAt(1)) : slength;
+            if(a > slength) a = slength;
+            if(b > slength) b = slength;
+            if(a < 0) a = 0;
+            if(b < 0) b = 0;
+            if(a > b) { int tmp = a; a = b; b = tmp; }
+            return s.substring(a,b);
+        }
+        if(method.equals("charAt")) {
+            int p = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
+            if(p < 0 || p >= slength) return "";
+            return s.substring(p,p+1);
+        }
+        if(method.equals("charCodeAt")) {
+            int p = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
+            if(p < 0 || p >= slength) return new Double(Double.NaN);
+            return wrapInt(s.charAt(p));
+        }
+        if(method.equals("concat")) {
+            StringBuffer sb = new StringBuffer(slength*2).append(s);
+            for(int i=0;i<alength;i++) sb.append(args.elementAt(i));
+            return sb.toString();
+        }
+        if(method.equals("indexOf")) {
+            String search = alength >= 1 ? args.elementAt(0).toString() : "null";
+            int start = alength >= 2 ? JS.toInt(args.elementAt(1)) : 0;
+            // Java's indexOf handles an out of bounds start index, it'll return -1
+            return wrapInt(s.indexOf(search,start));
+        }
+        if(method.equals("lastIndexOf")) {
+            String search = alength >= 1 ? args.elementAt(0).toString() : "null";
+            int start = alength >= 2 ? JS.toInt(args.elementAt(1)) : 0;
+            // Java's indexOf handles an out of bounds start index, it'll return -1
+            return wrapInt(s.lastIndexOf(search,start));            
+        }
+        if(method.equals("match")) {
+            return Regexp.stringMatch(s,args);
+        }
+        if(method.equals("replace")) {
+            return Regexp.stringReplace(s,args);
+        }
+        if(method.equals("search")) {
+            return Regexp.stringSearch(s,args);
+        }
+        if(method.equals("slice")) {
+            int a = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
+            int b = alength >= 2 ? JS.toInt(args.elementAt(1)) : slength;
+            if(a < 0) a = slength + a;
+            if(b < 0) b = slength + b;
+            if(a < 0) a = 0;
+            if(b < 0) b = 0;
+            if(a > slength) a = slength;
+            if(b > slength) b = slength;
+            if(a > b) return "";
+            return s.substring(a,b);
+        }
+        if(method.equals("split")){
+            return Regexp.stringSplit(s,args);
+        }
+        if(method.equals("toLowerCase")) return s.toLowerCase();
+        if(method.equals("toUpperCase")) return s.toUpperCase();
+        if(method.equals("toString")) return s;
+        throw new JS.Exn("Attempted to call non-existent method: " + method);
+    }
+    
+    static Object getFromPrimitive(Object o, Object key) {
+        boolean returnCallable = false;
+        if(o instanceof Boolean) {
+            // no properties for Booleans
+        } else if(o instanceof Number) {
+            if(key.equals("toPrecision") || key.equals("toExponential") || key.equals("toFixed"))
+                returnCallable = true;
+        }
+        if(!returnCallable) {
+            // the string stuff applies to everything
+            String s = o.toString();
+            
+            if(key.equals("length")) return wrapInt(s.length());
+        
+            // this is sort of ugly, but this list should never change
+            // These should provide a complete (enough) implementation of the ECMA-262 String object
+            if(key.equals("substring") || key.equals("charAt") || key.equals("charCodeAt") || key.equals("concat") ||
+                key.equals("indexOf") || key.equals("lastIndexOf") || key.equals("match") || key.equals("replace") ||
+                key.equals("seatch") || key.equals("slice") || key.equals("split") || key.equals("toLowerCase") ||
+                key.equals("toUpperCase") || key.equals("toString")
+            )
+                returnCallable = true;
+        }
+        if(returnCallable) {
+            final Object target = o;
+            final String method = key.toString();
+            return new JS.Callable() {
+                public Object call(JS.Array args) { return callMethodOnPrimitive(target,method,args); }
+            };
+        }
+        return null;
+    }
+    
+    static class CallableStub extends JS.Callable {
+        private Object method;
+        private JS.Obj obj;
+        public CallableStub(JS.Obj obj, Object method) { this.obj = obj; this.method = method; }
+        public Object call(JS.Array args) { return obj.callMethod(method,args,false); }
+    }
+}