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