54dc44650dc232d32f30ed6f4fb95373e6f46a39
[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) {
38             super(parent);
39         }
40         public Object get(Object key) {
41             if(key.equals("NaN")) return NaN;
42             if(key.equals("Infinity")) return POSITIVE_INFINITY;
43             if(key.equals("undefined")) return null;
44             return super.get(key);
45         }
46
47         public Object call(Object method, JSArray args) {
48             if (method.equals("stringFromCharCode")) return stringFromCharCode(args);
49             return super.call(method, args);
50         }
51
52         public Object call1(Object method, Object arg0) {
53             //#switch(method)
54             case "parseInt": return parseInt(arg0, N(0));
55             case "isNaN": { double d = toDouble(arg0); return d == d ? F : T; }
56             case "isFinite": { double d = toDouble(arg0); return (d == d && !Double.isInfinite(d)) ? T : F; }
57             case "decodeURI": throw new JS.Exn("unimplemented");
58             case "decodeURIComponent": throw new JS.Exn("unimplemented");
59             case "encodeURI": throw new JS.Exn("unimplemented");
60             case "encodeURIComponent": throw new JS.Exn("unimplemented");
61             case "escape": throw new JS.Exn("unimplemented");
62             case "unescape": throw new JS.Exn("unimplemented");
63             //#end
64             return super.call1(method, arg0);
65         }
66
67         public Object call2(Object method, Object arg1, Object arg2) {
68             if (method.equals("parseInt")) return parseInt(arg1, arg2);
69             return super.call2(method, arg1, arg2);
70         }
71
72         private Object stringFromCharCode(JSArray args) {
73             char buf[] = new char[args.length()];
74             for(int i=0;i<args.length();i++) buf[i] = (char)(JS.toInt(args.elementAt(i)) & 0xffff);
75             return new String(buf);
76         }
77
78         private Object parseInt(Object arg, Object r) {
79             int radix = JS.toInt(r);
80             String s = (String)arg;
81             int start = 0;
82             int length = s.length();
83             int sign = 1;
84             long n = 0;
85             if(radix != 0 && (radix < 2 || radix > 36)) return NaN;
86             while(start < length && Character.isWhitespace(s.charAt(start))) start++;
87             if((length >= start+1) && (s.charAt(start) == '+' || s.charAt(start) == '-')) {
88                 sign = s.charAt(start) == '+' ? 1 : -1;
89                 start++;
90             }
91             if(radix == 0 && length >= start+1 && s.charAt(start) == '0') {
92                 start++;
93                 if(length >= start+1 && (s.charAt(start) == 'x' || s.charAt(start) == 'X')) {
94                     start++;
95                     radix = 16;
96                 } else {
97                     radix = 8;
98                     if(length == start || Character.digit(s.charAt(start+1),8)==-1) return new Integer(0);
99                 }
100             }
101             if(radix == 0) radix = 10;
102             if(length == start || Character.digit(s.charAt(start),radix) == -1) return NaN;
103             // try the fast way first
104             try {
105                 String s2 = start == 0 ? s : s.substring(start);
106                 return new Integer(sign*Integer.parseInt(s2,radix));
107             } catch(NumberFormatException e) { }
108             // fall through to a slower but emca-compliant method
109             for(int i=start;i<length;i++) {
110                 int digit = Character.digit(s.charAt(i),radix);
111                 if(digit < 0) break;
112                 n = n*radix + digit;
113                 if(n < 0) return NaN; // overflow;
114             }
115             if(n <= Integer.MAX_VALUE) return new Integer(sign*(int)n);
116             return new Long((long)sign*n);
117         }
118
119         private Object parseFloat(Object arg) {
120             String s = (String)arg;
121             int start = 0;
122             int length = s.length();
123             while(start < length && Character.isWhitespace(s.charAt(0))) start++;
124             int end = length;
125             // as long as the string has no trailing garbage,this is fast, its slow with
126             // trailing garbage
127             while(start < end) {
128                 try {
129                     return new Double(s.substring(start,length));
130                 } catch(NumberFormatException e) { }
131                 end--;
132             }
133             return NaN;
134         }
135     }
136 }
137