1 21 22 package org.armedbear.lisp; 23 24 import java.lang.reflect.Constructor ; 25 import java.lang.reflect.InvocationTargetException ; 26 import java.lang.reflect.Method ; 27 import java.lang.reflect.Field ; 28 import java.lang.reflect.Modifier ; 29 import java.lang.reflect.Array ; 30 31 public final class Java extends Lisp 32 { 33 private static final Primitive1 JCLASS = new Primitive1("jclass", PACKAGE_JAVA, true, "name") 35 { 36 public LispObject execute(LispObject arg) throws ConditionThrowable 37 { 38 String className = arg.getStringValue(); 39 try { 40 return new JavaObject(classForName(className)); 41 } 42 catch (ClassNotFoundException e) { 43 signal(new LispError("class not found: " + className)); 44 } 45 catch (Throwable t) { 46 signal(new LispError(getMessage(t))); 47 } 48 return NIL; 50 } 51 }; 52 53 81 private static final Primitive JFIELD = 82 new Primitive("jfield", PACKAGE_JAVA, true, 83 "class-ref-or-field field-or-instance &optional instance value") 84 { 85 public LispObject execute(LispObject[] args) throws ConditionThrowable 86 { 87 return makeLispObject((JFIELD_RAW.execute(args)).javaInstance()); 88 } 89 }; 90 91 private static final Primitive JFIELD_RAW = 93 new Primitive("jfield-raw", PACKAGE_JAVA, true, 94 "class-ref-or-field field-or-instance &optional instance value") 95 { 96 public LispObject execute(LispObject[] args) throws ConditionThrowable 97 { 98 if (args.length < 2 || args.length > 4) 99 signal(new WrongNumberOfArgumentsException(this)); 100 String fieldName = null; 101 Class c; 102 Field f; 103 Class fieldType; 104 Object instance = null; 105 try { 106 if (args[1] instanceof AbstractString) { 107 fieldName = args[1].getStringValue(); 109 c = forClassRef(args[0]); 110 } else { 111 fieldName = args[0].getStringValue(); 113 instance = JavaObject.getObject(args[1]); 114 c = instance.getClass(); 115 } 116 f = c.getField(fieldName); 117 fieldType = f.getType(); 118 switch (args.length) { 119 case 2: 120 break; 122 case 3: 123 if (instance == null) { 125 if (args[2] instanceof JavaObject) { 127 instance = JavaObject.getObject(args[2]); 129 break; 130 } else { 131 f.set(null,args[2].javaInstance(fieldType)); 133 return args[2]; 134 } 135 } else { 136 f.set(instance,args[2].javaInstance(fieldType)); 138 return args[2]; 139 } 140 case 4: 141 if (args[2] != NIL) { 143 instance = JavaObject.getObject(args[2]); 145 } 146 f.set(instance,args[3].javaInstance(fieldType)); 147 return args[3]; 148 } 149 return new JavaObject(f.get(instance)); 150 } 151 catch (ClassNotFoundException e) { 152 signal(new LispError("class not found: " + e.getMessage())); 153 } 154 catch (NoSuchFieldException e) { 155 signal(new LispError("no such field")); 156 } 157 catch (SecurityException e) { 158 signal(new LispError("inaccessible field")); 159 } 160 catch (IllegalAccessException e) { 161 signal(new LispError("illegal access")); 162 } 163 catch (IllegalArgumentException e) { 164 signal(new LispError("illegal argument")); 165 } 166 catch (Throwable t) { 167 signal(new LispError(getMessage(t))); 168 } 169 return NIL; 171 } 172 }; 173 174 private static final Primitive JCONSTRUCTOR = 177 new Primitive("jconstructor", PACKAGE_JAVA, true, "class-ref &rest parameter-class-refs") 178 { 179 public LispObject execute(LispObject[] args) throws ConditionThrowable 180 { 181 if (args.length < 1) 182 signal(new WrongNumberOfArgumentsException(this)); 183 try { 184 final Class c = forClassRef(args[0]); 185 int argCount = 0; 186 if (args.length == 2 && args[1] instanceof Fixnum) { 187 argCount = Fixnum.getValue(args[1]); 188 } else { 189 Class [] parameterTypes = new Class [args.length-1]; 190 for (int i = 1; i < args.length; i++) { 191 parameterTypes[i-1] = forClassRef(args[i]); 192 } 193 return new JavaObject(c.getConstructor(parameterTypes)); 194 } 195 Constructor [] constructors = c.getConstructors(); 197 for (int i = 0; i < constructors.length; i++) { 198 Constructor constructor = constructors[i]; 199 if (constructor.getParameterTypes().length == argCount) 200 return new JavaObject(constructor); 201 } 202 throw new NoSuchMethodException (); 203 } 204 catch (ClassNotFoundException e) { 205 signal(new LispError("class not found: " + e.getMessage())); 206 } 207 catch (NoSuchMethodException e) { 208 signal(new LispError("no such constructor")); 209 } 210 catch (ConditionThrowable e) { 211 throw e; 212 } 213 catch (Throwable t) { 214 signal(new LispError(getMessage(t))); 215 } 216 return NIL; 218 } 219 }; 220 221 private static final Primitive JMETHOD = 224 new Primitive("jmethod", PACKAGE_JAVA, true, 225 "class-ref name &rest parameter-class-refs") 226 { 227 public LispObject execute(LispObject[] args) throws ConditionThrowable 228 { 229 if (args.length < 2) 230 signal(new WrongNumberOfArgumentsException(this)); 231 String methodName = args[1].getStringValue(); 232 try { 233 final Class c = forClassRef(args[0]); 234 int argCount = 0; 235 if (args.length == 3 && args[2] instanceof Fixnum) { 236 argCount = Fixnum.getValue(args[2]); 237 } else { 238 Class [] parameterTypes = new Class [args.length-2]; 239 for (int i = 2; i < args.length; i++) { 240 parameterTypes[i-2] = forClassRef(args[i]); 241 } 242 return new JavaObject(c.getMethod(methodName, 243 parameterTypes)); 244 } 245 Method [] methods = c.getMethods(); 247 for (int i = 0; i < methods.length; i++) { 248 Method method = methods[i]; 249 if (method.getName().equals(methodName) 250 && method.getParameterTypes().length == argCount) 251 return new JavaObject(method); 252 } 253 throw new NoSuchMethodException (); 254 } 255 catch (ClassNotFoundException e) { 256 signal(new LispError("class not found: " + e.getMessage())); 257 } 258 catch (NoSuchMethodException e) { 259 signal(new LispError("no such method: " + methodName)); 260 } 261 catch (ConditionThrowable e) { 262 throw e; 263 } 264 catch (Throwable t) { 265 signal(new LispError(getMessage(t))); 266 } 267 return NIL; 269 } 270 }; 271 272 private static final Primitive JSTATIC = new Primitive("jstatic", PACKAGE_JAVA, true, 275 "method class &rest args") 276 { 277 public LispObject execute(LispObject[] args) throws ConditionThrowable 278 { 279 return makeLispObject((JSTATIC_RAW.execute(args)).javaInstance()); 280 } 281 }; 282 283 284 private static final Primitive JSTATIC_RAW = new Primitive("jstatic-raw", PACKAGE_JAVA, true, 287 "method class &rest args") 288 { 289 public LispObject execute(LispObject[] args) throws ConditionThrowable 290 { 291 if (args.length < 2) 292 signal(new WrongNumberOfArgumentsException(this)); 293 try { 294 Method m = null; 295 LispObject methodRef = args[0]; 296 if (methodRef instanceof JavaObject) { 297 Object obj = ((JavaObject)methodRef).getObject(); 298 if (obj instanceof Method ) 299 m = (Method ) obj; 300 } else if (methodRef instanceof AbstractString) { 301 Class c = forClassRef(args[1]); 302 if (c != null) { 303 String methodName = methodRef.getStringValue(); 304 Method [] methods = c.getMethods(); 305 int argCount = args.length - 2; 306 for (int i = 0; i < methods.length; i++) { 307 Method method = methods[i]; 308 if (!Modifier.isStatic(method.getModifiers()) 309 || method.getParameterTypes().length != argCount) 310 continue; 311 if (method.getName().equals(methodName)) { 312 m = method; 313 break; 314 } 315 } 316 if (m == null) 317 signal(new LispError("no such method")); 318 } 319 } else 320 signal(new TypeError("wrong type: " + methodRef)); 321 Object [] methodArgs = new Object [args.length-2]; 322 Class [] argTypes = m.getParameterTypes(); 323 for (int i = 2; i < args.length; i++) { 324 LispObject arg = args[i]; 325 if (arg == NIL) 326 methodArgs[i-2] = null; 327 else 328 methodArgs[i-2] = arg.javaInstance(argTypes[i-2]); 329 } 330 Object result = m.invoke(null, methodArgs); 331 return new JavaObject(result); 332 } 333 catch (Throwable t) { 334 signal(new LispError(getMessage(t))); 335 } 336 return NIL; 338 } 339 }; 340 341 private static final Primitive JNEW = new Primitive("jnew", PACKAGE_JAVA, true, 344 "constructor &rest args") 345 { 346 public LispObject execute(LispObject[] args) throws ConditionThrowable 347 { 348 if (args.length < 1) 349 signal(new WrongNumberOfArgumentsException(this)); 350 LispObject classRef = args[0]; 351 try { 352 Constructor constructor = (Constructor ) JavaObject.getObject(classRef); 353 Class [] argTypes = constructor.getParameterTypes(); 354 Object [] initargs = new Object [args.length-1]; 355 for (int i = 1; i < args.length; i++) { 356 LispObject arg = args[i]; 357 if (arg == NIL) 358 initargs[i-1] = null; 359 else { 360 initargs[i-1] = arg.javaInstance(argTypes[i-1]); 361 } 362 } 363 return new JavaObject(constructor.newInstance(initargs)); 364 } 365 catch (Throwable t) { 366 signal(new LispError(getMessage(t))); 367 } 368 return NIL; 370 } 371 }; 372 373 private static final Primitive JNEW_ARRAY = new Primitive("jnew-array", PACKAGE_JAVA, true, 376 "element-type &rest dimensions") 377 { 378 public LispObject execute(LispObject[] args) throws ConditionThrowable 379 { 380 if (args.length < 2) 381 signal(new WrongNumberOfArgumentsException(this)); 382 try { 383 Class c = forClassRef(args[0]); 384 int[] dimensions = new int[args.length - 1]; 385 for (int i = 1; i < args.length; i++) 386 dimensions[i-1] = ((Integer )args[i].javaInstance()).intValue(); 387 return new JavaObject(Array.newInstance(c, dimensions)); 388 } 389 catch (ClassNotFoundException e) { 390 signal(new LispError("class not found: " + e.getMessage())); 391 } 392 catch (Throwable t) { 393 signal(new LispError(getMessage(t))); 394 } 395 return NIL; 397 } 398 }; 399 400 private static final Primitive JARRAY_REF = new Primitive("jarray-ref", PACKAGE_JAVA, true, 403 "java-array &rest indices") 404 { 405 public LispObject execute(LispObject[] args) throws ConditionThrowable 406 { 407 return makeLispObject((JARRAY_REF_RAW.execute(args)).javaInstance()); 408 } 409 }; 410 411 private static final Primitive JARRAY_REF_RAW = new Primitive("jarray-ref-raw", PACKAGE_JAVA, true, 414 "java-array &rest indices") 415 { 416 public LispObject execute(LispObject[] args) throws ConditionThrowable 417 { 418 if (args.length < 2) 419 signal(new WrongNumberOfArgumentsException(this)); 420 try { 421 Object a = args[0].javaInstance(); 422 for (int i = 1; i<args.length - 1; i++) 423 a = Array.get(a, ((Integer )args[i].javaInstance()).intValue()); 424 return new JavaObject(Array.get(a, ((Integer )args[args.length - 1].javaInstance()).intValue())); 425 } 426 catch (Throwable t) { 427 signal(new LispError(getMessage(t))); 428 } 429 return NIL; 431 } 432 }; 433 434 private static final Primitive JARRAY_SET = new Primitive("jarray-set", PACKAGE_JAVA, true, 437 "java-array new-value &rest indices") 438 { 439 public LispObject execute(LispObject[] args) throws ConditionThrowable 440 { 441 if (args.length < 3) 442 signal(new WrongNumberOfArgumentsException(this)); 443 try { 444 Object a = args[0].javaInstance(); 445 LispObject v = args[1]; 446 for (int i = 2; i<args.length - 1; i++) 447 a = Array.get(a, ((Integer )args[i].javaInstance()).intValue()); 448 Array.set(a, ((Integer )args[args.length - 1].javaInstance()).intValue(), v.javaInstance()); 449 return v; 450 } 451 catch (Throwable t) { 452 signal(new LispError(getMessage(t))); 453 } 454 return NIL; 456 } 457 }; 458 459 private static final Primitive JCALL = new Primitive("jcall", PACKAGE_JAVA, true, 462 "method instance &rest args") 463 { 464 public LispObject execute(LispObject[] args) throws ConditionThrowable 465 { 466 return makeLispObject((JCALL_RAW.execute(args)).javaInstance()); 467 } 468 }; 469 470 private static final Primitive JCALL_RAW = new Primitive("jcall-raw", PACKAGE_JAVA, true, 473 "method instance &rest args") 474 { 475 public LispObject execute(LispObject[] args) throws ConditionThrowable 476 { 477 if (args.length < 2) 478 signal(new WrongNumberOfArgumentsException(this)); 479 try { 480 Method method = (Method ) JavaObject.getObject(args[0]); 481 Class [] argTypes = method.getParameterTypes(); 482 Object instance; 483 if (args[1] instanceof AbstractString) 484 instance = args[1].getStringValue(); 485 else 486 instance = JavaObject.getObject(args[1]); 487 Object [] methodArgs = new Object [args.length-2]; 488 for (int i = 2; i < args.length; i++) { 489 LispObject arg = args[i]; 490 if (arg == NIL) 491 methodArgs[i-2] = null; 492 else 493 methodArgs[i-2] = arg.javaInstance(argTypes[i-2]); 494 } 495 Object result = method.invoke(instance, methodArgs); 496 return new JavaObject(result); 497 } 498 catch (Throwable t) { 499 signal(new LispError(getMessage(t))); 500 } 501 return NIL; 503 } 504 }; 505 506 private static final Primitive MAKE_IMMEDIATE_OBJECT = 509 new Primitive("make-immediate-object", PACKAGE_JAVA, true, "object &optional type") 510 { 511 public LispObject execute(LispObject[] args) throws ConditionThrowable 512 { 513 if (args.length < 1) 514 signal(new WrongNumberOfArgumentsException(this)); 515 LispObject object = args[0]; 516 try { 517 if (args.length > 1) { 518 LispObject type = args[1]; 519 if (type == Keyword.BOOLEAN) { 520 if (object == NIL) 521 return new JavaObject(Boolean.FALSE); 522 else 523 return new JavaObject(Boolean.TRUE); 524 } 525 if (type == Keyword.REF) { 526 if (object == NIL) 527 return new JavaObject(null); 528 else 529 throw new Error (); 530 } 531 } 533 return new JavaObject(object.javaInstance()); 534 } 535 catch (Throwable t) { 536 signal(new LispError("MAKE-IMMEDIATE-OBJECT: not implemented")); 537 } 538 return NIL; 540 } 541 }; 542 543 private static final Primitive1 JAVA_OBJECT_P = new Primitive1("java-object-p", PACKAGE_JAVA, true, 544 "object") 545 { 546 public LispObject execute(LispObject arg) throws ConditionThrowable 547 { 548 return (arg instanceof JavaObject) ? T : NIL; 549 } 550 }; 551 552 private static final Primitive1 JOBJECT_LISP_VALUE = 555 new Primitive1("jobject-lisp-value", PACKAGE_JAVA, true, "java-object") 556 { 557 public LispObject execute(LispObject arg) throws ConditionThrowable 558 { 559 return makeLispObject(arg.javaInstance()); 560 } 561 }; 562 563 private static Class classForName(String className) throws ClassNotFoundException 564 { 565 try { 566 return Class.forName(className); 567 } 568 catch (ClassNotFoundException e) { 569 return Class.forName(className, true, JavaClassLoader.getPersistentInstance()); 570 } 571 } 572 573 private static Class forClassRef(LispObject classRef) throws ClassNotFoundException , ConditionThrowable 575 { 576 if (classRef instanceof AbstractString) { 577 String className = classRef.getStringValue(); 578 if (className.equals("boolean")) 579 return Boolean.TYPE; 580 if (className.equals("byte")) 581 return Byte.TYPE; 582 if (className.equals("char")) 583 return Character.TYPE; 584 if (className.equals("short")) 585 return Short.TYPE; 586 if (className.equals("int")) 587 return Integer.TYPE; 588 if (className.equals("long")) 589 return Long.TYPE; 590 if (className.equals("float")) 591 return Float.TYPE; 592 if (className.equals("double")) 593 return Double.TYPE; 594 return classForName(className); 596 } else 597 try { 598 return (Class )JavaObject.getObject(classRef); 599 } 600 catch (ClassCastException e) { 601 signal(new TypeError(classRef, "Java class")); 602 } 603 catch (ConditionThrowable e) { 604 throw new ClassNotFoundException (e.getMessage()); 605 } 606 return null; 608 } 609 610 private static final LispObject makeLispObject(Object obj) throws ConditionThrowable 611 { 612 if (obj == null) 613 return NIL; 614 if (obj instanceof Boolean ) 615 return ((Boolean )obj).booleanValue() ? T : NIL; 616 if (obj instanceof Integer ) 617 return new Fixnum(((Integer )obj).intValue()); 618 if (obj instanceof Long ) 619 return new Bignum(((Long )obj).longValue()); 620 if (obj instanceof Double || obj instanceof Float ) 621 return new LispFloat(((Number )obj).doubleValue()); 622 if (obj instanceof String ) 623 return new SimpleString((String )obj); 624 if (obj instanceof Character ) 625 return LispCharacter.getInstance(((Character )obj).charValue()); 626 if (obj instanceof Object []) { 627 Object [] array = (Object []) obj; 628 SimpleVector v = new SimpleVector(array.length); 629 for (int i = array.length; i-- > 0;) 630 v.setRowMajor(i, new JavaObject(array[i])); 631 return v; 632 } 633 if (obj instanceof LispObject) 634 return (LispObject) obj; 635 return new JavaObject(obj); 636 } 637 638 private static final String getMessage(Throwable t) 639 { 640 if (t instanceof InvocationTargetException ) { 641 try { 642 Method method = 643 Throwable .class.getMethod("getCause", new Class [0]); 644 if (method != null) { 645 Throwable cause = (Throwable ) method.invoke(t, 646 new Object [0]); 647 if (cause != null) 648 t = cause; 649 } 650 } 651 catch (NoSuchMethodException e) { 652 Debug.trace(e); 653 } 654 catch (Exception e) { 655 Debug.trace(e); 656 } 657 } 658 String message = t.getMessage(); 659 if (message == null || message.length() == 0) 660 message = t.getClass().getName(); 661 return message; 662 } 663 } 664 | Popular Tags |