Mercurial Hosting > luan
comparison src/luan/lib/JavaLib.java @ 37:8a57ebfdfd78
add JavaLib
git-svn-id: https://luan-java.googlecode.com/svn/trunk@38 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Thu, 20 Dec 2012 02:36:07 +0000 |
parents | |
children | e3624b7cd603 |
comparison
equal
deleted
inserted
replaced
36:2a35154aec14 | 37:8a57ebfdfd78 |
---|---|
1 package luan.lib; | |
2 | |
3 import java.lang.reflect.Array; | |
4 import java.lang.reflect.Member; | |
5 import java.lang.reflect.Field; | |
6 import java.lang.reflect.Method; | |
7 import java.lang.reflect.Constructor; | |
8 import java.lang.reflect.Modifier; | |
9 import java.util.Map; | |
10 import java.util.HashMap; | |
11 import java.util.List; | |
12 import java.util.ArrayList; | |
13 import java.util.Iterator; | |
14 import luan.LuaNumber; | |
15 import luan.LuaState; | |
16 import luan.LuaTable; | |
17 import luan.MetatableGetter; | |
18 import luan.LuaException; | |
19 import luan.LuaFunction; | |
20 import luan.LuaJavaFunction; | |
21 | |
22 | |
23 public final class JavaLib { | |
24 | |
25 public static void register(LuaState lua) { | |
26 lua.addMetatableGetter(mg); | |
27 LuaTable module = new LuaTable(); | |
28 LuaTable global = lua.global(); | |
29 global.put("java",module); | |
30 try { | |
31 global.put( "import", new LuaJavaFunction(JavaLib.class.getMethod("importClass",LuaState.class,String.class),null) ); | |
32 module.put( "class", new LuaJavaFunction(JavaLib.class.getMethod("getClass",String.class),null) ); | |
33 } catch(NoSuchMethodException e) { | |
34 throw new RuntimeException(e); | |
35 } | |
36 add( global, "ipairs", Object.class ); | |
37 add( global, "pairs", Object.class ); | |
38 } | |
39 | |
40 private static final LuaTable mt = new LuaTable(); | |
41 static { | |
42 add( mt, "__index", Object.class, Object.class ); | |
43 } | |
44 | |
45 private static void add(LuaTable t,String method,Class<?>... parameterTypes) { | |
46 try { | |
47 t.put( method, new LuaJavaFunction(JavaLib.class.getMethod(method,parameterTypes),null) ); | |
48 } catch(NoSuchMethodException e) { | |
49 throw new RuntimeException(e); | |
50 } | |
51 } | |
52 | |
53 private static final MetatableGetter mg = new MetatableGetter() { | |
54 public LuaTable getMetatable(Object obj) { | |
55 if( obj==null ) | |
56 return null; | |
57 return mt; | |
58 } | |
59 }; | |
60 | |
61 public static Object __index(Object obj,Object key) throws LuaException { | |
62 if( obj instanceof Static ) { | |
63 if( key instanceof String ) { | |
64 String name = (String)key; | |
65 Static st = (Static)obj; | |
66 Class cls = st.cls; | |
67 if( "class".equals(name) ) { | |
68 return cls; | |
69 } else if( "new".equals(name) ) { | |
70 Constructor<?>[] constructors = cls.getConstructors(); | |
71 if( constructors.length > 0 ) { | |
72 if( constructors.length==1 ) { | |
73 return new LuaJavaFunction(constructors[0],null); | |
74 } else { | |
75 List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>(); | |
76 for( Constructor constructor : constructors ) { | |
77 fns.add(new LuaJavaFunction(constructor,null)); | |
78 } | |
79 return new AmbiguousJavaFunction(fns); | |
80 } | |
81 } | |
82 } else { | |
83 List<Member> members = getStaticMembers(cls,name); | |
84 if( !members.isEmpty() ) { | |
85 return member(null,members); | |
86 } | |
87 } | |
88 } | |
89 throw new LuaException("invalid index for java class: "+key); | |
90 } | |
91 Class cls = obj.getClass(); | |
92 if( cls.isArray() ) { | |
93 if( "length".equals(key) ) { | |
94 return Array.getLength(obj); | |
95 } | |
96 if( key instanceof LuaNumber ) { | |
97 LuaNumber n = (LuaNumber)key; | |
98 double d = n.value(); | |
99 int i = (int)d; | |
100 if( d==i ) { | |
101 return Array.get(obj,i); | |
102 } | |
103 } | |
104 throw new LuaException("invalid index for java array: "+key); | |
105 } | |
106 if( key instanceof String ) { | |
107 String name = (String)key; | |
108 if( "instanceof".equals(name) ) { | |
109 return new LuaJavaFunction(instanceOf,new InstanceOf(obj)); | |
110 } else { | |
111 List<Member> members = getMembers(cls,name); | |
112 if( !members.isEmpty() ) { | |
113 return member(obj,members); | |
114 } | |
115 } | |
116 } | |
117 throw new LuaException("invalid index for java object: "+key); | |
118 } | |
119 | |
120 private static Object member(Object obj,List<Member> members) throws LuaException { | |
121 try { | |
122 if( members.size()==1 ) { | |
123 Member member = members.get(0); | |
124 if( member instanceof Field ) { | |
125 Field field = (Field)member; | |
126 Object value = field.get(obj); | |
127 if( value instanceof Number ) { | |
128 Number n = (Number)value; | |
129 value = new LuaNumber(n.doubleValue()); | |
130 } | |
131 return value; | |
132 } else { | |
133 Method method = (Method)member; | |
134 return new LuaJavaFunction(method,obj); | |
135 } | |
136 } else { | |
137 List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>(); | |
138 for( Member member : members ) { | |
139 Method method = (Method)member; | |
140 fns.add(new LuaJavaFunction(method,obj)); | |
141 } | |
142 return new AmbiguousJavaFunction(fns); | |
143 } | |
144 } catch(IllegalAccessException e) { | |
145 throw new RuntimeException(e); | |
146 } | |
147 } | |
148 | |
149 private static Map<Class,Map<String,List<Member>>> memberMap = new HashMap<Class,Map<String,List<Member>>>(); | |
150 | |
151 private static synchronized List<Member> getMembers(Class cls,String name) { | |
152 Map<String,List<Member>> clsMap = memberMap.get(cls); | |
153 if( clsMap == null ) { | |
154 clsMap = new HashMap<String,List<Member>>(); | |
155 for( Field field : cls.getFields() ) { | |
156 String s = field.getName(); | |
157 List<Member> list = clsMap.get(s); | |
158 if( list == null ) { | |
159 list = new ArrayList<Member>(); | |
160 clsMap.put(s,list); | |
161 } | |
162 list.add(field); | |
163 } | |
164 for( Method method : cls.getMethods() ) { | |
165 String s = method.getName(); | |
166 List<Member> list = clsMap.get(s); | |
167 if( list == null ) { | |
168 list = new ArrayList<Member>(); | |
169 clsMap.put(s,list); | |
170 } | |
171 list.add(method); | |
172 } | |
173 memberMap.put(cls,clsMap); | |
174 } | |
175 return clsMap.get(name); | |
176 } | |
177 | |
178 private static synchronized List<Member> getStaticMembers(Class cls,String name) { | |
179 List<Member> staticMembers = new ArrayList<Member>(); | |
180 for( Member m : getMembers(cls,name) ) { | |
181 if( Modifier.isStatic(m.getModifiers()) ) | |
182 staticMembers.add(m); | |
183 } | |
184 return staticMembers; | |
185 } | |
186 | |
187 static class Static { | |
188 final Class cls; | |
189 | |
190 Static(Class cls) { | |
191 this.cls = cls; | |
192 } | |
193 } | |
194 | |
195 public static Static getClass(String name) throws LuaException { | |
196 try { | |
197 return new Static( Class.forName(name) ); | |
198 } catch(ClassNotFoundException e) { | |
199 throw new LuaException(e); | |
200 } | |
201 } | |
202 | |
203 public static void importClass(LuaState lua,String name) throws LuaException { | |
204 lua.global().put( name.substring(name.lastIndexOf('.')+1), getClass(name) ); | |
205 } | |
206 | |
207 static class AmbiguousJavaFunction extends LuaFunction { | |
208 private final Map<Integer,List<LuaJavaFunction>> fnMap = new HashMap<Integer,List<LuaJavaFunction>>(); | |
209 | |
210 AmbiguousJavaFunction(List<LuaJavaFunction> fns) { | |
211 for( LuaJavaFunction fn : fns ) { | |
212 Integer n = fn.getParameterTypes().length; | |
213 List<LuaJavaFunction> list = fnMap.get(n); | |
214 if( list==null ) { | |
215 list = new ArrayList<LuaJavaFunction>(); | |
216 fnMap.put(n,list); | |
217 } | |
218 list.add(fn); | |
219 } | |
220 } | |
221 | |
222 @Override public Object[] call(LuaState lua,Object... args) throws LuaException { | |
223 for( LuaJavaFunction fn : fnMap.get(args.length) ) { | |
224 try { | |
225 return fn.call(lua,args); | |
226 } catch(IllegalArgumentException e) {} | |
227 } | |
228 throw new LuaException("no method matched args"); | |
229 } | |
230 } | |
231 | |
232 | |
233 public static LuaFunction pairs(Object t) throws LuaException { | |
234 if( t instanceof LuaTable ) | |
235 return BasicLib.pairs((LuaTable)t); | |
236 if( t instanceof Map ) { | |
237 @SuppressWarnings("unchecked") | |
238 Map<Object,Object> m = (Map<Object,Object>)t; | |
239 return BasicLib.pairs(m.entrySet().iterator()); | |
240 } | |
241 throw new LuaException( "bad argument #1 to 'pairs' (table or Map expected)" ); | |
242 } | |
243 | |
244 private static class Iter { | |
245 private final Iterator iter; | |
246 private double i = 0.0; | |
247 | |
248 Iter(Iterable t) { | |
249 this.iter = t.iterator(); | |
250 } | |
251 | |
252 public Object[] next() { | |
253 if( !iter.hasNext() ) | |
254 return LuaFunction.EMPTY_RTN ; | |
255 return new Object[]{ new LuaNumber(i++), iter.next() }; | |
256 } | |
257 } | |
258 private static final Method nextIter; | |
259 static { | |
260 try { | |
261 nextIter = Iter.class.getMethod("next"); | |
262 nextIter.setAccessible(true); | |
263 } catch(NoSuchMethodException e) { | |
264 throw new RuntimeException(e); | |
265 } | |
266 } | |
267 | |
268 public static LuaFunction ipairs(Object t) throws LuaException { | |
269 if( t instanceof LuaTable ) | |
270 return BasicLib.ipairs((LuaTable)t); | |
271 if( t instanceof Iterable ) { | |
272 Iter ai = new Iter((Iterable)t); | |
273 return new LuaJavaFunction(nextIter,ai); | |
274 } | |
275 throw new LuaException( "bad argument #1 to 'ipairs' (table or Iterable expected)" ); | |
276 } | |
277 | |
278 | |
279 private static class InstanceOf { | |
280 private final Object obj; | |
281 | |
282 InstanceOf(Object obj) { | |
283 this.obj = obj; | |
284 } | |
285 | |
286 public boolean instanceOf(Static st) { | |
287 return st.cls.isInstance(obj); | |
288 } | |
289 } | |
290 private static final Method instanceOf; | |
291 static { | |
292 try { | |
293 instanceOf = InstanceOf.class.getMethod("instanceOf",Static.class); | |
294 instanceOf.setAccessible(true); | |
295 } catch(NoSuchMethodException e) { | |
296 throw new RuntimeException(e); | |
297 } | |
298 } | |
299 | |
300 } |