PageRenderTime 23ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/bsh/ClassGeneratorImpl.java

#
Java | 327 lines | 225 code | 51 blank | 51 comment | 26 complexity | 098ca364a7dee4c0bbde5bcb27630e55 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 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. Capabilities.setAccessibility( true );
  57. if ( !Capabilities.haveAccessibility() )
  58. throw new InterpreterError(
  59. "Defining classes currently requires reflect Accessibility.");
  60. NameSpace enclosingNameSpace = callstack.top();
  61. String packageName = enclosingNameSpace.getPackage();
  62. String className = enclosingNameSpace.isClass ?
  63. ( enclosingNameSpace.getName()+"$"+name ) : name;
  64. String fqClassName =
  65. packageName == null ? className : packageName + "." + className;
  66. BshClassManager bcm = interpreter.getClassManager();
  67. // Race condition here...
  68. bcm.definingClass( fqClassName );
  69. // Create the class static namespace
  70. NameSpace classStaticNameSpace =
  71. new NameSpace( enclosingNameSpace, className);
  72. classStaticNameSpace.isClass = true;
  73. callstack.push( classStaticNameSpace );
  74. // Evaluate any inner class class definitions in the block
  75. // effectively recursively call this method for contained classes first
  76. block.evalBlock(
  77. callstack, interpreter, true/*override*/,
  78. ClassNodeFilter.CLASSCLASSES );
  79. // Generate the type for our class
  80. Variable [] variables =
  81. getDeclaredVariables( block, callstack, interpreter, packageName );
  82. DelayedEvalBshMethod [] methods =
  83. getDeclaredMethods( block, callstack, interpreter, packageName );
  84. ClassGeneratorUtil classGenerator = new ClassGeneratorUtil(
  85. modifiers, className, packageName, superClass, interfaces,
  86. variables, methods, classStaticNameSpace, isInterface );
  87. byte [] code = classGenerator.generateClass();
  88. // if debug, write out the class file to debugClasses directory
  89. String dir = System.getProperty("debugClasses");
  90. if ( dir != null )
  91. try {
  92. FileOutputStream out=
  93. new FileOutputStream( dir+"/"+className+".class" );
  94. out.write(code);
  95. out.close();
  96. } catch ( IOException e ) { }
  97. // Define the new class in the classloader
  98. Class genClass = bcm.defineClass( fqClassName, code );
  99. //bcm.doneDefiningClass( fqClassName );
  100. // import the unq name into parent
  101. enclosingNameSpace.importClass( fqClassName.replace('$','.') );
  102. // Also cache the class so that no import resolution must occur
  103. // this avoids having to load our enclosing class which isn't
  104. // finished being generated yet... oy.
  105. // caching is not correct and doesn't seem to help...
  106. // enclosingNameSpace.cacheClass( name, genClass );
  107. // Also cache it in the static namespace...
  108. //classStaticNameSpace.cacheClass( name, genClass );
  109. //classStaticNameSpace.importClass( fqClassName.replace('$','.') );
  110. try {
  111. classStaticNameSpace.setLocalVariable(
  112. ClassGeneratorUtil.BSHINIT, block, false/*strictJava*/ );
  113. } catch ( UtilEvalError e ) {
  114. throw new InterpreterError("unable to init static: "+e );
  115. }
  116. // Give the static space its class static import
  117. // important to do this after all classes are defined
  118. classStaticNameSpace.setClassStatic( genClass );
  119. // evaluate the static portion of the block in the static space
  120. block.evalBlock(
  121. callstack, interpreter, true/*override*/,
  122. ClassNodeFilter.CLASSSTATIC );
  123. callstack.pop();
  124. if ( !genClass.isInterface() )
  125. {
  126. // Set the static bsh This callback
  127. String bshStaticFieldName = ClassGeneratorUtil.BSHSTATIC+className;
  128. try {
  129. LHS lhs = Reflect.getLHSStaticField( genClass, bshStaticFieldName );
  130. lhs.assign(
  131. classStaticNameSpace.getThis( interpreter ), false/*strict*/ );
  132. } catch ( Exception e ) {
  133. throw new InterpreterError("Error in class gen setup: "+e );
  134. }
  135. }
  136. bcm.doneDefiningClass( fqClassName );
  137. return genClass;
  138. }
  139. static Variable [] getDeclaredVariables(
  140. BSHBlock body, CallStack callstack, Interpreter interpreter,
  141. String defaultPackage
  142. )
  143. throws EvalError
  144. {
  145. List vars = new ArrayList();
  146. for( int child=0; child<body.jjtGetNumChildren(); child++ )
  147. {
  148. SimpleNode node = (SimpleNode)body.jjtGetChild(child);
  149. if ( node instanceof BSHTypedVariableDeclaration )
  150. {
  151. BSHTypedVariableDeclaration tvd =
  152. (BSHTypedVariableDeclaration)node;
  153. Modifiers modifiers = tvd.modifiers;
  154. String type = tvd.getTypeDescriptor(
  155. callstack, interpreter, defaultPackage );
  156. BSHVariableDeclarator [] vardec = tvd.getDeclarators();
  157. for( int i = 0; i< vardec.length; i++)
  158. {
  159. String name = vardec[i].name;
  160. try {
  161. Variable var = new Variable(
  162. name, type, null/*value*/, modifiers );
  163. vars.add( var );
  164. } catch ( UtilEvalError e ) {
  165. // value error shouldn't happen
  166. }
  167. }
  168. }
  169. }
  170. return (Variable [])vars.toArray( new Variable[0] );
  171. }
  172. static DelayedEvalBshMethod [] getDeclaredMethods(
  173. BSHBlock body, CallStack callstack, Interpreter interpreter,
  174. String defaultPackage
  175. )
  176. throws EvalError
  177. {
  178. List methods = new ArrayList();
  179. for( int child=0; child<body.jjtGetNumChildren(); child++ )
  180. {
  181. SimpleNode node = (SimpleNode)body.jjtGetChild(child);
  182. if ( node instanceof BSHMethodDeclaration )
  183. {
  184. BSHMethodDeclaration md = (BSHMethodDeclaration)node;
  185. md.insureNodesParsed();
  186. Modifiers modifiers = md.modifiers;
  187. String name = md.name;
  188. String returnType = md.getReturnTypeDescriptor(
  189. callstack, interpreter, defaultPackage );
  190. BSHReturnType returnTypeNode = md.getReturnTypeNode();
  191. BSHFormalParameters paramTypesNode = md.paramsNode;
  192. String [] paramTypes = paramTypesNode.getTypeDescriptors(
  193. callstack, interpreter, defaultPackage );
  194. DelayedEvalBshMethod bm = new DelayedEvalBshMethod(
  195. name,
  196. returnType, returnTypeNode,
  197. md.paramsNode.getParamNames(),
  198. paramTypes, paramTypesNode,
  199. md.blockNode, null/*declaringNameSpace*/,
  200. modifiers, callstack, interpreter
  201. );
  202. methods.add( bm );
  203. }
  204. }
  205. return (DelayedEvalBshMethod [])methods.toArray(
  206. new DelayedEvalBshMethod[0] );
  207. }
  208. /**
  209. A node filter that filters nodes for either a class body static
  210. initializer or instance initializer. In the static case only static
  211. members are passed, etc.
  212. */
  213. static class ClassNodeFilter implements BSHBlock.NodeFilter
  214. {
  215. public static final int STATIC=0, INSTANCE=1, CLASSES=2;
  216. public static ClassNodeFilter CLASSSTATIC =
  217. new ClassNodeFilter( STATIC );
  218. public static ClassNodeFilter CLASSINSTANCE =
  219. new ClassNodeFilter( INSTANCE );
  220. public static ClassNodeFilter CLASSCLASSES =
  221. new ClassNodeFilter( CLASSES );
  222. int context;
  223. private ClassNodeFilter( int context ) { this.context = context; }
  224. public boolean isVisible( SimpleNode node )
  225. {
  226. if ( context == CLASSES )
  227. return node instanceof BSHClassDeclaration;
  228. // Only show class decs in CLASSES
  229. if ( node instanceof BSHClassDeclaration )
  230. return false;
  231. if ( context == STATIC )
  232. return isStatic( node );
  233. if ( context == INSTANCE )
  234. return !isStatic( node );
  235. // ALL
  236. return true;
  237. }
  238. boolean isStatic( SimpleNode node )
  239. {
  240. if ( node instanceof BSHTypedVariableDeclaration )
  241. return ((BSHTypedVariableDeclaration)node).modifiers != null
  242. && ((BSHTypedVariableDeclaration)node).modifiers
  243. .hasModifier("static");
  244. if ( node instanceof BSHMethodDeclaration )
  245. return ((BSHMethodDeclaration)node).modifiers != null
  246. && ((BSHMethodDeclaration)node).modifiers
  247. .hasModifier("static");
  248. // need to add static block here
  249. if ( node instanceof BSHBlock)
  250. return false;
  251. return false;
  252. }
  253. }
  254. public static Object invokeSuperclassMethodImpl(
  255. BshClassManager bcm, Object instance, String methodName, Object [] args
  256. )
  257. throws UtilEvalError, ReflectError, InvocationTargetException
  258. {
  259. String superName = ClassGeneratorUtil.BSHSUPER+methodName;
  260. // look for the specially named super delegate method
  261. Class clas = instance.getClass();
  262. Method superMethod = Reflect.resolveJavaMethod(
  263. bcm, clas, superName, Types.getTypes(args), false/*onlyStatic*/ );
  264. if ( superMethod != null )
  265. return Reflect.invokeOnMethod(
  266. superMethod, instance, args );
  267. // No super method, try to invoke regular method
  268. // could be a superfluous "super." which is legal.
  269. Class superClass = clas.getSuperclass();
  270. superMethod = Reflect.resolveExpectedJavaMethod(
  271. bcm, superClass, instance, methodName, args,
  272. false/*onlyStatic*/ );
  273. return Reflect.invokeOnMethod( superMethod, instance, args );
  274. }
  275. }