PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-1-pre5/bsh/BSHPrimarySuffix.java

#
Java | 233 lines | 134 code | 25 blank | 74 comment | 18 complexity | a46b3caa913aa30ec50d5be98e01d4ea MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*****************************************************************************
  2. * *
  3. * This file is part of the BeanShell Java Scripting distribution. *
  4. * Documentation and updates may be found at http://www.beanshell.org/ *
  5. * *
  6. * Sun Public License Notice: *
  7. * *
  8. * The contents of this file are subject to the Sun Public License Version *
  9. * 1.0 (the "License"); you may not use this file except in compliance with *
  10. * the License. A copy of the License is available at http://www.sun.com *
  11. * *
  12. * The Original Code is BeanShell. The Initial Developer of the Original *
  13. * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
  14. * (C) 2000. All Rights Reserved. *
  15. * *
  16. * GNU Public License Notice: *
  17. * *
  18. * Alternatively, the contents of this file may be used under the terms of *
  19. * the GNU Lesser General Public License (the "LGPL"), in which case the *
  20. * provisions of LGPL are applicable instead of those above. If you wish to *
  21. * allow use of your version of this file only under the terms of the LGPL *
  22. * and not to allow others to use your version of this file under the SPL, *
  23. * indicate your decision by deleting the provisions above and replace *
  24. * them with the notice and other provisions required by the LGPL. If you *
  25. * do not delete the provisions above, a recipient may use your version of *
  26. * this file under either the SPL or the LGPL. *
  27. * *
  28. * Patrick Niemeyer (pat@pat.net) *
  29. * Author of Learning Java, O'Reilly & Associates *
  30. * http://www.pat.net/~pat/ *
  31. * *
  32. *****************************************************************************/
  33. /*
  34. Warning: this is a hack... should be unified with BSHLHSPrimarySuffix
  35. */
  36. package bsh;
  37. import java.util.Hashtable;
  38. import java.lang.reflect.Array;
  39. import java.lang.reflect.InvocationTargetException;
  40. class BSHPrimarySuffix extends SimpleNode
  41. {
  42. public static final int
  43. CLASS = 0,
  44. INDEX = 1,
  45. NAME = 2,
  46. PROPERTY = 3;
  47. public int operation;
  48. Object index;
  49. public String field;
  50. BSHPrimarySuffix(int id) { super(id); }
  51. /*
  52. Perform a suffix operation on the given object and return the
  53. new value.
  54. obj will be a Node when suffix evaluation begins, allowing us to
  55. interpret it contextually. (e.g. for .class) Thereafter it will be
  56. a normal object.
  57. */
  58. public Object doSuffix(
  59. Object obj, CallStack callstack, Interpreter interpreter)
  60. throws EvalError
  61. {
  62. // Handle ".class" suffix operation
  63. /*
  64. if ( operation == CLASS )
  65. if ( obj instanceof BSHAmbiguousName ) {
  66. NameSpace namespace = callstack.top();
  67. return ((BSHAmbiguousName)obj).toClass( namespace );
  68. } else
  69. throw new EvalError(
  70. "Attemp to .class on non class...", this);
  71. */
  72. if ( operation == CLASS )
  73. if ( obj instanceof BSHType ) {
  74. NameSpace namespace = callstack.top();
  75. return ((BSHType)obj).getType( namespace );
  76. } else
  77. throw new EvalError(
  78. "Attemp to invoke .class on non class.", this);
  79. // Handle other suffix operations
  80. /*
  81. eval( ) the node to an object
  82. Note: This construct is now necessary where the node may be
  83. an ambiguous name. If this becomes common we might want to
  84. make a static method nodeToObject() or something.
  85. */
  86. if ( obj instanceof SimpleNode )
  87. if ( obj instanceof BSHAmbiguousName )
  88. obj = ((BSHAmbiguousName)obj).toObject(callstack, interpreter);
  89. else
  90. obj = ((SimpleNode)obj).eval(callstack, interpreter);
  91. try
  92. {
  93. switch(operation)
  94. {
  95. case INDEX:
  96. return doIndex(obj, callstack, interpreter );
  97. case NAME:
  98. return doName(obj, callstack, interpreter );
  99. case PROPERTY:
  100. return doProperty(obj, callstack, interpreter );
  101. default:
  102. throw new InterpreterError("LHS suffix");
  103. }
  104. }
  105. catch(ReflectError e)
  106. {
  107. throw new EvalError("reflection error: " + e, this);
  108. }
  109. catch(InvocationTargetException e)
  110. {
  111. throw new TargetError(
  112. "target exception", e.getTargetException(), this, true);
  113. }
  114. }
  115. /*
  116. Field access or a method invocation
  117. Field access might be .length on an array
  118. */
  119. private Object doName(
  120. Object obj, CallStack callstack, Interpreter interpreter)
  121. throws EvalError, ReflectError, InvocationTargetException
  122. {
  123. if(field.equals("length") && obj.getClass().isArray())
  124. return new Primitive(Array.getLength(obj));
  125. if (jjtGetNumChildren() == 0)
  126. // field access
  127. return Reflect.getObjectField(obj, field);
  128. else
  129. {
  130. // method invocation
  131. Object[] oa = ((BSHArguments)jjtGetChild(0)).getArguments(
  132. callstack, interpreter);
  133. try {
  134. return Reflect.invokeObjectMethod(interpreter, obj, field, oa, this);
  135. } catch ( EvalError ee ) {
  136. // catch and re-throw to get line number right
  137. throw new EvalError( ee.getMessage(), this );
  138. }
  139. }
  140. }
  141. /**
  142. Just factoring out some common code for the two suffix classes...
  143. later need to complete factoring of these classes
  144. (BSHPrimarySuffix, BSHLHSPrimarySuffix)
  145. */
  146. static int getIndexAux(
  147. Object obj, CallStack callstack, Interpreter interpreter,
  148. SimpleNode callerNode )
  149. throws EvalError
  150. {
  151. if ( !obj.getClass().isArray() )
  152. throw new EvalError("Not an array", callerNode );
  153. int index;
  154. try {
  155. Object indexVal =
  156. ((SimpleNode)callerNode.jjtGetChild(0)).eval(
  157. callstack, interpreter );
  158. if ( !(indexVal instanceof Primitive) )
  159. indexVal = NameSpace.getAssignableForm( indexVal, Integer.TYPE);
  160. index = ((Primitive)indexVal).intValue();
  161. } catch( EvalError e ) {
  162. Interpreter.debug("doIndex: "+e);
  163. e.reThrow(
  164. "You can only index arrays by integer types", callerNode );
  165. throw new Error("can't get here");
  166. }
  167. return index;
  168. }
  169. private Object doIndex(
  170. Object obj, CallStack callstack, Interpreter interpreter)
  171. throws EvalError, ReflectError
  172. {
  173. int index = getIndexAux( obj, callstack, interpreter, this );
  174. return Reflect.getIndex(obj, index);
  175. }
  176. private Object doProperty(
  177. Object obj, CallStack callstack, Interpreter interpreter )
  178. throws EvalError
  179. {
  180. if(obj == Primitive.VOID)
  181. throw new EvalError("Attempt to access property on undefined variable or class name", this);
  182. if(obj instanceof Primitive)
  183. throw new EvalError("Attempt to access property on a primitive", this);
  184. Object value = ((SimpleNode)jjtGetChild(0)).eval(
  185. callstack, interpreter);
  186. if(!(value instanceof String))
  187. throw new EvalError("Property expression must be a String or identifier.", this);
  188. // property style access to hashtable
  189. if(obj instanceof Hashtable)
  190. {
  191. Object val = ((Hashtable)obj).get((String)value);
  192. if(val == null)
  193. val = Primitive.NULL;
  194. return val;
  195. }
  196. try
  197. {
  198. return Reflect.getObjectProperty(obj, (String)value);
  199. }
  200. catch(ReflectError e)
  201. {
  202. Interpreter.debug(e.toString());
  203. throw new EvalError("No such property: " + value, this);
  204. }
  205. }
  206. }