comparison src/luan/LuanJavaFunction.java @ 1335:e0cf0d108a77

major cleanup
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 14 Feb 2019 03:10:45 -0700
parents 25746915a241
children 71f067287642
comparison
equal deleted inserted replaced
1334:c88b486a9511 1335:e0cf0d108a77
15 15
16 public final class LuanJavaFunction extends LuanFunction { 16 public final class LuanJavaFunction extends LuanFunction {
17 private final JavaMethod method; 17 private final JavaMethod method;
18 private Object obj; 18 private Object obj;
19 private final RtnConverter rtnConverter; 19 private final RtnConverter rtnConverter;
20 private final boolean takesLuaState; 20 private final boolean takesLuan;
21 private final ArgConverter[] argConverters; 21 private final ArgConverter[] argConverters;
22 private final Class varArgCls; 22 private final Class varArgCls;
23 23
24 public LuanJavaFunction(Method method,Object obj) { 24 public LuanJavaFunction(Luan luan,Method method,Object obj) {
25 this( JavaMethod.of(method), obj ); 25 this( luan, JavaMethod.of(method), obj );
26 } 26 }
27 27
28 public LuanJavaFunction(Constructor constr,Object obj) { 28 public LuanJavaFunction(Luan luan,Constructor constr,Object obj) {
29 this( JavaMethod.of(constr), obj ); 29 this( luan, JavaMethod.of(constr), obj );
30 } 30 }
31 31
32 private LuanJavaFunction(JavaMethod method,Object obj) { 32 private LuanJavaFunction(Luan luan,JavaMethod method,Object obj) {
33 super(luan);
33 this.method = method; 34 this.method = method;
34 this.obj = obj; 35 this.obj = obj;
35 this.rtnConverter = getRtnConverter(method); 36 this.rtnConverter = getRtnConverter(method);
36 this.takesLuaState = takesLuaState(method); 37 this.takesLuan = takesLuan(method);
37 this.argConverters = getArgConverters(takesLuaState,method); 38 this.argConverters = getArgConverters(takesLuan,method);
38 if( method.isVarArgs() ) { 39 if( method.isVarArgs() ) {
39 Class[] paramTypes = method.getParameterTypes(); 40 Class[] paramTypes = method.getParameterTypes();
40 this.varArgCls = paramTypes[paramTypes.length-1].getComponentType(); 41 this.varArgCls = paramTypes[paramTypes.length-1].getComponentType();
41 } else { 42 } else {
42 this.varArgCls = null; 43 this.varArgCls = null;
43 } 44 }
45 if( !takesLuan )
46 dontClone();
44 } 47 }
45 48
46 @Override public String toString() { 49 @Override public String toString() {
47 return "java-function: " + method; 50 return "java-function: " + method;
48 } 51 }
53 56
54 public boolean isVarArgs() { 57 public boolean isVarArgs() {
55 return method.isVarArgs(); 58 return method.isVarArgs();
56 } 59 }
57 60
58 @Override public Object call(Luan luan,Object[] args) throws LuanException { 61 @Override public Object call(Object[] args) throws LuanException {
59 try { 62 try {
60 args = fixArgs(luan,args); 63 args = fixArgs(args);
61 return doCall(luan,args); 64 return doCall(args);
62 } catch(IllegalArgumentException e) { 65 } catch(IllegalArgumentException e) {
63 checkArgs(args); 66 checkArgs(args);
64 throw e; 67 throw e;
65 } 68 }
66 } 69 }
67 70
68 public Object rawCall(Luan luan,Object[] args) throws LuanException { 71 public Object rawCall(Object[] args) throws LuanException {
69 args = fixArgs(luan,args); 72 args = fixArgs(args);
70 return doCall(luan,args); 73 return doCall(args);
71 } 74 }
72 75
73 private Object doCall(Luan luan,Object[] args) throws LuanException { 76 private Object doCall(Object[] args) throws LuanException {
74 Object rtn; 77 Object rtn;
75 try { 78 try {
76 rtn = method.invoke(obj,args); 79 rtn = method.invoke(obj,args);
77 } catch(IllegalAccessException e) { 80 } catch(IllegalAccessException e) {
78 throw new RuntimeException("method = "+method,e); 81 throw new RuntimeException("method = "+method,e);
84 throw (LuanException)cause; 87 throw (LuanException)cause;
85 throw new LuanException(cause); 88 throw new LuanException(cause);
86 } catch(InstantiationException e) { 89 } catch(InstantiationException e) {
87 throw new RuntimeException(e); 90 throw new RuntimeException(e);
88 } 91 }
89 return rtnConverter.convert(luan,rtn); 92 return rtnConverter.convert(rtn);
90 } 93 }
91 94
92 private static final Map primitiveMap = new HashMap(); 95 private static final Map primitiveMap = new HashMap();
93 static { 96 static {
94 primitiveMap.put(Boolean.TYPE,Boolean.class); 97 primitiveMap.put(Boolean.TYPE,Boolean.class);
102 primitiveMap.put(Void.TYPE,Void.class); 105 primitiveMap.put(Void.TYPE,Void.class);
103 } 106 }
104 107
105 private void checkArgs(Object[] args) throws LuanException { 108 private void checkArgs(Object[] args) throws LuanException {
106 Class[] a = method.getParameterTypes(); 109 Class[] a = method.getParameterTypes();
107 int start = takesLuaState ? 1 : 0; 110 int start = takesLuan ? 1 : 0;
108 for( int i=start; i<a.length; i++ ) { 111 for( int i=start; i<a.length; i++ ) {
109 Class paramType = a[i]; 112 Class paramType = a[i];
110 Class type = paramType; 113 Class type = paramType;
111 if( type.isPrimitive() ) 114 if( type.isPrimitive() )
112 type = (Class)primitiveMap.get(type); 115 type = (Class)primitiveMap.get(type);
144 if( type.equals("LuanJavaFunction") ) 147 if( type.equals("LuanJavaFunction") )
145 return "function"; 148 return "function";
146 return type; 149 return type;
147 } 150 }
148 151
149 private Object[] fixArgs(Luan luan,Object[] args) throws LuanException { 152 private Object[] fixArgs(Object[] args) throws LuanException {
150 int n = argConverters.length; 153 int n = argConverters.length;
151 Object[] rtn; 154 Object[] rtn;
152 int start = 0; 155 int start = 0;
153 if( !takesLuaState && varArgCls==null && args.length == n ) { 156 if( !takesLuan && varArgCls==null && args.length == n ) {
154 rtn = args; 157 rtn = args;
155 } else { 158 } else {
156 if( takesLuaState ) 159 if( takesLuan )
157 n++; 160 n++;
158 rtn = new Object[n]; 161 rtn = new Object[n];
159 if( takesLuaState ) { 162 if( takesLuan ) {
160 rtn[start++] = luan; 163 rtn[start++] = luan();
161 } 164 }
162 n = argConverters.length; 165 n = argConverters.length;
163 if( varArgCls == null ) { 166 if( varArgCls == null ) {
164 for( int i=n; i<args.length; i++ ) { 167 for( int i=n; i<args.length; i++ ) {
165 if( args[i] != null ) 168 if( args[i] != null )
172 } else { 175 } else {
173 int len = args.length - n; 176 int len = args.length - n;
174 Object varArgs = Array.newInstance(varArgCls,len); 177 Object varArgs = Array.newInstance(varArgCls,len);
175 ArgConverter ac = argConverters[n]; 178 ArgConverter ac = argConverters[n];
176 for( int i=0; i<len; i++ ) { 179 for( int i=0; i<len; i++ ) {
177 Array.set( varArgs, i, ac.convert(luan,args[n+i]) ); 180 Array.set( varArgs, i, ac.convert(args[n+i]) );
178 } 181 }
179 rtn[rtn.length-1] = varArgs; 182 rtn[rtn.length-1] = varArgs;
180 } 183 }
181 } 184 }
182 System.arraycopy(args,0,rtn,start,Math.min(args.length,n)); 185 System.arraycopy(args,0,rtn,start,Math.min(args.length,n));
183 } 186 }
184 for( int i=0; i<n; i++ ) { 187 for( int i=0; i<n; i++ ) {
185 rtn[start+i] = argConverters[i].convert(luan,rtn[start+i]); 188 rtn[start+i] = argConverters[i].convert(rtn[start+i]);
186 } 189 }
187 return rtn; 190 return rtn;
188 } 191 }
189 192
190 193
191 private interface RtnConverter { 194 private interface RtnConverter {
192 public Object convert(Luan luan,Object obj); 195 public Object convert(Object obj);
193 } 196 }
194 197
195 private static final RtnConverter RTN_NOTHING = new RtnConverter() { 198 private static final RtnConverter RTN_NOTHING = new RtnConverter() {
196 @Override public Object[] convert(Luan luan,Object obj) { 199 @Override public Object[] convert(Object obj) {
197 return NOTHING; 200 return NOTHING;
198 } 201 }
199 }; 202 };
200 203
201 private static final RtnConverter RTN_SAME = new RtnConverter() { 204 private static final RtnConverter RTN_SAME = new RtnConverter() {
202 @Override public Object convert(Luan luan,Object obj) { 205 @Override public Object convert(Object obj) {
203 return obj; 206 return obj;
204 } 207 }
205 }; 208 };
206 209 /*
207 private static final RtnConverter RTN_ARRAY = new RtnConverter() { 210 private static final RtnConverter RTN_ARRAY = new RtnConverter() {
208 @Override public Object convert(Luan luan,Object obj) { 211 @Override public Object convert(Luan luan,Object obj) {
209 if( obj == null ) 212 if( obj == null )
210 return null; 213 return null;
211 Object[] a = new Object[Array.getLength(obj)]; 214 Object[] a = new Object[Array.getLength(obj)];
213 a[i] = Array.get(obj,i); 216 a[i] = Array.get(obj,i);
214 } 217 }
215 return new LuanTable(luan,new ArrayList<Object>(Arrays.asList(a))); 218 return new LuanTable(luan,new ArrayList<Object>(Arrays.asList(a)));
216 } 219 }
217 }; 220 };
218 221 */
219 private static RtnConverter getRtnConverter(JavaMethod m) { 222 private static RtnConverter getRtnConverter(JavaMethod m) {
220 Class rtnType = m.getReturnType(); 223 Class rtnType = m.getReturnType();
221 if( rtnType == Void.TYPE ) 224 if( rtnType == Void.TYPE )
222 return RTN_NOTHING; 225 return RTN_NOTHING;
226 /*
223 if( !m.isLuan() && rtnType.isArray() && !rtnType.getComponentType().isPrimitive() ) { 227 if( !m.isLuan() && rtnType.isArray() && !rtnType.getComponentType().isPrimitive() ) {
224 return RTN_ARRAY; 228 return RTN_ARRAY;
225 } 229 }
230 */
226 return RTN_SAME; 231 return RTN_SAME;
227 } 232 }
228 233
229 private interface ArgConverter { 234 private interface ArgConverter {
230 public Object convert(Luan luan,Object obj) throws LuanException; 235 public Object convert(Object obj) throws LuanException;
231 } 236 }
232 237
233 private static final ArgConverter ARG_SAME = new ArgConverter() { 238 private static final ArgConverter ARG_SAME = new ArgConverter() {
234 public Object convert(Luan luan,Object obj) { 239 @Override public Object convert(Object obj) {
235 return obj; 240 return obj;
236 } 241 }
237 @Override public String toString() { 242 @Override public String toString() {
238 return "ARG_SAME"; 243 return "ARG_SAME";
239 } 244 }
240 }; 245 };
241 246
242 private static final ArgConverter ARG_DOUBLE = new ArgConverter() { 247 private static final ArgConverter ARG_DOUBLE = new ArgConverter() {
243 public Object convert(Luan luan,Object obj) { 248 @Override public Object convert(Object obj) {
244 if( obj instanceof Double ) 249 if( obj instanceof Double )
245 return obj; 250 return obj;
246 if( obj instanceof Number ) { 251 if( obj instanceof Number ) {
247 Number n = (Number)obj; 252 Number n = (Number)obj;
248 return n.doubleValue(); 253 return n.doubleValue();
253 return "ARG_DOUBLE"; 258 return "ARG_DOUBLE";
254 } 259 }
255 }; 260 };
256 261
257 private static final ArgConverter ARG_FLOAT = new ArgConverter() { 262 private static final ArgConverter ARG_FLOAT = new ArgConverter() {
258 public Object convert(Luan luan,Object obj) { 263 @Override public Object convert(Object obj) {
259 if( obj instanceof Float ) 264 if( obj instanceof Float )
260 return obj; 265 return obj;
261 if( obj instanceof Number ) { 266 if( obj instanceof Number ) {
262 Number n = (Number)obj; 267 Number n = (Number)obj;
263 return n.floatValue(); 268 return n.floatValue();
268 return "ARG_FLOAT"; 273 return "ARG_FLOAT";
269 } 274 }
270 }; 275 };
271 276
272 private static final ArgConverter ARG_LONG = new ArgConverter() { 277 private static final ArgConverter ARG_LONG = new ArgConverter() {
273 public Object convert(Luan luan,Object obj) { 278 @Override public Object convert(Object obj) {
274 if( obj instanceof Long ) 279 if( obj instanceof Long )
275 return obj; 280 return obj;
276 if( obj instanceof Number ) { 281 if( obj instanceof Number ) {
277 Number n = (Number)obj; 282 Number n = (Number)obj;
278 long r = n.longValue(); 283 long r = n.longValue();
285 return "ARG_LONG"; 290 return "ARG_LONG";
286 } 291 }
287 }; 292 };
288 293
289 private static final ArgConverter ARG_INTEGER = new ArgConverter() { 294 private static final ArgConverter ARG_INTEGER = new ArgConverter() {
290 public Object convert(Luan luan,Object obj) { 295 @Override public Object convert(Object obj) {
291 if( obj instanceof Integer ) 296 if( obj instanceof Integer )
292 return obj; 297 return obj;
293 if( obj instanceof Number ) { 298 if( obj instanceof Number ) {
294 Number n = (Number)obj; 299 Number n = (Number)obj;
295 int r = n.intValue(); 300 int r = n.intValue();
302 return "ARG_INTEGER"; 307 return "ARG_INTEGER";
303 } 308 }
304 }; 309 };
305 310
306 private static final ArgConverter ARG_SHORT = new ArgConverter() { 311 private static final ArgConverter ARG_SHORT = new ArgConverter() {
307 public Object convert(Luan luan,Object obj) { 312 @Override public Object convert(Object obj) {
308 if( obj instanceof Short ) 313 if( obj instanceof Short )
309 return obj; 314 return obj;
310 if( obj instanceof Number ) { 315 if( obj instanceof Number ) {
311 Number n = (Number)obj; 316 Number n = (Number)obj;
312 short r = n.shortValue(); 317 short r = n.shortValue();
319 return "ARG_SHORT"; 324 return "ARG_SHORT";
320 } 325 }
321 }; 326 };
322 327
323 private static final ArgConverter ARG_BYTE = new ArgConverter() { 328 private static final ArgConverter ARG_BYTE = new ArgConverter() {
324 public Object convert(Luan luan,Object obj) { 329 @Override public Object convert(Object obj) {
325 if( obj instanceof Byte ) 330 if( obj instanceof Byte )
326 return obj; 331 return obj;
327 if( obj instanceof Number ) { 332 if( obj instanceof Number ) {
328 Number n = (Number)obj; 333 Number n = (Number)obj;
329 byte r = n.byteValue(); 334 byte r = n.byteValue();
334 } 339 }
335 @Override public String toString() { 340 @Override public String toString() {
336 return "ARG_BYTE"; 341 return "ARG_BYTE";
337 } 342 }
338 }; 343 };
339 344 /*
340 private static final ArgConverter ARG_TABLE = new ArgConverter() { 345 private static final ArgConverter ARG_TABLE = new ArgConverter() {
341 public Object convert(Luan luan,Object obj) { 346 @Override public Object convert(Luan luan,Object obj) {
342 LuanTable tbl = luan.toTable(obj); 347 LuanTable tbl = luan.toTable(obj);
343 return tbl!=null ? tbl : obj; 348 return tbl!=null ? tbl : obj;
344 } 349 }
345 @Override public String toString() { 350 @Override public String toString() {
346 return "ARG_TABLE"; 351 return "ARG_TABLE";
347 } 352 }
348 }; 353 };
349 354 */
350 private static final ArgConverter ARG_MAP = new ArgConverter() { 355 private static final ArgConverter ARG_MAP = new ArgConverter() {
351 public Object convert(Luan luan,Object obj) throws LuanException { 356 @Override public Object convert(Object obj) throws LuanException {
352 if( obj instanceof LuanTable ) { 357 if( obj instanceof LuanTable ) {
353 LuanTable t = (LuanTable)obj; 358 LuanTable t = (LuanTable)obj;
354 return t.asMap(); 359 return t.asMap();
355 } 360 }
356 return obj; 361 return obj;
359 return "ARG_MAP"; 364 return "ARG_MAP";
360 } 365 }
361 }; 366 };
362 367
363 private static final ArgConverter ARG_LIST = new ArgConverter() { 368 private static final ArgConverter ARG_LIST = new ArgConverter() {
364 public Object convert(Luan luan,Object obj) { 369 @Override public Object convert(Object obj) {
365 if( obj instanceof LuanTable ) { 370 if( obj instanceof LuanTable ) {
366 LuanTable t = (LuanTable)obj; 371 LuanTable t = (LuanTable)obj;
367 if( t.isList() ) 372 if( t.isList() )
368 return t.asList(); 373 return t.asList();
369 } 374 }
373 return "ARG_LIST"; 378 return "ARG_LIST";
374 } 379 }
375 }; 380 };
376 381
377 private static final ArgConverter ARG_SET = new ArgConverter() { 382 private static final ArgConverter ARG_SET = new ArgConverter() {
378 public Object convert(Luan luan,Object obj) throws LuanException { 383 @Override public Object convert(Object obj) throws LuanException {
379 if( obj instanceof LuanTable ) { 384 if( obj instanceof LuanTable ) {
380 LuanTable t = (LuanTable)obj; 385 LuanTable t = (LuanTable)obj;
381 if( t.isSet() ) 386 if( t.isSet() )
382 return t.asSet(); 387 return t.asSet();
383 } 388 }
387 return "ARG_SET"; 392 return "ARG_SET";
388 } 393 }
389 }; 394 };
390 395
391 private static final ArgConverter ARG_COLLECTION = new ArgConverter() { 396 private static final ArgConverter ARG_COLLECTION = new ArgConverter() {
392 public Object convert(Luan luan,Object obj) throws LuanException { 397 @Override public Object convert(Object obj) throws LuanException {
393 if( obj instanceof LuanTable ) { 398 if( obj instanceof LuanTable ) {
394 LuanTable t = (LuanTable)obj; 399 LuanTable t = (LuanTable)obj;
395 if( t.isList() ) 400 if( t.isList() )
396 return t.asList(); 401 return t.asList();
397 if( t.isSet() ) 402 if( t.isSet() )
409 414
410 ArgArray(Class cls) { 415 ArgArray(Class cls) {
411 a = (Object[])Array.newInstance(cls.getComponentType(),0); 416 a = (Object[])Array.newInstance(cls.getComponentType(),0);
412 } 417 }
413 418
414 public Object convert(Luan luan,Object obj) { 419 @Override public Object convert(Object obj) {
415 if( obj instanceof LuanTable ) { 420 if( obj instanceof LuanTable ) {
416 LuanTable t = (LuanTable)obj; 421 LuanTable t = (LuanTable)obj;
417 if( t.isList() ) { 422 if( t.isList() ) {
418 try { 423 try {
419 return t.asList().toArray(a); 424 return t.asList().toArray(a);
422 } 427 }
423 return obj; 428 return obj;
424 } 429 }
425 } 430 }
426 431
427 private static boolean takesLuaState(JavaMethod m) { 432 private static boolean takesLuan(JavaMethod m) {
428 Class[] paramTypes = m.getParameterTypes(); 433 Class[] paramTypes = m.getParameterTypes();
429 return paramTypes.length > 0 && paramTypes[0].equals(Luan.class); 434 return paramTypes.length > 0 && paramTypes[0].equals(Luan.class);
430 } 435 }
431 436
432 private static ArgConverter[] getArgConverters(boolean takesLuaState,JavaMethod m) { 437 private static ArgConverter[] getArgConverters(boolean takesLuan,JavaMethod m) {
433 final boolean isVarArgs = m.isVarArgs(); 438 final boolean isVarArgs = m.isVarArgs();
434 Class[] paramTypes = m.getParameterTypes(); 439 Class[] paramTypes = m.getParameterTypes();
435 if( takesLuaState ) { 440 if( takesLuan ) {
436 Class[] t = new Class[paramTypes.length-1]; 441 Class[] t = new Class[paramTypes.length-1];
437 System.arraycopy(paramTypes,1,t,0,t.length); 442 System.arraycopy(paramTypes,1,t,0,t.length);
438 paramTypes = t; 443 paramTypes = t;
439 } 444 }
440 ArgConverter[] a = new ArgConverter[paramTypes.length]; 445 ArgConverter[] a = new ArgConverter[paramTypes.length];
458 return ARG_INTEGER; 463 return ARG_INTEGER;
459 if( cls == Short.TYPE || cls.equals(Short.class) ) 464 if( cls == Short.TYPE || cls.equals(Short.class) )
460 return ARG_SHORT; 465 return ARG_SHORT;
461 if( cls == Byte.TYPE || cls.equals(Byte.class) ) 466 if( cls == Byte.TYPE || cls.equals(Byte.class) )
462 return ARG_BYTE; 467 return ARG_BYTE;
463 if( cls.equals(LuanTable.class) ) 468 // if( cls.equals(LuanTable.class) )
464 return ARG_TABLE; 469 // return ARG_TABLE;
465 if( cls.equals(Map.class) ) 470 if( cls.equals(Map.class) )
466 return ARG_MAP; 471 return ARG_MAP;
467 if( cls.equals(List.class) ) 472 if( cls.equals(List.class) )
468 return ARG_LIST; 473 return ARG_LIST;
469 if( cls.equals(Set.class) ) 474 if( cls.equals(Set.class) )
481 abstract boolean isVarArgs(); 486 abstract boolean isVarArgs();
482 abstract Class[] getParameterTypes(); 487 abstract Class[] getParameterTypes();
483 abstract Object invoke(Object obj,Object... args) 488 abstract Object invoke(Object obj,Object... args)
484 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException; 489 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException;
485 abstract Class getReturnType(); 490 abstract Class getReturnType();
486 abstract boolean isLuan(); 491 abstract String getName();
487 492
488 static JavaMethod of(final Method m) { 493 static JavaMethod of(final Method m) {
489 return new JavaMethod() { 494 return new JavaMethod() {
490 @Override boolean isVarArgs() { 495 @Override boolean isVarArgs() {
491 return m.isVarArgs(); 496 return m.isVarArgs();
499 return m.invoke(obj,args); 504 return m.invoke(obj,args);
500 } 505 }
501 @Override Class getReturnType() { 506 @Override Class getReturnType() {
502 return m.getReturnType(); 507 return m.getReturnType();
503 } 508 }
504 @Override boolean isLuan() { 509 @Override public String getName() {
505 return m.getAnnotation(LuanMethod.class) != null; 510 return m.getName();
506 } 511 }
507 @Override public String toString() { 512 @Override public String toString() {
508 return m.toString(); 513 return m.toString();
509 } 514 }
510 }; 515 };
524 return c.newInstance(args); 529 return c.newInstance(args);
525 } 530 }
526 @Override Class getReturnType() { 531 @Override Class getReturnType() {
527 return c.getDeclaringClass(); 532 return c.getDeclaringClass();
528 } 533 }
529 @Override boolean isLuan() { 534 @Override public String getName() {
530 return false; 535 return c.getName();
531 } 536 }
532 @Override public String toString() { 537 @Override public String toString() {
533 return c.toString(); 538 return c.toString();
534 } 539 }
535 }; 540 };