2003/07/28 23:17:00
[org.ibex.core.git] / src / org / xwt / js / Internal.java
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] 
2
3 package org.xwt.js; 
4 import org.xwt.util.*; 
5
6 /**
7  * Misc static methods used internally by the JS engine
8  */
9 class Internal {
10     // Package Helper Methods //////////////////////////////////////////////////////////////
11
12     private static Object wrapInt(int i) { return new Integer(i); }
13     static Object callMethodOnPrimitive(Object o, Object method, JS.Array args) {
14         int alength = args.length();
15         String s;
16         if(o instanceof Number) {
17             if(method.equals("toFixed")) throw new JS.Exn("toFixed() not implemented");
18             if(method.equals("toExponential")) throw new JS.Exn("toExponential() not implemented");
19             if(method.equals("toPrecision")) throw new JS.Exn("toPrecision() not implemented");
20             if(method.equals("toString")) {
21                 int radix = alength >= 1 ? JS.toInt(args.elementAt(0)) : 10;
22                 return Long.toString(((Number)o).longValue(),radix);
23             }
24         } else if(o instanceof Boolean) {
25             // No methods for Booleans
26         }
27         s = JS.toString(o);
28         int slength = s.length();
29         if(method.equals("substring")) {
30             int a = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
31             int b = alength >= 2 ? JS.toInt(args.elementAt(1)) : slength;
32             if(a > slength) a = slength;
33             if(b > slength) b = slength;
34             if(a < 0) a = 0;
35             if(b < 0) b = 0;
36             if(a > b) { int tmp = a; a = b; b = tmp; }
37             return s.substring(a,b);
38         }
39         if(method.equals("substr")) {
40             int start = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
41             int len = alength >= 2 ? JS.toInt(args.elementAt(1)) : Integer.MAX_VALUE;
42             if(start < 0) start = slength + start;
43             if(start < 0) start = 0;
44             if(len < 0) len = 0;
45             if(len > slength - start) len = slength - start;
46             if(len <= 0) return "";
47             return s.substring(start,start+len);
48         }
49         if(method.equals("charAt")) {
50             int p = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
51             if(p < 0 || p >= slength) return "";
52             return s.substring(p,p+1);
53         }
54         if(method.equals("charCodeAt")) {
55             int p = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
56             if(p < 0 || p >= slength) return new Double(Double.NaN);
57             return wrapInt(s.charAt(p));
58         }
59         if(method.equals("concat")) {
60             StringBuffer sb = new StringBuffer(slength*2).append(s);
61             for(int i=0;i<alength;i++) sb.append(args.elementAt(i));
62             return sb.toString();
63         }
64         if(method.equals("indexOf")) {
65             String search = alength >= 1 ? args.elementAt(0).toString() : "null";
66             int start = alength >= 2 ? JS.toInt(args.elementAt(1)) : 0;
67             // Java's indexOf handles an out of bounds start index, it'll return -1
68             return wrapInt(s.indexOf(search,start));
69         }
70         if(method.equals("lastIndexOf")) {
71             String search = alength >= 1 ? args.elementAt(0).toString() : "null";
72             int start = alength >= 2 ? JS.toInt(args.elementAt(1)) : 0;
73             // Java's indexOf handles an out of bounds start index, it'll return -1
74             return wrapInt(s.lastIndexOf(search,start));            
75         }
76         if(method.equals("match")) {
77             return Regexp.stringMatch(s,args);
78         }
79         if(method.equals("replace")) {
80             return Regexp.stringReplace(s,args);
81         }
82         if(method.equals("search")) {
83             return Regexp.stringSearch(s,args);
84         }
85         if(method.equals("slice")) {
86             int a = alength >= 1 ? JS.toInt(args.elementAt(0)) : 0;
87             int b = alength >= 2 ? JS.toInt(args.elementAt(1)) : slength;
88             if(a < 0) a = slength + a;
89             if(b < 0) b = slength + b;
90             if(a < 0) a = 0;
91             if(b < 0) b = 0;
92             if(a > slength) a = slength;
93             if(b > slength) b = slength;
94             if(a > b) return "";
95             return s.substring(a,b);
96         }
97         if(method.equals("split")){
98             return Regexp.stringSplit(s,args);
99         } 
100         if(method.equals("toLowerCase")) return s.toLowerCase();
101         if(method.equals("toUpperCase")) return s.toUpperCase();
102         if(method.equals("toString")) return s;
103         throw new JS.Exn("Attempted to call non-existent method: " + method);
104     }
105     
106     static Object getFromPrimitive(Object o, Object key) {
107         boolean returnCallable = false;
108         if(o instanceof Boolean) {
109             // no properties for Booleans
110         } else if(o instanceof Number) {
111             if(key.equals("toPrecision") || key.equals("toExponential") || key.equals("toFixed"))
112                 returnCallable = true;
113         }
114         if(!returnCallable) {
115             // the string stuff applies to everything
116             String s = o.toString();
117             
118             if(key.equals("length")) return wrapInt(s.length());
119         
120             // this is sort of ugly, but this list should never change
121             // These should provide a complete (enough) implementation of the ECMA-262 String object
122             if(key.equals("substring") || key.equals("charAt") || key.equals("charCodeAt") || key.equals("concat") ||
123                 key.equals("indexOf") || key.equals("lastIndexOf") || key.equals("match") || key.equals("replace") ||
124                 key.equals("seatch") || key.equals("slice") || key.equals("split") || key.equals("toLowerCase") ||
125                 key.equals("toUpperCase") || key.equals("toString") || key.equals("substr")
126             )
127                 returnCallable = true;
128         }
129         if(returnCallable) {
130             final Object target = o;
131             final String method = key.toString();
132             return new JS.Callable() {
133                 public Object call(JS.Array args) { return callMethodOnPrimitive(target,method,args); }
134             };
135         }
136         return null;
137     }
138     
139     static class CallableStub extends JS.Callable {
140         private Object method;
141         private JS.Obj obj;
142         public CallableStub(JS.Obj obj, Object method) { this.obj = obj; this.method = method; }
143         public Object call(JS.Array args) { return obj.callMethod(method,args,false); }
144     }
145 }