PageRenderTime 66ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/bsh/ClassGeneratorImpl.java

#
Java | 316 lines | 228 code | 46 blank | 42 comment | 25 complexity | f83ab2c018bd5dc439b841bf9de2b09d 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. package org.gjt.sp.jedit.bsh;
  2. import java.io.*;
  3. import java.util.*;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. /**
  7. @author Pat Niemeyer (pat@pat.net)
  8. */
  9. public class ClassGeneratorImpl extends ClassGenerator
  10. {
  11. public Class generateClass(
  12. String name, Modifiers modifiers,
  13. Class [] interfaces, Class superClass, BSHBlock block,
  14. boolean isInterface, CallStack callstack, Interpreter interpreter
  15. )
  16. throws EvalError
  17. {
  18. // Delegate to the static method
  19. return generateClassImpl( name, modifiers, interfaces, superClass,
  20. block, isInterface, callstack, interpreter );
  21. }
  22. public Object invokeSuperclassMethod(
  23. BshClassManager bcm, Object instance, String methodName, Object [] args
  24. )
  25. throws UtilEvalError, ReflectError, InvocationTargetException
  26. {
  27. // Delegate to the static method
  28. return invokeSuperclassMethodImpl( bcm, instance, methodName, args );
  29. }
  30. /**
  31. Change the parent of the class instance namespace.
  32. This is currently used for inner class support.
  33. Note: This method will likely be removed in the future.
  34. */
  35. // This could be static
  36. public void setInstanceNameSpaceParent(
  37. Object instance, String className, NameSpace parent )
  38. {
  39. This ithis =
  40. ClassGeneratorUtil.getClassInstanceThis( instance, className );
  41. ithis.getNameSpace().setParent( parent );
  42. }
  43. /**
  44. Parse the BSHBlock for for the class definition and generate the class
  45. using ClassGenerator.
  46. */
  47. public static Class generateClassImpl(
  48. String name, Modifiers modifiers,
  49. Class [] interfaces, Class superClass, BSHBlock block,
  50. boolean isInterface, CallStack callstack, Interpreter interpreter
  51. )
  52. throws EvalError
  53. {
  54. // Scripting classes currently requires accessibility
  55. // This can be eliminated with a bit more work.
  56. try {
  57. Capabilities.setAccessibility( true );
  58. } catch ( Capabilities.Unavailable e )
  59. {
  60. throw new EvalError(
  61. "Defining classes currently requires reflective Accessibility.",
  62. block, callstack );
  63. }
  64. NameSpace enclosingNameSpace = callstack.top();
  65. String packageName = enclosingNameSpace.getPackage();
  66. String className = enclosingNameSpace.isClass ?
  67. ( enclosingNameSpace.getName()+"$"+name ) : name;
  68. String fqClassName =
  69. packageName == null ? className : packageName + "." + className;
  70. BshClassManager bcm = interpreter.getClassManager();
  71. // Race condition here...
  72. bcm.definingClass( fqClassName );
  73. // Create the class static namespace
  74. NameSpace classStaticNameSpace =
  75. new NameSpace( enclosingNameSpace, className);
  76. classStaticNameSpace.isClass = true;
  77. callstack.push( classStaticNameSpace );
  78. // Evaluate any inner class class definitions in the block
  79. // effectively recursively call this method for contained classes first
  80. block.evalBlock(
  81. callstack, interpreter, true/*override*/,
  82. ClassNodeFilter.CLASSCLASSES );
  83. // Generate the type for our class
  84. Variable [] variables =
  85. getDeclaredVariables( block, callstack, interpreter, packageName );
  86. DelayedEvalBshMethod [] methods =
  87. getDeclaredMethods( block, callstack, interpreter, packageName );
  88. ClassGeneratorUtil classGenerator = new ClassGeneratorUtil(
  89. modifiers, className, packageName, superClass, interfaces,
  90. variables, methods, classStaticNameSpace, isInterface );
  91. byte [] code = classGenerator.generateClass();
  92. // if debug, write out the class file to debugClasses directory
  93. String dir = System.getProperty("debugClasses");
  94. if ( dir != null )
  95. try {
  96. FileOutputStream out=
  97. new FileOutputStream( dir+"/"+className+".class" );
  98. out.write(code);
  99. out.close();
  100. } catch ( IOException e ) { }
  101. // Define the new class in the classloader
  102. Class genClass = bcm.defineClass( fqClassName, code );
  103. // import the unq name into parent
  104. enclosingNameSpace.importClass( fqClassName.replace('$','.') );
  105. try {
  106. classStaticNameSpace.setLocalVariable(
  107. ClassGeneratorUtil.BSHINIT, block, false/*strictJava*/ );
  108. } catch ( UtilEvalError e ) {
  109. throw new InterpreterError("unable to init static: "+e );
  110. }
  111. // Give the static space its class static import
  112. // important to do this after all classes are defined
  113. classStaticNameSpace.setClassStatic( genClass );
  114. // evaluate the static portion of the block in the static space
  115. block.evalBlock(
  116. callstack, interpreter, true/*override*/,
  117. ClassNodeFilter.CLASSSTATIC );
  118. callstack.pop();
  119. if ( !genClass.isInterface() )
  120. {
  121. // Set the static bsh This callback
  122. String bshStaticFieldName = ClassGeneratorUtil.BSHSTATIC+className;
  123. try {
  124. LHS lhs = Reflect.getLHSStaticField( genClass, bshStaticFieldName );
  125. lhs.assign(
  126. classStaticNameSpace.getThis( interpreter ), false/*strict*/ );
  127. } catch ( Exception e ) {
  128. throw new InterpreterError("Error in class gen setup: "+e );
  129. }
  130. }
  131. bcm.doneDefiningClass( fqClassName );
  132. return genClass;
  133. }
  134. static Variable [] getDeclaredVariables(
  135. BSHBlock body, CallStack callstack, Interpreter interpreter,
  136. String defaultPackage
  137. )
  138. {
  139. List vars = new ArrayList();
  140. for( int child=0; child<body.jjtGetNumChildren(); child++ )
  141. {
  142. SimpleNode node = (SimpleNode)body.jjtGetChild(child);
  143. if ( node instanceof BSHTypedVariableDeclaration )
  144. {
  145. BSHTypedVariableDeclaration tvd =
  146. (BSHTypedVariableDeclaration)node;
  147. Modifiers modifiers = tvd.modifiers;
  148. String type = tvd.getTypeDescriptor(
  149. callstack, interpreter, defaultPackage );
  150. BSHVariableDeclarator [] vardec = tvd.getDeclarators();
  151. for( int i = 0; i< vardec.length; i++)
  152. {
  153. String name = vardec[i].name;
  154. try {
  155. Variable var = new Variable(
  156. name, type, null/*value*/, modifiers );
  157. vars.add( var );
  158. } catch ( UtilEvalError e ) {
  159. // value error shouldn't happen
  160. }
  161. }
  162. }
  163. }
  164. return (Variable [])vars.toArray( new Variable[0] );
  165. }
  166. static DelayedEvalBshMethod [] getDeclaredMethods(
  167. BSHBlock body, CallStack callstack, Interpreter interpreter,
  168. String defaultPackage
  169. )
  170. throws EvalError
  171. {
  172. List methods = new ArrayList();
  173. for( int child=0; child<body.jjtGetNumChildren(); child++ )
  174. {
  175. SimpleNode node = (SimpleNode)body.jjtGetChild(child);
  176. if ( node instanceof BSHMethodDeclaration )
  177. {
  178. BSHMethodDeclaration md = (BSHMethodDeclaration)node;
  179. md.insureNodesParsed();
  180. Modifiers modifiers = md.modifiers;
  181. String name = md.name;
  182. String returnType = md.getReturnTypeDescriptor(
  183. callstack, interpreter, defaultPackage );
  184. BSHReturnType returnTypeNode = md.getReturnTypeNode();
  185. BSHFormalParameters paramTypesNode = md.paramsNode;
  186. String [] paramTypes = paramTypesNode.getTypeDescriptors(
  187. callstack, interpreter, defaultPackage );
  188. DelayedEvalBshMethod bm = new DelayedEvalBshMethod(
  189. name,
  190. returnType, returnTypeNode,
  191. md.paramsNode.getParamNames(),
  192. paramTypes, paramTypesNode,
  193. md.blockNode, null/*declaringNameSpace*/,
  194. modifiers, callstack, interpreter
  195. );
  196. methods.add( bm );
  197. }
  198. }
  199. return (DelayedEvalBshMethod [])methods.toArray(
  200. new DelayedEvalBshMethod[0] );
  201. }
  202. /**
  203. A node filter that filters nodes for either a class body static
  204. initializer or instance initializer. In the static case only static
  205. members are passed, etc.
  206. */
  207. static class ClassNodeFilter implements BSHBlock.NodeFilter
  208. {
  209. public static final int STATIC=0, INSTANCE=1, CLASSES=2;
  210. public static ClassNodeFilter CLASSSTATIC =
  211. new ClassNodeFilter( STATIC );
  212. public static ClassNodeFilter CLASSINSTANCE =
  213. new ClassNodeFilter( INSTANCE );
  214. public static ClassNodeFilter CLASSCLASSES =
  215. new ClassNodeFilter( CLASSES );
  216. int context;
  217. private ClassNodeFilter( int context ) { this.context = context; }
  218. public boolean isVisible( SimpleNode node )
  219. {
  220. if ( context == CLASSES )
  221. return node instanceof BSHClassDeclaration;
  222. // Only show class decs in CLASSES
  223. if ( node instanceof BSHClassDeclaration )
  224. return false;
  225. if ( context == STATIC )
  226. return isStatic( node );
  227. if ( context == INSTANCE )
  228. return !isStatic( node );
  229. // ALL
  230. return true;
  231. }
  232. boolean isStatic( SimpleNode node )
  233. {
  234. if ( node instanceof BSHTypedVariableDeclaration )
  235. return ((BSHTypedVariableDeclaration)node).modifiers != null
  236. && ((BSHTypedVariableDeclaration)node).modifiers
  237. .hasModifier("static");
  238. if ( node instanceof BSHMethodDeclaration )
  239. return ((BSHMethodDeclaration)node).modifiers != null
  240. && ((BSHMethodDeclaration)node).modifiers
  241. .hasModifier("static");
  242. // need to add static block here
  243. if ( node instanceof BSHBlock)
  244. return false;
  245. return false;
  246. }
  247. }
  248. public static Object invokeSuperclassMethodImpl(
  249. BshClassManager bcm, Object instance, String methodName, Object [] args
  250. )
  251. throws UtilEvalError, ReflectError, InvocationTargetException
  252. {
  253. String superName = ClassGeneratorUtil.BSHSUPER+methodName;
  254. // look for the specially named super delegate method
  255. Class clas = instance.getClass();
  256. Method superMethod = Reflect.resolveJavaMethod(
  257. bcm, clas, superName, Types.getTypes(args), false/*onlyStatic*/ );
  258. if ( superMethod != null )
  259. return Reflect.invokeMethod(
  260. superMethod, instance, args );
  261. // No super method, try to invoke regular method
  262. // could be a superfluous "super." which is legal.
  263. Class superClass = clas.getSuperclass();
  264. superMethod = Reflect.resolveExpectedJavaMethod(
  265. bcm, superClass, instance, methodName, args,
  266. false/*onlyStatic*/ );
  267. return Reflect.invokeMethod( superMethod, instance, args );
  268. }
  269. }