1 33 34 35 package bsh; 36 37 import java.lang.reflect.Array ; 38 import java.util.Hashtable ; 39 import java.io.*; 40 import java.lang.reflect.InvocationTargetException ; 41 import java.lang.reflect.Method ; 42 43 61 98 class Name implements java.io.Serializable 99 { 100 public NameSpace namespace; 102 String value = null; 103 104 108 110 private String evalName; 111 115 private String lastEvalName; 116 private static String FINISHED = null; private Object evalBaseObject; 119 private int callstackDepth; 121 125 128 131 134 Class asClass; 135 136 139 Class classOfStaticMethod; 140 141 143 private void reset() { 144 evalName = value; 145 evalBaseObject = null; 146 callstackDepth = 0; 147 } 148 149 154 Name( NameSpace namespace, String s ) 156 { 157 this.namespace = namespace; 158 value = s; 159 } 160 161 182 public Object toObject( CallStack callstack, Interpreter interpreter ) 183 throws UtilEvalError 184 { 185 return toObject( callstack, interpreter, false ); 186 } 187 188 194 synchronized public Object toObject( 195 CallStack callstack, Interpreter interpreter, boolean forceClass ) 196 throws UtilEvalError 197 { 198 reset(); 199 200 Object obj = null; 201 while( evalName != null ) 202 obj = consumeNextObjectField( 203 callstack, interpreter, forceClass, false ); 204 205 if ( obj == null ) 206 throw new InterpreterError("null value in toObject()"); 207 208 return obj; 209 } 210 211 private Object completeRound( 212 String lastEvalName, String nextEvalName, Object returnObject ) 213 { 214 if ( returnObject == null ) 215 throw new InterpreterError("lastEvalName = "+lastEvalName); 216 this.lastEvalName = lastEvalName; 217 this.evalName = nextEvalName; 218 this.evalBaseObject = returnObject; 219 return returnObject; 220 } 221 222 228 private Object consumeNextObjectField( 229 CallStack callstack, Interpreter interpreter, 230 boolean forceClass, boolean autoAllocateThis ) 231 throws UtilEvalError 232 { 233 239 if ( (evalBaseObject == null && !isCompound(evalName) ) 240 && !forceClass ) 241 { 242 Object obj = resolveThisFieldReference( 243 callstack, namespace, interpreter, evalName, false ); 244 245 if ( obj != Primitive.VOID ) 246 return completeRound( evalName, FINISHED, obj ); 247 } 248 249 254 String varName = prefix(evalName, 1); 255 if ( ( evalBaseObject == null || evalBaseObject instanceof This ) 256 && !forceClass ) 257 { 258 if ( Interpreter.DEBUG ) 259 Interpreter.debug("trying to resolve variable: " + varName); 260 261 Object obj; 262 if ( evalBaseObject == null ) { 264 obj = resolveThisFieldReference( 265 callstack, namespace, interpreter, varName, false ); 266 } else { 267 obj = resolveThisFieldReference( 268 callstack, ((This)evalBaseObject).namespace, 269 interpreter, varName, true ); 270 } 271 272 if ( obj != Primitive.VOID ) 273 { 274 if ( Interpreter.DEBUG ) 276 Interpreter.debug( "resolved variable: " + varName + 277 " in namespace: "+namespace); 278 279 return completeRound( varName, suffix(evalName), obj ); 280 } 281 } 282 283 287 if ( evalBaseObject == null ) 288 { 289 if ( Interpreter.DEBUG ) 290 Interpreter.debug( "trying class: " + evalName); 291 292 295 Class clas = null; 296 int i = 1; 297 String className = null; 298 for(; i <= countParts(evalName); i++) 299 { 300 className = prefix(evalName, i); 301 if ( (clas = namespace.getClass(className)) != null ) 302 break; 303 } 304 305 if ( clas != null ) { 306 return completeRound( 307 className, 308 suffix( evalName, countParts(evalName)-i ), 309 new ClassIdentifier(clas) 310 ); 311 } 312 if ( Interpreter.DEBUG ) 314 Interpreter.debug( "not a class, trying var prefix "+evalName ); 315 } 316 317 if ( ( evalBaseObject == null || evalBaseObject instanceof This ) 320 && !forceClass && autoAllocateThis ) 321 { 322 NameSpace targetNameSpace = 323 ( evalBaseObject == null ) ? 324 namespace : ((This)evalBaseObject).namespace; 325 Object obj = new NameSpace( 326 targetNameSpace, "auto: "+varName ).getThis( interpreter ); 327 targetNameSpace.setVariable( varName, obj, false ); 328 return completeRound( varName, suffix(evalName), obj ); 329 } 330 331 339 if ( evalBaseObject == null ) { 340 if ( !isCompound(evalName) ) { 341 return completeRound( evalName, FINISHED, Primitive.VOID ); 342 } else 343 throw new UtilEvalError( 344 "Class or variable not found: " + evalName); 345 } 346 347 353 354 357 358 if ( evalBaseObject == Primitive.NULL) throw new UtilTargetError( new NullPointerException ( 360 "Null Pointer while evaluating: " +value ) ); 361 362 if ( evalBaseObject == Primitive.VOID) throw new UtilEvalError( 364 "Undefined variable or class name while evaluating: "+value); 365 366 if ( evalBaseObject instanceof Primitive) 367 throw new UtilEvalError("Can't treat primitive like an object. "+ 368 "Error while evaluating: "+value); 369 370 374 if ( evalBaseObject instanceof ClassIdentifier ) 375 { 376 Class clas = ((ClassIdentifier)evalBaseObject).getTargetClass(); 377 String field = prefix(evalName, 1); 378 379 if ( field.equals("this") ) 382 { 383 NameSpace ns = namespace; 385 while ( ns != null ) 386 { 387 if ( ns.classInstance != null 389 && ns.classInstance.getClass() == clas 390 ) 391 return completeRound( 392 field, suffix(evalName), ns.classInstance ); 393 ns=ns.getParent(); 394 } 395 throw new UtilEvalError( 396 "Can't find enclosing 'this' instance of class: "+clas); 397 } 398 399 Object obj = null; 400 try { 402 if ( Interpreter.DEBUG ) 403 Interpreter.debug("Name call to getStaticFieldValue, class: " 404 +clas+", field:"+field); 405 obj = Reflect.getStaticFieldValue(clas, field); 406 } catch( ReflectError e ) { 407 if ( Interpreter.DEBUG ) 408 Interpreter.debug("field reflect error: "+e); 409 } 410 411 if ( obj == null ) { 413 String iclass = clas.getName()+"$"+field; 414 Class c = namespace.getClass( iclass ); 415 if ( c != null ) 416 obj = new ClassIdentifier(c); 417 } 418 419 if ( obj == null ) 420 throw new UtilEvalError( 421 "No static field or inner class: " 422 + field + " of " + clas ); 423 424 return completeRound( field, suffix(evalName), obj ); 425 } 426 427 431 if ( forceClass ) 432 throw new UtilEvalError( 433 value +" does not resolve to a class name." ); 434 435 438 439 String field = prefix(evalName, 1); 440 441 if ( field.equals("length") && evalBaseObject.getClass().isArray() ) 443 { 444 Object obj = new Primitive(Array.getLength(evalBaseObject)); 445 return completeRound( field, suffix(evalName), obj ); 446 } 447 448 try { 451 Object obj = Reflect.getObjectFieldValue(evalBaseObject, field); 452 return completeRound( field, suffix(evalName), obj ); 453 } catch(ReflectError e) { } 454 455 throw new UtilEvalError( 457 "Cannot access field: " + field + ", on object: " + evalBaseObject); 458 } 459 460 476 Object resolveThisFieldReference( 477 CallStack callstack, NameSpace thisNameSpace, Interpreter interpreter, 478 String varName, boolean specialFieldsVisible ) 479 throws UtilEvalError 480 { 481 if ( varName.equals("this") ) 482 { 483 489 if ( specialFieldsVisible ) 490 throw new UtilEvalError("Redundant to call .this on This type"); 491 492 This ths = thisNameSpace.getThis( interpreter ); 496 thisNameSpace= ths.getNameSpace(); 497 Object result = ths; 498 499 NameSpace classNameSpace = getClassNameSpace( thisNameSpace ); 500 if ( classNameSpace != null ) 501 { 502 if ( isCompound( evalName ) ) 503 result = classNameSpace.getThis( interpreter ); 504 else 505 result = classNameSpace.getClassInstance(); 506 } 507 508 return result; 509 } 510 511 516 if ( varName.equals("super") ) 517 { 518 521 This ths = thisNameSpace.getSuper( interpreter ); 523 thisNameSpace = ths.getNameSpace(); 524 526 if ( 531 thisNameSpace.getParent() != null 532 && thisNameSpace.getParent().isClass 533 ) 534 ths = thisNameSpace.getParent().getThis( interpreter ); 535 536 return ths; 537 } 538 539 Object obj = null; 540 541 if ( varName.equals("global") ) 542 obj = thisNameSpace.getGlobal( interpreter ); 543 544 if ( obj == null && specialFieldsVisible ) 545 { 546 if (varName.equals("namespace")) 547 obj = thisNameSpace; 548 else if (varName.equals("variables")) 549 obj = thisNameSpace.getVariableNames(); 550 else if (varName.equals("methods")) 551 obj = thisNameSpace.getMethodNames(); 552 else if ( varName.equals("interpreter") ) 553 if ( lastEvalName.equals("this") ) 554 obj = interpreter; 555 else 556 throw new UtilEvalError( 557 "Can only call .interpreter on literal 'this'"); 558 } 559 560 if ( obj == null && specialFieldsVisible && varName.equals("caller") ) 561 { 562 if ( lastEvalName.equals("this") || lastEvalName.equals("caller") ) 563 { 564 if ( callstack == null ) 566 throw new InterpreterError("no callstack"); 567 obj = callstack.get( ++callstackDepth ).getThis( 568 interpreter ); 569 } 570 else 571 throw new UtilEvalError( 572 "Can only call .caller on literal 'this' or literal '.caller'"); 573 574 return obj; 576 } 577 578 if ( obj == null && specialFieldsVisible 579 && varName.equals("callstack") ) 580 { 581 if ( lastEvalName.equals("this") ) 582 { 583 if ( callstack == null ) 585 throw new InterpreterError("no callstack"); 586 obj = callstack; 587 } 588 else 589 throw new UtilEvalError( 590 "Can only call .callstack on literal 'this'"); 591 } 592 593 594 if ( obj == null ) 595 obj = thisNameSpace.getVariable(varName); 596 597 if ( obj == null ) 598 throw new InterpreterError("null this field ref:"+varName); 599 600 return obj; 601 } 602 603 606 static NameSpace getClassNameSpace( NameSpace thisNameSpace ) 607 { 608 if ( thisNameSpace.isClass ) 611 return thisNameSpace; 612 613 if ( thisNameSpace.isMethod 614 && thisNameSpace.getParent() != null 615 && thisNameSpace.getParent().isClass 617 ) 618 return thisNameSpace.getParent(); 619 620 return null; 621 } 622 623 631 synchronized public Class toClass() 632 throws ClassNotFoundException , UtilEvalError 633 { 634 if ( asClass != null ) 635 return asClass; 636 637 reset(); 638 639 if ( evalName.equals("var") ) 641 return asClass = null; 642 643 644 Class clas = namespace.getClass( evalName ); 645 646 if ( clas == null ) 647 { 648 652 Object obj = null; 653 try { 654 obj = toObject( null, null, true ); 657 } catch ( UtilEvalError e ) { }; 659 if ( obj instanceof ClassIdentifier ) 660 clas = ((ClassIdentifier)obj).getTargetClass(); 661 } 662 663 if ( clas == null ) 664 throw new ClassNotFoundException ( 665 "Class: " + value+ " not found in namespace"); 666 667 asClass = clas; 668 return asClass; 669 } 670 671 673 synchronized public LHS toLHS( 674 CallStack callstack, Interpreter interpreter ) 675 throws UtilEvalError 676 { 677 reset(); 679 LHS lhs; 680 681 if ( !isCompound(evalName) ) 683 { 684 if ( evalName.equals("this") ) 685 throw new UtilEvalError("Can't assign to 'this'." ); 686 687 lhs = new LHS( namespace, evalName, false); 689 return lhs; 690 } 691 692 Object obj = null; 694 try { 695 while( evalName != null && isCompound( evalName ) ) 696 { 697 obj = consumeNextObjectField( callstack, interpreter, 698 false, true ); 699 } 700 } 701 catch( UtilEvalError e ) { 702 throw new UtilEvalError( "LHS evaluation: " + e.getMessage() ); 703 } 704 705 if ( evalName == null && obj instanceof ClassIdentifier ) 707 throw new UtilEvalError("Can't assign to class: " + value ); 708 709 if ( obj == null ) 710 throw new UtilEvalError("Error in LHS: " + value ); 711 712 if ( obj instanceof This ) 714 { 715 if ( 717 evalName.equals("namespace") 718 || evalName.equals("variables") 719 || evalName.equals("methods") 720 || evalName.equals("caller") 721 ) 722 throw new UtilEvalError( 723 "Can't assign to special variable: "+evalName ); 724 725 Interpreter.debug("found This reference evaluating LHS"); 726 736 boolean localVar = !lastEvalName.equals("super"); 737 return new LHS( ((This)obj).namespace, evalName, localVar ); 738 } 739 740 if ( evalName != null ) 741 { 742 try { 743 if ( obj instanceof ClassIdentifier ) 744 { 745 Class clas = ((ClassIdentifier)obj).getTargetClass(); 746 lhs = Reflect.getLHSStaticField(clas, evalName); 747 return lhs; 748 } else { 749 lhs = Reflect.getLHSObjectField(obj, evalName); 750 return lhs; 751 } 752 } catch(ReflectError e) { 753 throw new UtilEvalError("Field access: "+e); 754 } 755 } 756 757 throw new InterpreterError("Internal error in lhs..."); 758 } 759 760 784 public Object invokeMethod( 785 Interpreter interpreter, Object [] args, CallStack callstack, 786 SimpleNode callerInfo 787 ) 788 throws UtilEvalError, EvalError, ReflectError, InvocationTargetException 789 { 790 String methodName = Name.suffix(value, 1); 791 BshClassManager bcm = interpreter.getClassManager(); 792 NameSpace namespace = callstack.top(); 793 794 if ( classOfStaticMethod != null ) 798 { 799 return Reflect.invokeStaticMethod( 800 bcm, classOfStaticMethod, methodName, args ); 801 } 802 803 if ( !Name.isCompound(value) ) 804 return invokeLocalMethod( 805 interpreter, args, callstack, callerInfo ); 806 807 813 String prefix = Name.prefix(value); 814 815 if ( prefix.equals("super") && Name.countParts(value) == 2 ) 817 { 818 This ths = namespace.getThis( interpreter ); 820 NameSpace thisNameSpace = ths.getNameSpace(); 821 NameSpace classNameSpace = getClassNameSpace( thisNameSpace ); 822 if ( classNameSpace != null ) 823 { 824 Object instance = classNameSpace.getClassInstance(); 825 return ClassGenerator.getClassGenerator() 826 .invokeSuperclassMethod( bcm, instance, methodName, args ); 827 } 828 } 829 830 Name targetName = namespace.getNameResolver( prefix ); 832 Object obj = targetName.toObject( callstack, interpreter ); 833 834 if ( obj == Primitive.VOID ) 835 throw new UtilEvalError( "Attempt to resolve method: "+methodName 836 +"() on undefined variable or class name: "+targetName); 837 838 if ( !(obj instanceof ClassIdentifier) ) { 840 841 if (obj instanceof Primitive) { 842 843 if (obj == Primitive.NULL) 844 throw new UtilTargetError( new NullPointerException ( 845 "Null Pointer in Method Invocation" ) ); 846 847 if ( Interpreter.DEBUG ) 852 interpreter.debug( 853 "Attempt to access method on primitive..." 854 + " allowing bsh.Primitive to peek through for debugging"); 855 } 856 857 return Reflect.invokeObjectMethod( 859 obj, methodName, args, interpreter, callstack, callerInfo ); 860 } 861 862 864 if ( Interpreter.DEBUG ) 866 Interpreter.debug("invokeMethod: trying static - " + targetName); 867 868 Class clas = ((ClassIdentifier)obj).getTargetClass(); 869 870 classOfStaticMethod = clas; 872 873 if ( clas != null ) 874 return Reflect.invokeStaticMethod( bcm, clas, methodName, args ); 875 876 throw new UtilEvalError("invokeMethod: unknown target: " + targetName); 878 } 879 880 886 891 private Object invokeLocalMethod( 892 Interpreter interpreter, Object [] args, CallStack callstack, 893 SimpleNode callerInfo 894 ) 895 throws EvalError 896 { 897 if ( Interpreter.DEBUG ) 898 Interpreter.debug( "invokeLocalMethod: " + value ); 899 if ( interpreter == null ) 900 throw new InterpreterError( 901 "invokeLocalMethod: interpreter = null"); 902 903 String commandName = value; 904 Class [] argTypes = Types.getTypes( args ); 905 906 BshMethod meth = null; 908 try { 909 meth = namespace.getMethod( commandName, argTypes ); 910 } catch ( UtilEvalError e ) { 911 throw e.toEvalError( 912 "Local method invocation", callerInfo, callstack ); 913 } 914 915 if ( meth != null ) 917 return meth.invoke( args, interpreter, callstack, callerInfo ); 918 919 BshClassManager bcm = interpreter.getClassManager(); 920 921 923 Object commandObject; 924 try { 925 commandObject = namespace.getCommand( 926 commandName, argTypes, interpreter ); 927 } catch ( UtilEvalError e ) { 928 throw e.toEvalError("Error loading command: ", 929 callerInfo, callstack ); 930 } 931 932 if ( commandObject == null ) 934 { 935 BshMethod invokeMethod = null; 939 try { 940 invokeMethod = namespace.getMethod( 941 "invoke", new Class [] { null, null } ); 942 } catch ( UtilEvalError e ) { 943 throw e.toEvalError( 944 "Local method invocation", callerInfo, callstack ); 945 } 946 947 if ( invokeMethod != null ) 948 return invokeMethod.invoke( 949 new Object [] { commandName, args }, 950 interpreter, callstack, callerInfo ); 951 952 throw new EvalError( "Command not found: " 953 +StringUtil.methodString( commandName, argTypes ), 954 callerInfo, callstack ); 955 } 956 957 if ( commandObject instanceof BshMethod ) 958 return ((BshMethod)commandObject).invoke( 959 args, interpreter, callstack, callerInfo ); 960 961 if ( commandObject instanceof Class ) 962 try { 963 return Reflect.invokeCompiledCommand( 964 ((Class )commandObject), args, interpreter, callstack ); 965 } catch ( UtilEvalError e ) { 966 throw e.toEvalError("Error invoking compiled command: ", 967 callerInfo, callstack ); 968 } 969 970 throw new InterpreterError("invalid command type"); 971 } 972 973 996 997 1000 public static boolean isCompound(String value) 1001 { 1002 return value.indexOf('.') != -1 ; 1003 } 1005 1006 static int countParts(String value) 1007 { 1008 if(value == null) 1009 return 0; 1010 1011 int count = 0; 1012 int index = -1; 1013 while((index = value.indexOf('.', index + 1)) != -1) 1014 count++; 1015 return count + 1; 1016 } 1017 1018 static String prefix(String value) 1019 { 1020 if(!isCompound(value)) 1021 return null; 1022 1023 return prefix(value, countParts(value) - 1); 1024 } 1025 1026 static String prefix(String value, int parts) 1027 { 1028 if (parts < 1 ) 1029 return null; 1030 1031 int count = 0; 1032 int index = -1; 1033 1034 while( ((index = value.indexOf('.', index + 1)) != -1) 1035 && (++count < parts) ) 1036 { ; } 1037 1038 return (index == -1) ? value : value.substring(0, index); 1039 } 1040 1041 static String suffix(String name) 1042 { 1043 if(!isCompound(name)) 1044 return null; 1045 1046 return suffix(name, countParts(name) - 1); 1047 } 1048 1049 public static String suffix(String value, int parts) 1050 { 1051 if (parts < 1) 1052 return null; 1053 1054 int count = 0; 1055 int index = value.length() + 1; 1056 1057 while ( ((index = value.lastIndexOf('.', index - 1)) != -1) 1058 && (++count < parts) ); 1059 1060 return (index == -1) ? value : value.substring(index + 1); 1061 } 1062 1063 1065 1066 public String toString() { return value; } 1067 1068} 1069 1070 | Popular Tags |