2003/11/17 01:53:25
[org.ibex.core.git] / src / org / xwt / js / JSScope.java
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] 
2 package org.xwt.js; 
3
4 import org.xwt.util.*; 
5 import java.io.*;
6 import java.util.*;
7
8 /** Implementation of a JavaScript JSScope */
9 public class JSScope extends JSCallable { 
10     private JSScope parentJSScope;
11     private static final Object NULL_PLACEHOLDER = new Object();
12     public JSScope(JSScope parentJSScope) {
13         if (parentJSScope == this) throw new Error("can't make a scope its own parent!");
14         this.parentJSScope = parentJSScope;
15     }
16
17     public boolean isTransparent() { return false; }
18     public void declare(String s) { super.put(s, NULL_PLACEHOLDER); }
19     public JSScope getParentJSScope() { return parentJSScope; }
20     public boolean has(Object key) { return super.get(key) != null; }
21
22     public Object get(Object key) {
23         Object o = super.get(key);
24         if (o != null) return o == NULL_PLACEHOLDER ? null : o;
25         else return parentJSScope == null ? null : parentJSScope.get(key);
26     }
27
28     public void put(Object key, Object val) {
29         if (parentJSScope != null && !has(key)) parentJSScope.put(key, val);
30         else super.put(key, val == null ? NULL_PLACEHOLDER : val);
31     }
32
33     public static class Global extends JSScope {
34         private final static Double NaN = new Double(Double.NaN);
35         private final static Double POSITIVE_INFINITY = new Double(Double.POSITIVE_INFINITY);
36     
37         public Global(JSScope parent) { super(parent); }
38
39         public Object get(Object key) {
40             //#switch(key)
41             case "NaN": return NaN;
42             case "Infinity": return POSITIVE_INFINITY;
43             case "undefined": return null;
44             case "stringFromCharCode": return METHOD;
45             case "parseInt": return METHOD;
46             case "isNaN": return METHOD;
47             case "isFinite": return METHOD;
48             case "decodeURI": return METHOD;
49             case "decodeURIComponent": return METHOD;
50             case "encodeURI": return METHOD;
51             case "encodeURIComponent": return METHOD;
52             case "escape": return METHOD;
53             case "unescape": return METHOD;
54             case "parseInt": return METHOD;
55             //#end
56             return super.get(key);
57         }
58
59         public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) {
60             switch(nargs) {
61                 case 0: {
62                     //#switch(method)
63                     case "stringFromCharCode":
64                         JSArray args = new JSArray();
65                         for(int i=0; i<nargs; i++) args.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
66                         return stringFromCharCode(args);
67                     default: break;
68                     //#end
69                 }
70                 case 1: {
71                     //#switch(method)
72                     case "parseInt": return parseInt(a0, N(0));
73                     case "isNaN": { double d = toDouble(a0); return d == d ? F : T; }
74                     case "isFinite": { double d = toDouble(a0); return (d == d && !Double.isInfinite(d)) ? T : F; }
75                     case "decodeURI": throw new JS.Exn("unimplemented");
76                     case "decodeURIComponent": throw new JS.Exn("unimplemented");
77                     case "encodeURI": throw new JS.Exn("unimplemented");
78                     case "encodeURIComponent": throw new JS.Exn("unimplemented");
79                     case "escape": throw new JS.Exn("unimplemented");
80                     case "unescape": throw new JS.Exn("unimplemented");
81                     default: break;
82                     //#end
83                 }
84                 case 2: {
85                     //#switch(method)
86                     case "parseInt": return parseInt(a0, a1);
87                     default: break;
88                     //#end
89                 }
90             }
91             return super.callMethod(method, a0, a1, a2, rest, nargs);
92         }
93
94         private Object stringFromCharCode(JSArray args) {
95             char buf[] = new char[args.length()];
96             for(int i=0;i<args.length();i++) buf[i] = (char)(JS.toInt(args.elementAt(i)) & 0xffff);
97             return new String(buf);
98         }
99
100         private Object parseInt(Object arg, Object r) {
101             int radix = JS.toInt(r);
102             String s = (String)arg;
103             int start = 0;
104             int length = s.length();
105             int sign = 1;
106             long n = 0;
107             if(radix != 0 && (radix < 2 || radix > 36)) return NaN;
108             while(start < length && Character.isWhitespace(s.charAt(start))) start++;
109             if((length >= start+1) && (s.charAt(start) == '+' || s.charAt(start) == '-')) {
110                 sign = s.charAt(start) == '+' ? 1 : -1;
111                 start++;
112             }
113             if(radix == 0 && length >= start+1 && s.charAt(start) == '0') {
114                 start++;
115                 if(length >= start+1 && (s.charAt(start) == 'x' || s.charAt(start) == 'X')) {
116                     start++;
117                     radix = 16;
118                 } else {
119                     radix = 8;
120                     if(length == start || Character.digit(s.charAt(start+1),8)==-1) return new Integer(0);
121                 }
122             }
123             if(radix == 0) radix = 10;
124             if(length == start || Character.digit(s.charAt(start),radix) == -1) return NaN;
125             // try the fast way first
126             try {
127                 String s2 = start == 0 ? s : s.substring(start);
128                 return new Integer(sign*Integer.parseInt(s2,radix));
129             } catch(NumberFormatException e) { }
130             // fall through to a slower but emca-compliant method
131             for(int i=start;i<length;i++) {
132                 int digit = Character.digit(s.charAt(i),radix);
133                 if(digit < 0) break;
134                 n = n*radix + digit;
135                 if(n < 0) return NaN; // overflow;
136             }
137             if(n <= Integer.MAX_VALUE) return new Integer(sign*(int)n);
138             return new Long((long)sign*n);
139         }
140
141         private Object parseFloat(Object arg) {
142             String s = (String)arg;
143             int start = 0;
144             int length = s.length();
145             while(start < length && Character.isWhitespace(s.charAt(0))) start++;
146             int end = length;
147             // as long as the string has no trailing garbage,this is fast, its slow with
148             // trailing garbage
149             while(start < end) {
150                 try {
151                     return new Double(s.substring(start,length));
152                 } catch(NumberFormatException e) { }
153                 end--;
154             }
155             return NaN;
156         }
157     }
158 }
159