Logo Search packages:      
Sourcecode: janino version File versions  Download package

final void org::codehaus::janino::ScriptEvaluator::cook ( Scanner[]  scanners  )  throws CompileException, Parser.ParseException, Scanner.ScanException, IOException [inline]

Like cook(Scanner), but cooks a set of scripts into one class. Notice that if any of the scripts causes trouble, the entire compilation will fail. If you need to report which of the scripts causes the exception, you may want to use the optionalFileName argument of Scanner#Scanner(String, Reader) to distinguish between the individual token sources.

On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling 10000 expressions "a + b" (integer) takes about 4 seconds and 56 MB of main memory. The generated class file is 639203 bytes large.

The number and the complexity of the scripts is restricted by the Limitations of the Java Virtual Machine, where the most limiting factor is the 64K entries limit of the constant pool. Since every method with a distinct name requires one entry there, you can define at best 32K (very simple) scripts.

If and only if the number of scanners is one, then that single script may contain leading IMPORT directives.

Exceptions:
IllegalStateException if any of the preceeding set...() had an array size different from that of scanners

Definition at line 539 of file ScriptEvaluator.java.

References org::codehaus::janino::ClassBodyEvaluator::addPackageMemberClassDeclaration(), org::codehaus::janino::ClassBodyEvaluator::compileToClass(), org::codehaus::janino::SimpleCompiler::equals(), org::codehaus::janino::Scanner::location(), makeBlock(), org::codehaus::janino::ClassBodyEvaluator::makeCompilationUnit(), makeMethodDeclaration(), and org::codehaus::janino::SimpleCompiler::setUpClassLoaders().

                                                                                       {
        if (scanners == null) throw new NullPointerException();

        // The "dimension" of this ScriptEvaluator, i.e. how many scripts are cooked at the same
        // time.
        int count = scanners.length;

        // Check array sizes.
        if (this.optionalMethodNames      != null && this.optionalMethodNames.length      != count) throw new IllegalStateException("methodName");
        if (this.optionalParameterNames   != null && this.optionalParameterNames.length   != count) throw new IllegalStateException("parameterNames");
        if (this.optionalParameterTypes   != null && this.optionalParameterTypes.length   != count) throw new IllegalStateException("parameterTypes");
        if (this.optionalReturnTypes      != null && this.optionalReturnTypes.length      != count) throw new IllegalStateException("returnTypes");
        if (this.optionalStaticMethod     != null && this.optionalStaticMethod.length     != count) throw new IllegalStateException("staticMethod");
        if (this.optionalThrownExceptions != null && this.optionalThrownExceptions.length != count) throw new IllegalStateException("thrownExceptions");

        this.setUpClassLoaders();

        // Create compilation unit.
        Java.CompilationUnit compilationUnit = this.makeCompilationUnit(count == 1 ? scanners[0] : null);

        // Create class declaration.
        Java.ClassDeclaration cd = this.addPackageMemberClassDeclaration(scanners[0].location(), compilationUnit);

        // Determine method names.
        String[] methodNames;
        if (this.optionalMethodNames == null) {
            methodNames = new String[count];
            for (int i = 0; i < count; ++i) methodNames[i] = "eval" + i;
        } else
        {
            methodNames = this.optionalMethodNames;
        }

        // Create methods with one block each.
        for (int i = 0; i < count; ++i) {
            Scanner s = scanners[i];

            Java.Block block = this.makeBlock(i, scanners[i]);

            // Determine the following script properties AFTER the call to "makeBlock()",
            // because "makeBlock()" may modify these script properties on-the-fly.
            boolean  staticMethod     = this.optionalStaticMethod     == null ? true : this.optionalStaticMethod[i];
            Class    returnType       = this.optionalReturnTypes      == null ? this.getDefaultReturnType() : this.optionalReturnTypes[i];
            String[] parameterNames   = this.optionalParameterNames   == null ? new String[0] : this.optionalParameterNames[i];
            Class[]  parameterTypes   = this.optionalParameterTypes   == null ? new Class[0] : this.optionalParameterTypes[i];
            Class[]  thrownExceptions = this.optionalThrownExceptions == null ? new Class[0] : this.optionalThrownExceptions[i];

            cd.addDeclaredMethod(this.makeMethodDeclaration(
                s.location(),     // location
                staticMethod,     // staticMethod
                returnType,       // returnType
                methodNames[i],   // methodName
                parameterTypes,   // parameterTypes
                parameterNames,   // parameterNames
                thrownExceptions, // thrownExceptions
                block             // optionalBody
            ));
        }

        // Compile and load the compilation unit.
        Class c = this.compileToClass(
            compilationUnit,                                    // compilationUnit
            DebuggingInformation.DEFAULT_DEBUGGING_INFORMATION, // debuggingInformation
            this.className
        );
        
        // Find the script methods by name.
        this.result = new Method[count];
        if (count <= 10) {
            for (int i = 0; i < count; ++i) {
                try {
                    this.result[i] = c.getDeclaredMethod(methodNames[i], this.optionalParameterTypes == null ? new Class[0] : this.optionalParameterTypes[i]);
                } catch (NoSuchMethodException ex) {
                    throw new RuntimeException("SNO: Loaded class does not declare method \"" + methodNames[i] + "\"");
                }
            }
        } else
        {
            class MethodWrapper {
                private final String  name;
                private final Class[] parameterTypes;
                MethodWrapper(String name, Class[] parameterTypes) {
                    this.name = name;
                    this.parameterTypes = parameterTypes;
                }
                public boolean equals(Object o) {
                    if (!(o instanceof MethodWrapper)) return false;
                    MethodWrapper that = (MethodWrapper) o;
                    if (!this.name.equals(that.name)) return false;
                    int cnt = this.parameterTypes.length;
                    if (cnt != that.parameterTypes.length) return false;
                    for (int i = 0; i < cnt; ++i) {
                        if (!this.parameterTypes[i].equals(that.parameterTypes[i])) return false;
                    }
                    return true;
                }
                public int hashCode() {
                    int hc = this.name.hashCode();
                    for (int i = 0; i < this.parameterTypes.length; ++i) {
                        hc ^= this.parameterTypes[i].hashCode();
                    }
                    return hc;
                }
            }
            Method[] ma = c.getDeclaredMethods();
            Map dms = new HashMap(2 * count);
            for (int i = 0; i < ma.length; ++i) {
                Method m = ma[i];
                dms.put(new MethodWrapper(m.getName(), m.getParameterTypes()), m);
            }
            for (int i = 0; i < count; ++i) {
                Method m = (Method) dms.get(new MethodWrapper(methodNames[i], this.optionalParameterTypes == null ? new Class[0] : this.optionalParameterTypes[i]));
                if (m == null) throw new RuntimeException("SNO: Loaded class does not declare method \"" + methodNames[i] + "\"");
                this.result[i] = m;
            }
        }
    }


Generated by  Doxygen 1.6.0   Back to index