PageRenderTime 46ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/bsh/BshMethod.java

#
Java | 207 lines | 101 code | 20 blank | 86 comment | 20 complexity | 7328a0a0d2c4d6df6c1f79a7707b35d2 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. package bsh;
  34. /**
  35. This represents an *instance* of a bsh method declaration in a particular
  36. namespace. This is a thin wrapper around the BSHMethodDeclaration
  37. with a pointer to the declaring namespace.
  38. The issue is that when a method is located in a subordinate namespace or
  39. invoked from an arbitrary namespace it must nontheless execute with its
  40. 'super' as the context in which it was declared.
  41. i.e.
  42. The local method context is a child namespace of the declaring namespace.
  43. */
  44. class BshMethod implements java.io.Serializable
  45. {
  46. BSHMethodDeclaration method;
  47. /*
  48. I believe this is always the namespace in which the method is
  49. defined... It is a back-reference for the node, which needs to
  50. execute under this namespace.
  51. So it is not necessary to declare this transient, because we can
  52. only be saved as part of our namespace anyway... (currently).
  53. */
  54. NameSpace declaringNameSpace;
  55. private Class [] argTypes;
  56. BshMethod(
  57. BSHMethodDeclaration method, NameSpace declaringNameSpace )
  58. {
  59. this.method = method;
  60. this.declaringNameSpace = declaringNameSpace;
  61. }
  62. /**
  63. Note: bshmethod needs to re-evaluate arg types here
  64. This is broken
  65. */
  66. public Class [] getArgTypes() {
  67. if ( argTypes == null )
  68. // should re-eval here...
  69. argTypes = method.params.argTypes ;
  70. return argTypes;
  71. }
  72. /**
  73. Invoke the bsh method with the specified args, interpreter ref,
  74. and callstack.
  75. callerInfo is the node representing the method invocation
  76. It is used primarily for debugging in order to provide access to the
  77. text of the construct that invoked the method through the namespace.
  78. @param callerInfo is the node representing the method invocation
  79. This is used primarily for debugging and may be null.
  80. @param callstack is the callstack of course. If you are using a
  81. hacked version of BeanShell that exposed this method take a look
  82. at NameSpace invokeMethod to see how to make a fake callstack...
  83. */
  84. public Object invokeDeclaredMethod(
  85. Object[] argValues, Interpreter interpreter, CallStack callstack,
  86. SimpleNode callerInfo )
  87. throws EvalError
  88. {
  89. if ( argValues == null )
  90. argValues = new Object [] { };
  91. // Cardinality (number of args) mismatch
  92. if ( argValues.length != method.params.numArgs ) {
  93. // look for help string
  94. try {
  95. // should check for null namespace here
  96. String help =
  97. (String)declaringNameSpace.get(
  98. "bsh.help."+method.name, interpreter );
  99. interpreter.println(help);
  100. return Primitive.VOID;
  101. } catch ( Exception e ) {
  102. throw new EvalError(
  103. "Wrong number of arguments for local method: "
  104. + method.name, callerInfo);
  105. }
  106. }
  107. // Make the local namespace for the method invocation
  108. NameSpace localNameSpace = new NameSpace(
  109. declaringNameSpace, method.name );
  110. localNameSpace.setNode( callerInfo );
  111. // set the method parameters in the local namespace
  112. for(int i=0; i<method.params.numArgs; i++)
  113. {
  114. // Set typed variable
  115. if ( method.params.argTypes[i] != null )
  116. {
  117. try {
  118. argValues[i] = NameSpace.getAssignableForm(argValues[i],
  119. method.params.argTypes[i]);
  120. }
  121. catch(EvalError e) {
  122. throw new EvalError(
  123. "Invalid argument: "
  124. + "`"+method.params.argNames[i]+"'" + " for method: "
  125. + method.name + " : " +
  126. e.getMessage(), callerInfo);
  127. }
  128. localNameSpace.setTypedVariable( method.params.argNames[i],
  129. method.params.argTypes[i], argValues[i], false);
  130. }
  131. // Set untyped variable
  132. else // untyped param
  133. {
  134. // checkAssignable would catch this for typed param
  135. if ( argValues[i] == Primitive.VOID)
  136. throw new EvalError(
  137. "Undefined variable or class name, parameter: " +
  138. method.params.argNames[i] + " to method: "
  139. + method.name, callerInfo);
  140. else
  141. localNameSpace.setVariable(
  142. method.params.argNames[i], argValues[i]);
  143. }
  144. }
  145. // Push the new namespace on the call stack
  146. callstack.push( localNameSpace );
  147. // Invoke the method
  148. Object ret = method.block.eval( callstack, interpreter, true );
  149. // pop back to caller namespace
  150. callstack.pop();
  151. if ( ret instanceof ReturnControl )
  152. {
  153. ReturnControl rs = (ReturnControl)ret;
  154. if(rs.kind == rs.RETURN)
  155. ret = ((ReturnControl)ret).value;
  156. else
  157. // This error points to the method, should it?
  158. throw new EvalError("continue or break in method body", method);
  159. }
  160. // there should be a check in here for an explicit value return
  161. // from a void type method... (throw evalerror)
  162. if(method.returnType != null)
  163. {
  164. // if void return type throw away any value
  165. // ideally, we'd error on an explicit 'return' of value
  166. if(method.returnType == Primitive.VOID)
  167. return method.returnType;
  168. // return type is a class
  169. try {
  170. ret = NameSpace.getAssignableForm(
  171. ret, (Class)method.returnType);
  172. }
  173. catch(EvalError e) {
  174. // This error points to the method, should it?
  175. throw new EvalError(
  176. "Incorrect type returned from method: "
  177. + method.name + e.getMessage(), method);
  178. }
  179. }
  180. return ret;
  181. }
  182. public String toString() {
  183. return "Bsh Method: "+method.name;
  184. }
  185. }