static DelayedEvalBshMethod[] getDeclaredMethods( BSHBlock body, CallStack callstack, Interpreter interpreter, String defaultPackage) throws EvalError { List<DelayedEvalBshMethod> methods = new ArrayList<DelayedEvalBshMethod>(); 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 methods.toArray(new DelayedEvalBshMethod[methods.size()]); }
static Variable[] getDeclaredVariables( BSHBlock body, CallStack callstack, Interpreter interpreter, String defaultPackage) { List<Variable> vars = new ArrayList<Variable>(); 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 (BSHVariableDeclarator aVardec : vardec) { String name = aVardec.name; try { Variable var = new Variable(name, type, null /*value*/, modifiers); vars.add(var); } catch (UtilEvalError e) { // value error shouldn't happen } } } } return vars.toArray(new Variable[vars.size()]); }
/** * 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 if (DEBUG_DIR != null) try { FileOutputStream out = new FileOutputStream(DEBUG_DIR + '/' + className + ".class"); out.write(code); out.close(); } catch (IOException e) { throw new IllegalStateException( "cannot create file " + DEBUG_DIR + '/' + className + ".class", 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; }