/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
- package org.gjt.sp.jedit.bsh;
- import java.io.*;
- import java.util.*;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
-
- @author Pat Niemeyer (pat@pat.net)
- */
- public class ClassGeneratorImpl extends ClassGenerator
- {
- public Class generateClass(
- String name, Modifiers modifiers,
- Class [] interfaces, Class superClass, BSHBlock block,
- boolean isInterface, CallStack callstack, Interpreter interpreter
- )
- throws EvalError
- {
- // Delegate to the static method
- return generateClassImpl( name, modifiers, interfaces, superClass,
- block, isInterface, callstack, interpreter );
- }
- public Object invokeSuperclassMethod(
- BshClassManager bcm, Object instance, String methodName, Object [] args
- )
- throws UtilEvalError, ReflectError, InvocationTargetException
- {
- // Delegate to the static method
- return invokeSuperclassMethodImpl( bcm, instance, methodName, args );
- }
- /**
- Change the parent of the class instance namespace.
- This is currently used for inner class support.
- Note: This method will likely be removed in the future.
- */
- // This could be static
- public void setInstanceNameSpaceParent(
- Object instance, String className, NameSpace parent )
- {
- This ithis =
- ClassGeneratorUtil.getClassInstanceThis( instance, className );
- ithis.getNameSpace().setParent( parent );
- }
- /**
- Parse the BSHBlock for for the class definition and generate the class
- using ClassGenerator.
- */
- public static Class generateClassImpl(
- String name, Modifiers modifiers,
- Class [] interfaces, Class superClass, BSHBlock block,
- boolean isInterface, CallStack callstack, Interpreter interpreter
- )
- throws EvalError
- {
- // Scripting classes currently requires accessibility
- // This can be eliminated with a bit more work.
- try {
- Capabilities.setAccessibility( true );
- } catch ( Capabilities.Unavailable e )
- {
- throw new EvalError(
- "Defining classes currently requires reflective Accessibility.",
- block, callstack );
- }
- NameSpace enclosingNameSpace = callstack.top();
- String packageName = enclosingNameSpace.getPackage();
- String className = enclosingNameSpace.isClass ?
- ( enclosingNameSpace.getName()+"$"+name ) : name;
- String fqClassName =
- packageName == null ? className : packageName + "." + className;
- BshClassManager bcm = interpreter.getClassManager();
- // Race condition here...
- bcm.definingClass( fqClassName );
- // Create the class static namespace
- NameSpace classStaticNameSpace =
- new NameSpace( enclosingNameSpace, className);
- classStaticNameSpace.isClass = true;
- callstack.push( classStaticNameSpace );
- // Evaluate any inner class class definitions in the block
- // effectively recursively call this method for contained classes first
- block.evalBlock(
- callstack, interpreter, true/*override*/,
- ClassNodeFilter.CLASSCLASSES );
- // Generate the type for our class
- Variable [] variables =
- getDeclaredVariables( block, callstack, interpreter, packageName );
- DelayedEvalBshMethod [] methods =
- getDeclaredMethods( block, callstack, interpreter, packageName );
- ClassGeneratorUtil classGenerator = new ClassGeneratorUtil(
- modifiers, className, packageName, superClass, interfaces,
- variables, methods, classStaticNameSpace, isInterface );
- byte [] code = classGenerator.generateClass();
- // if debug, write out the class file to debugClasses directory
- String dir = System.getProperty("debugClasses");
- if ( dir != null )
- try {
- FileOutputStream out=
- new FileOutputStream( dir+"/"+className+".class" );
- out.write(code);
- out.close();
- } catch ( IOException e ) { }
- // Define the new class in the classloader
- Class genClass = bcm.defineClass( fqClassName, code );
- // import the unq name into parent
- enclosingNameSpace.importClass( fqClassName.replace('$','.') );
- try {
- classStaticNameSpace.setLocalVariable(
- ClassGeneratorUtil.BSHINIT, block, false/*strictJava*/ );
- } catch ( UtilEvalError e ) {
- throw new InterpreterError("unable to init static: "+e );
- }
- // Give the static space its class static import
- // important to do this after all classes are defined
- classStaticNameSpace.setClassStatic( genClass );
- // evaluate the static portion of the block in the static space
- block.evalBlock(
- callstack, interpreter, true/*override*/,
- ClassNodeFilter.CLASSSTATIC );
- callstack.pop();
- if ( !genClass.isInterface() )
- {
- // Set the static bsh This callback
- String bshStaticFieldName = ClassGeneratorUtil.BSHSTATIC+className;
- try {
- LHS lhs = Reflect.getLHSStaticField( genClass, bshStaticFieldName );
- lhs.assign(
- classStaticNameSpace.getThis( interpreter ), false/*strict*/ );
- } catch ( Exception e ) {
- throw new InterpreterError("Error in class gen setup: "+e );
- }
- }
- bcm.doneDefiningClass( fqClassName );
- return genClass;
- }
- static Variable [] getDeclaredVariables(
- BSHBlock body, CallStack callstack, Interpreter interpreter,
- String defaultPackage
- )
- {
- List vars = new ArrayList();
- for( int child=0; child<body.jjtGetNumChildren(); child++ )
- {
- SimpleNode node = (SimpleNode)body.jjtGetChild(child);
- if ( node instanceof BSHTypedVariableDeclaration )
- {
- BSHTypedVariableDeclaration tvd =
- (BSHTypedVariableDeclaration)node;
- Modifiers modifiers = tvd.modifiers;
- String type = tvd.getTypeDescriptor(
- callstack, interpreter, defaultPackage );
- BSHVariableDeclarator [] vardec = tvd.getDeclarators();
- for( int i = 0; i< vardec.length; i++)
- {
- String name = vardec[i].name;
- try {
- Variable var = new Variable(
- name, type, null/*value*/, modifiers );
- vars.add( var );
- } catch ( UtilEvalError e ) {
- // value error shouldn't happen
- }
- }
- }
- }
- return (Variable [])vars.toArray( new Variable[0] );
- }
- static DelayedEvalBshMethod [] getDeclaredMethods(
- BSHBlock body, CallStack callstack, Interpreter interpreter,
- String defaultPackage
- )
- throws EvalError
- {
- List methods = new ArrayList();
- for( int child=0; child<body.jjtGetNumChildren(); child++ )
- {
- SimpleNode node = (SimpleNode)body.jjtGetChild(child);
- if ( node instanceof BSHMethodDeclaration )
- {
- BSHMethodDeclaration md = (BSHMethodDeclaration)node;
- md.insureNodesParsed();
- Modifiers modifiers = md.modifiers;
- String name = md.name;
- String returnType = md.getReturnTypeDescriptor(
- callstack, interpreter, defaultPackage );
- BSHReturnType returnTypeNode = md.getReturnTypeNode();
- BSHFormalParameters paramTypesNode = md.paramsNode;
- String [] paramTypes = paramTypesNode.getTypeDescriptors(
- callstack, interpreter, defaultPackage );
- DelayedEvalBshMethod bm = new DelayedEvalBshMethod(
- name,
- returnType, returnTypeNode,
- md.paramsNode.getParamNames(),
- paramTypes, paramTypesNode,
- md.blockNode, null/*declaringNameSpace*/,
- modifiers, callstack, interpreter
- );
- methods.add( bm );
- }
- }
- return (DelayedEvalBshMethod [])methods.toArray(
- new DelayedEvalBshMethod[0] );
- }
- /**
- A node filter that filters nodes for either a class body static
- initializer or instance initializer. In the static case only static
- members are passed, etc.
- */
- static class ClassNodeFilter implements BSHBlock.NodeFilter
- {
- public static final int STATIC=0, INSTANCE=1, CLASSES=2;
- public static ClassNodeFilter CLASSSTATIC =
- new ClassNodeFilter( STATIC );
- public static ClassNodeFilter CLASSINSTANCE =
- new ClassNodeFilter( INSTANCE );
- public static ClassNodeFilter CLASSCLASSES =
- new ClassNodeFilter( CLASSES );
- int context;
- private ClassNodeFilter( int context ) { this.context = context; }
- public boolean isVisible( SimpleNode node )
- {
- if ( context == CLASSES )
- return node instanceof BSHClassDeclaration;
- // Only show class decs in CLASSES
- if ( node instanceof BSHClassDeclaration )
- return false;
- if ( context == STATIC )
- return isStatic( node );
- if ( context == INSTANCE )
- return !isStatic( node );
- // ALL
- return true;
- }
- boolean isStatic( SimpleNode node )
- {
- if ( node instanceof BSHTypedVariableDeclaration )
- return ((BSHTypedVariableDeclaration)node).modifiers != null
- && ((BSHTypedVariableDeclaration)node).modifiers
- .hasModifier("static");
- if ( node instanceof BSHMethodDeclaration )
- return ((BSHMethodDeclaration)node).modifiers != null
- && ((BSHMethodDeclaration)node).modifiers
- .hasModifier("static");
- // need to add static block here
- if ( node instanceof BSHBlock)
- return false;
- return false;
- }
- }
- public static Object invokeSuperclassMethodImpl(
- BshClassManager bcm, Object instance, String methodName, Object [] args
- )
- throws UtilEvalError, ReflectError, InvocationTargetException
- {
- String superName = ClassGeneratorUtil.BSHSUPER+methodName;
-
- // look for the specially named super delegate method
- Class clas = instance.getClass();
- Method superMethod = Reflect.resolveJavaMethod(
- bcm, clas, superName, Types.getTypes(args), false/*onlyStatic*/ );
- if ( superMethod != null )
- return Reflect.invokeMethod(
- superMethod, instance, args );
- // No super method, try to invoke regular method
- // could be a superfluous "super." which is legal.
- Class superClass = clas.getSuperclass();
- superMethod = Reflect.resolveExpectedJavaMethod(
- bcm, superClass, instance, methodName, args,
- false/*onlyStatic*/ );
- return Reflect.invokeMethod( superMethod, instance, args );
- }
- }