/*
* Janino - An embedded Java[TM] compiler
* Copyright (C) 2001-2004 Arno Unkrig
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information:
* Arno Unkrig
* Ferdinand-Miller-Platz 10
* 80335 Muenchen
* Germany
* http://www.janino.net
* maintainer@janino.net
*/
package net.janino;
import java.io.*;
import net.janino.util.ClassFile;
/**
* Utilities for the various "...Evaluator" classes.
*/
public class EvaluatorBase {
private final static boolean DEBUG = false;
protected EvaluatorBase(
ClassLoader optionalClassLoader // null == use current thread's context class loader
) {
ClassLoader cl = (
optionalClassLoader == null ?
Thread.currentThread().getContextClassLoader() :
optionalClassLoader
);
this.byteArrayClassLoader = (
cl instanceof ByteArrayClassLoader ?
(ByteArrayClassLoader) cl :
new ByteArrayClassLoader(cl)
);
this.classLoaderIClassLoader = new ClassLoaderIClassLoader(cl);
}
/**
* Parse as many import declarations as possible for the given
* {@link Java.CompilationUnit}.
* @param compilationUnit
* @param scanner Source of tokens
* @throws Scanner.ScanException
* @throws Parser.ParseException
* @throws IOException
*/
protected void parseImportDeclarations(
Java.CompilationUnit compilationUnit,
Scanner scanner
) throws Scanner.ScanException, Parser.ParseException, IOException {
Parser parser = new Parser(scanner);
while (scanner.peek().isKeyword("import")) parser.parseImportDeclaration(compilationUnit);
}
/**
* To the given {@link Java.CompilationUnit}, add
* <ul>
* <li>A class declaration with the given name, superclass and interfaces
* <li>A method declaration with the given return type, name, parameter
* names and values and thrown exceptions
* </ul>
* @param location
* @param compilationUnit
* @param className
* @param optionalExtendedType (null == {@link Object})
* @param implementedTypes
* @return The created {@link Java.ClassDeclaration} object
* @throws Parser.ParseException
* @throws Scanner.ScanException
* @throws IOException
*/
protected Java.PackageMemberClassDeclaration addPackageMemberClassDeclaration(
Scanner.Location location,
Java.CompilationUnit compilationUnit,
String className,
Class optionalExtendedType,
Class[] implementedTypes
) throws Parser.ParseException {
Java.PackageMemberClassDeclaration tlcd = new Java.PackageMemberClassDeclaration(
location, // location
compilationUnit, // declaringCompilationUnit
Mod.PUBLIC, // modifiers
className, // name
this.classToType(location, optionalExtendedType), // optionalExtendedType
this.classesToTypes(location, implementedTypes) // implementedTypes
);
compilationUnit.addPackageMemberTypeDeclaration(tlcd);
return tlcd;
}
/**
* To the given {@link Java.CompilationUnit}, add
* <ul>
* <li>A package member class declaration with the given name, superclass and interfaces
* <li>A public method declaration with the given return type, name, parameter
* names and values and thrown exceptions
* <li>A block
* </ul>
* @param location
* @param compilationUnit
* @param className
* @param optionalExtendedType (null == {@link Object})
* @param implementedTypes
* @param staticMethod Whether the method should be declared "static"
* @param returnType Return type of the declared method
* @param methodName
* @param parameterNames
* @param parameterTypes
* @param thrownExceptions
* @return The created {@link Java.Block} object
* @throws Parser.ParseException
* @throws Scanner.ScanException
* @throws IOException
*/
protected Java.Block addClassMethodBlockDeclaration(
Scanner.Location location,
Java.CompilationUnit compilationUnit,
String className,
Class optionalExtendedType,
Class[] implementedTypes,
boolean staticMethod,
Class returnType,
String methodName,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions
) throws Parser.ParseException {
if (parameterNames.length != parameterTypes.length) throw new RuntimeException("Lengths of \"parameterNames\" and \"parameterTypes\" do not match");
// Add class declaration.
Java.ClassDeclaration cd = this.addPackageMemberClassDeclaration(
location,
compilationUnit,
className, optionalExtendedType, implementedTypes
);
// Add method declaration.
Java.MethodDeclarator md = new Java.MethodDeclarator(
location, // location
cd, // declaringClassOrInterface
( // modifiers
staticMethod ?
(short) (Mod.PUBLIC | Mod.STATIC) :
(short) Mod.PUBLIC
),
this.classToType(location, returnType), // type
methodName, // name
this.makeFormalParameters( // formalParameters
location,
parameterNames, parameterTypes
),
this.classesToTypes(location, thrownExceptions) // thrownExceptions
);
cd.addDeclaredMethod(md);
// Add block as method body.
Java.Block b = new Java.Block(location, (Java.Scope) md);
md.setBody(b);
return b;
}
/**
* Wrap a reflection {@link Class} in a {@link Java.Type} object.
*/
protected Java.Type classToType(
Scanner.Location location,
final Class optionalClass
) {
if (optionalClass == null) return null;
return new Java.SimpleType(
location,
this.classLoaderIClassLoader.loadIClass(Descriptor.fromClassName(optionalClass.getName()))
);
}
/**
* Convert an array of {@link Class}es into an array of{@link Java.Type}s.
*/
protected Java.Type[] classesToTypes(
Scanner.Location location,
Class[] classes
) {
Java.Type[] types = new Java.Type[classes.length];
for (int i = 0; i < classes.length; ++i) {
types[i] = this.classToType(location, classes[i]);
}
return types;
}
/**
* Convert name and {@link Class}-base parameters into an array of
* {@link Java.FormalParameter}s.
*/
protected Java.FormalParameter[] makeFormalParameters(
Scanner.Location location,
String[] parameterNames,
Class[] parameterTypes
) {
Java.FormalParameter[] res = new Java.FormalParameter[parameterNames.length];
for (int i = 0; i < res.length; ++i) {
res[i] = new Java.FormalParameter(
true, // finaL
this.classToType(location, parameterTypes[i]), // type
parameterNames[i] // name
);
}
return res;
}
/**
* Compile the given compilation unit. (A "compilation unit" is typically the contents
* of a Java<sup>TM</sup> source file.)
* @param compilationUnit The parsed compilation unit
* @param debuggingInformation Any of <code>Java.DEBUGGING_*</code>
* @return A {@link ClassLoader} object through which the compiled classes can be accessed
* @throws Java.CompileException
*/
protected ClassLoader compileAndLoad(
Java.CompilationUnit compilationUnit,
DebuggingInformation debuggingInformation
) throws Java.CompileException {
if (EvaluatorBase.DEBUG) {
UnparseVisitor.unparse(compilationUnit, new OutputStreamWriter(System.out));
}
// Compile compilation unit to class files.
ClassFile[] classFiles = compilationUnit.compile(
this.classLoaderIClassLoader, // iClassLoader
debuggingInformation // debuggingInformation
);
// Add the generated class files to the {@link ByteArrayClassLoader}.
for (int i = 0; i < classFiles.length; ++i) {
ClassFile cf = classFiles[i];
String className = cf.getThisClassName();
if (EvaluatorBase.DEBUG) System.out.println("Define class \"" + className + "\".");
this.byteArrayClassLoader.addClass(className, cf.toByteArray());
}
return this.byteArrayClassLoader;
}
/**
* Compile the given compilation unit, load all generated classes, and
* return the class with the given name.
* @param compilationUnit
* @param debuggingInformation TODO
* @param newClassName The fully qualified class name
* @return The loaded class
* @throws Java.CompileException
* @throws ClassNotFoundException A class with the given name was not declared in the compilation unit
*/
protected Class compileAndLoad(
Java.CompilationUnit compilationUnit,
DebuggingInformation debuggingInformation,
String newClassName
) throws Java.CompileException, ClassNotFoundException {
return this.compileAndLoad(compilationUnit, debuggingInformation).loadClass(newClassName);
}
private final ClassLoaderIClassLoader classLoaderIClassLoader;
private final ByteArrayClassLoader byteArrayClassLoader;
}