licensing update to APSL 2.0
[org.ibex.js.git] / src / org / ibex / js / JSReflection.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.js; 
6
7 import org.ibex.util.*; 
8 import java.io.*;
9 import java.util.*;
10 import java.lang.reflect.*;
11
12 /** Automatic JS-ification via Reflection (not for use in the core) */
13 public class JSReflection extends JS {
14
15     public static JS wrap(Object o) throws JSExn {
16         if (o == null) return null;
17         if (o instanceof String) return JS.S((String)o);
18         if (o instanceof Boolean) return JS.B(((Boolean)o).booleanValue());
19         if (o instanceof Number) return JS.N((Number)o);
20         if (o instanceof JS) return (JS)o;
21         if (o instanceof Object[]) {
22             // FIXME: get element type here
23         }
24         throw new JSExn("Reflection object tried to return a " + o.getClass().getName());
25     }
26
27     public static class Array extends JS {
28         final Object[] arr;
29         public Array(Object[] arr) { this.arr = arr; }
30         // FEATURE: Add a JSCounterEnumeration
31         public Enumeration keys() throws JSExn {
32             return new Enumeration(null) {
33                 private int n = 0;
34                 public boolean _hasMoreElements() { return n < arr.length; }
35                 public JS _nextElement() {
36                     return n >= arr.length ? null : JS.N(n++);
37                 }
38             };
39         }
40         public JS get(JS key) throws JSExn { return wrap(arr[toInt(key)]); }
41         public void put(JS key, JS val) throws JSExn { throw new JSExn("can't write to org.ibex.js.Reflection.Array's"); }
42     }
43
44     // FIXME public static class Hash { }
45     // FIXME public Enumeration keys() throws JSExn {  }
46
47     public JS get(JS key) throws JSExn {
48         String k = toString(key);
49         try {
50             Field f = this.getClass().getField(k);
51             return wrap(f.get(this));
52         } catch (NoSuchFieldException nfe) {
53         } catch (IllegalAccessException nfe) {
54         } catch (SecurityException nfe) { }
55
56         try {
57             Method[] methods = this.getClass().getMethods();
58             for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(k)) return METHOD;
59         } catch (SecurityException nfe) { }
60         return null;
61     }
62
63     public void put(JS key, JS val) throws JSExn {
64         throw new JSExn("put() not supported yet");
65     }
66
67     public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
68         String k = toString(method);
69         try {
70             Method[] methods = this.getClass().getMethods();
71             for(int j=0; j<methods.length; j++) {
72                 if (methods[j].getName().equals(k) && methods[j].getParameterTypes().length == nargs) {
73                     Object[] args = new Object[nargs];
74                     for(int i = 0; i<args.length; i++) {
75                         if (i==0) args[i] = a0;
76                         else if (i==1) args[i] = a1;
77                         else if (i==2) args[i] = a2;
78                         else args[i] = rest[i-3];
79                     }
80                     return wrap(methods[j].invoke(this, args));
81                 }
82             }
83         } catch (IllegalAccessException nfe) {
84         } catch (InvocationTargetException it) {
85             Throwable ite = it.getTargetException();
86             if (ite instanceof JSExn) throw ((JSExn)ite);
87             JS.warn(ite);
88             throw new JSExn("unhandled reflected exception: " + ite.toString());
89         } catch (SecurityException nfe) { }
90         throw new JSExn("called a reflection method with the wrong number of arguments");
91     }
92