02/11/2015 - Added ZStringArray String Decrypter. (Thanks Righteous)
02/20/2015 - Moved the decompilers/disassemblers around.
02/20/2015 - Fixed a resource leak with Krakatau
Decompiler/Disassembler/Assembler.
02/21/2015 - Fixed regex searching if your regex search contained a
syntax error.
02/21/2015 - Added the compiler/decompiler instances to the
BytecodeViewer API class.
02/21/2015 - Sped up the decompilers, each view pane runs its own
decompiler thread.
02/21/2015 - Added Janino compiler, you can now compile the decompiled
source code inside of BCV.
02/21/2015 - Added the editable option for almost all of the
decompilers/disassemblers.
02/21/2015 - Cached the next/previous icons and added a resources class
for all resources.
01/21/2015 - Renamed EZ-Injection as File-Run, however kept the plugin
named EZ-Injection.
02/21/2015 - Dropped Groovy support, added .Java plugin compilation
instead (now only 10mb).
02/21/2015 - Added support for reading resources, including displaying
images, detecting pure ascii files and more.
02/21/2015 - Fixed an issue with loading an already selected node in the
file navigation pane.
02/22/2015 - Added an error console to the Java compiler
02/22/2015 - Ensured the spawned Python/Krakatau processes are killed
when closing BCV.
02/22/2015 - Made it more beginner friendly.
02/22/2015 - Fixed? The file navigation search.
02/22/2015 - Added a shit ton more comments to non-api related classes.
02/23/2015 - Added APK resources.
02/23/2015 - MORE ANDROID LOVE! Added APKTool.jar's decode. (Takes a
while so it's a setting, also pumped the jar back to 16MB)
02/23/2015 - Added close all but this tab menu.
02/23/2015 - Not really code related, but added _install.bat and
_uninstall.bat for the exe version of BCV.
02/23/2015 - Back to ASM5, packed dex2jar in its own obfuscated jar.
02/23/2015 - Added the annotations back to the Bytecode Decompiler.
(Once again, thanks Bibl)
02/23/2015 - It once again works with Java 8 Jars.
This commit is contained in:
Kalen Kinloch 2015-02-23 23:55:53 -08:00
parent bde746b3b7
commit 0f5ef77944
160 changed files with 39708 additions and 1228 deletions

BIN
BCV Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
BytecodeViewer 2.9.0.jar Normal file

Binary file not shown.

View File

@ -49,7 +49,7 @@ Key Features:
Java Decompiler - It utilizes FernFlower, Procyon and CFR for decompilation.
Bytecode Decompiler - A modified version of CFIDE's.
Hex Viewer - Powered by JHexPane.
Each Decompiler/Viewer is toggleable, you can also select what will display on each pane.
Each Decompiler/Editor/Viewer is toggleable, you can also select what will display on each pane.
Fully Featured Search System - Search through strings, functions, variables and more!
A Plugin System With Built In Plugins - (Show All Strings, Malicious Code Scanner, String Decrypters, etc)
Fully Featured Scripting System That Supports Groovy.
@ -292,4 +292,30 @@ Changelog:
02/04/2015 - Added Krakatau Assembly.
--- 2.8.1 ---:
02/04/2015 - Fixed UI bug with Krakatau/Krakatau Editable view panes.
02/05/2015 - Added CTRL + F.
02/05/2015 - Added CTRL + F.
--- 2.9.0 ---:
02/11/2015 - Added ZStringArray String Decrypter. (Thanks Righteous)
02/20/2015 - Moved the decompilers/disassemblers around.
02/20/2015 - Fixed a resource leak with Krakatau Decompiler/Disassembler/Assembler.
02/21/2015 - Fixed regex searching if your regex search contained a syntax error.
02/21/2015 - Added the compiler/decompiler instances to the BytecodeViewer API class.
02/21/2015 - Sped up the decompilers, each view pane runs its own decompiler thread.
02/21/2015 - Added Janino compiler, you can now compile the decompiled source code inside of BCV.
02/21/2015 - Added the editable option for almost all of the decompilers/disassemblers.
02/21/2015 - Cached the next/previous icons and added a resources class for all resources.
01/21/2015 - Renamed EZ-Injection as File-Run, however kept the plugin named EZ-Injection.
02/21/2015 - Dropped Groovy support, added .Java plugin compilation instead (now only 10mb).
02/21/2015 - Added support for reading resources, including displaying images, detecting pure ascii files and more.
02/21/2015 - Fixed an issue with loading an already selected node in the file navigation pane.
02/22/2015 - Added an error console to the Java compiler
02/22/2015 - Ensured the spawned Python/Krakatau processes are killed when closing BCV.
02/22/2015 - Made it more beginner friendly.
02/22/2015 - Fixed? The file navigation search.
02/22/2015 - Added a shit ton more comments to non-api related classes.
02/23/2015 - Added APK resources.
02/23/2015 - MORE ANDROID LOVE! Added APKTool.jar's decode. (Takes a while so it's a setting, also pumped the jar back to 16MB)
02/23/2015 - Added close all but this tab menu.
02/23/2015 - Not really code related, but added _install.bat and _uninstall.bat for the exe version of BCV.
02/23/2015 - Back to ASM5, packed dex2jar in its own obfuscated jar.
02/23/2015 - Added the annotations back to the Bytecode Decompiler. (Once again, thanks Bibl)
02/23/2015 - It once again works with Java 8 Jars.

14
_install BCV.bat Normal file
View File

@ -0,0 +1,14 @@
@echo off
assoc .class=BCV
assoc .apk=BCV
assoc .dex=BCV
ftype BCV="%CD%\BytecodeViewer.exe" "%%1"
echo.
echo.
echo Installed, .class, .apk and .dex will be associated with BytecodeViwer.exe
echo.
echo Note, if you move BytecodeViewer.exe
echo you'll need to re-run this program in the same directory as it.
echo.
echo.
pause

10
_uninstall BCV.bat Normal file
View File

@ -0,0 +1,10 @@
@echo off
assoc .class=
assoc .apk=
assoc .dex=
echo.
echo.
echo Uninstalled, .class, .apk and .dex will no longer be associated.
echo.
echo.
pause

1
jar2exe_config.j2e Normal file
View File

@ -0,0 +1 @@
"C:\Program Files\Jar2Exe Wizard\j2ewiz" /jar "C:\Users\null\Documents\GitHub\bytecode-viewer\BytecodeViewer 2.9.0.jar" /o C:\Users\null\Documents\GitHub\bytecode-viewer\BytecodeViewer.exe /m the.bytecode.club.bytecodeviewer.BytecodeViewer /type windows /minjre 1.7 /platform windows /checksum /icon "C:\Users\null\Documents\GitHub\bytecode-viewer\BCV Icon.ico, 0" /pv 1,0,0,1 /fv 1,0,0,1 /ve ProductVersion=1.9.0 /ve "ProductName=The Bytecode Club" /ve "LegalCopyright=Copyright (c) 2014 - 2015 Kalen (Konloch) Kinloch" /ve "SpecialBuild=1, 0, 0, 1" /ve FileVersion=1 /ve "FileDescription=Java Reverse Engineering Suite" /ve "LegalTrademarks=Trade marks" /ve "InternalName=1, 0, 0, 1" /ve "CompanyName=The Bytecode Club"

Binary file not shown.

Binary file not shown.

BIN
libs/asm-all-5.0.3.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
libs/commons-compiler.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
libs/dex_obf.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,49 @@
import the.bytecode.club.bytecodeviewer.api.*;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import java.lang.reflect.Field;
import org.objectweb.asm.tree.FieldNode;
public class EldevinStringDecrypter extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodesList) {
PluginConsole gui = new PluginConsole("Eldevin String Decrypter");
JOptionPane pane = new JOptionPane("WARNING: This method of decryption loads the classes into a classloader and executes the init function, this could lead to malicious code executing.\n\r\n\rAre you sure you want to run this plugin?");
String[] options = ["Yes", "No"];
pane.setOptions(options);
JDialog dialog = pane.createDialog(the.bytecode.club.bytecodeviewer.BytecodeViewer.viewer, "WARNING");
dialog.show();
Object obj = pane.getValue();
int result = -1;
for (int k = 0; k < options.length; k++)
if (options[k].equals(obj))
result = k;
if(result == 0) {
for(ClassNode cn : classNodesList) {
the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().addClass(cn);
for(Object o : cn.fields.toArray()) {
FieldNode f = (FieldNode) o;
if(f.name.equals("z")) {// && f.desc.equals("([Ljava/lang/String;)V")) {
try {
for(Field f2 : the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().nodeToClass(cn).getFields()) {
String s = f2.get(null);
if(s != null && !s.empty())
gui.appendText(cn+":"+s);
}
} catch(Exception | StackOverflowError e) {}
}
}
}
gui.setVisible(true);
}
}
}

15
plugins/Skeleton.rb Normal file
View File

@ -0,0 +1,15 @@
require 'java'
java_import 'the.bytecode.club.bytecodeviewer.api.Plugin'
java_import 'the.bytecode.club.bytecodeviewer.api.PluginConsole'
java_import 'java.lang.System'
java_import 'java.util.ArrayList'
java_import 'org.objectweb.asm.tree.ClassNode'
class Skeleton < Plugin
def execute(classNodeList)
gui = PluginConsole.new "Skeleton"
gui.setVisible(true)
gui.appendText("exceuted skeleton")
end
end

14
plugins/Test.gy Normal file
View File

@ -0,0 +1,14 @@
import the.bytecode.club.bytecodeviewer.api.*;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.decompilers.*;
public class Test extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodesList) {
PluginConsole gui = new PluginConsole("Skeleton");
gui.setVisible(true);
gui.appendText(Smali.decompileClassNode(the.bytecode.club.bytecodeviewer.BytecodeViewer.viewer.workPane.getCurrentClass().cn));
}
}

13
plugins/skeleton.py Normal file
View File

@ -0,0 +1,13 @@
from the.bytecode.club.bytecodeviewer.api import Plugin
from the.bytecode.club.bytecodeviewer.api import PluginConsole
from java.lang import System
from java.lang import Boolean
from java.util import ArrayList
from org.objectweb.asm.tree import ClassNode
class skeleton(Plugin):
def execute(classNodeList, poop): #for some reason it requires a second arg
gui = PluginConsole("Skeleton")
gui.setVisible(Boolean.TRUE)
gui.appendText("exceuted skeleton")

View File

@ -0,0 +1,56 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import org.codehaus.janino.util.enumerator.Enumerator;
import org.codehaus.janino.util.enumerator.EnumeratorFormatException;
/** Return value for {@link IClass.IMember#getAccess}. */
public final
class Access extends Enumerator {
/** Representation of PRIVATE accessibility. */
public static final Access PRIVATE = new Access("private");
/** Representation of PROTECTED accessibility. */
public static final Access PROTECTED = new Access("protected");
/** Representation of DEFAULT accessibility. */
public static final Access DEFAULT = new Access("/*default*/");
/** Representation of PUBLIC accessibility. */
public static final Access PUBLIC = new Access("public");
// These MUST be declared exactly like this:
private Access(String name) { super(name); }
/** @return The {@code name} converted to {@link Access} */
public static Access
fromString(String name) throws EnumeratorFormatException {
return (Access) Enumerator.fromString(name, Access.class);
}
}

View File

@ -0,0 +1,74 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.util.Map;
/** This {@link ClassLoader} allows for the loading of a set of Java&trade; classes provided in class file format. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class ByteArrayClassLoader extends ClassLoader {
/**
* The given {@link Map} of classes must not be modified afterwards.
*
* @param classes String className => byte[] data
*/
public
ByteArrayClassLoader(Map<String /*className*/, byte[] /*data*/> classes) { this.classes = classes; }
/** @see #ByteArrayClassLoader(Map) */
public
ByteArrayClassLoader(Map<String /*className*/, byte[] /*data*/> classes, ClassLoader parent) {
super(parent);
this.classes = classes;
}
/**
* Implements {@link ClassLoader#findClass(String)}.
* <p>
* Notice that, although nowhere documented, no more than one thread at a time calls this
* method, because {@link ClassLoader#loadClass(java.lang.String)} is
* <code>synchronized</code>.
*/
@Override protected Class
findClass(String name) throws ClassNotFoundException {
byte[] data = (byte[]) this.classes.get(name);
if (data == null) throw new ClassNotFoundException(name);
// Notice: Not inheriting the protection domain will cause problems with Java Web Start /
// JNLP. See
// http://jira.codehaus.org/browse/JANINO-104
// http://www.nabble.com/-Help-jel--java.security.AccessControlException-to13073723.html
return super.defineClass(
name, // name
data, 0, data.length, // b, off, len
this.getClass().getProtectionDomain() // protectionDomain
);
}
private final Map<String /*className*/, byte[] /*data*/> classes;
}

View File

@ -0,0 +1,218 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.resource.DirectoryResourceCreator;
import org.codehaus.janino.util.resource.DirectoryResourceFinder;
import org.codehaus.janino.util.resource.PathResourceFinder;
import org.codehaus.janino.util.resource.Resource;
import org.codehaus.janino.util.resource.ResourceCreator;
import org.codehaus.janino.util.resource.ResourceFinder;
/**
* A {@link org.codehaus.janino.JavaSourceClassLoader} that uses a resource storage provided by the application to cache
* compiled classes and thus saving unnecessary recompilations.
* <p>
* The application provides access to the resource storeage through a pair of a {@link
* org.codehaus.janino.util.resource.ResourceFinder} and a {@link org.codehaus.janino.util.resource.ResourceCreator}
* (see {@link #CachingJavaSourceClassLoader(ClassLoader, ResourceFinder, String, ResourceFinder, ResourceCreator)}.
* <p>
* See {@link org.codehaus.janino.JavaSourceClassLoader#main(String[])} for an example how to use this class.
* <p>
* <b>Notice:</b> You must NOT rely on that this class stores some particular data in some particular resources through
* the given {@code classFileCacheResourceFinder/Creator}! These serve only as a means for the {@link
* CachingJavaSourceClassLoader} to persistently cache some data between invocations. In other words: If you want to
* compile {@code .java} files into {@code .class} files, then don't use <i>this</i> class but {@link Compiler}
* instead!
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class CachingJavaSourceClassLoader extends JavaSourceClassLoader {
private final ResourceFinder classFileCacheResourceFinder;
private final ResourceCreator classFileCacheResourceCreator;
private final ResourceFinder sourceFinder;
/**
* See {@link #CachingJavaSourceClassLoader(ClassLoader, ResourceFinder, String, ResourceFinder, ResourceCreator)}.
*
* @param optionalSourcePath Directories to scan for source files
* @param cacheDirectory Directory to use for caching generated class files (see class description)
*/
public
CachingJavaSourceClassLoader(
ClassLoader parentClassLoader,
File[] optionalSourcePath,
String optionalCharacterEncoding,
File cacheDirectory
) {
this(
parentClassLoader, // parentClassLoader
( // sourceFinder
optionalSourcePath == null
? (ResourceFinder) new DirectoryResourceFinder(new File("."))
: (ResourceFinder) new PathResourceFinder(optionalSourcePath)
),
optionalCharacterEncoding, // optionalCharacterEncoding
new DirectoryResourceFinder(cacheDirectory), // classFileCacheResourceFinder
new DirectoryResourceCreator(cacheDirectory) // classFileCacheResourceCreator
);
}
/**
* Notice that this class is thread-safe if and only if the {@code classFileCacheResourceCreator} stores its data
* atomically, i.e. the {@code classFileCacheResourceFinder} sees the resource written by the {@code
* classFileCacheResourceCreator} only after the {@link OutputStream} is closed.
* <p>
* In order to make the caching scheme work, both the {@code classFileCacheResourceFinder} and the {@code
* sourceFinder} must support the {@link org.codehaus.janino.util.resource.Resource#lastModified()} method, so that
* the modification time of the source and the class files can be compared.
*
* @param parentClassLoader Attempt to load classes through this one before looking for source files
* @param sourceFinder Finds Java&trade; source for class {@code pkg.Cls} in resource {@code
* pkg/Cls.java}
* @param optionalCharacterEncoding Encoding of Java&trade; source or {@code null} for platform default
* encoding
* @param classFileCacheResourceFinder Finds precompiled class {@code pkg.Cls} in resource {@code pkg/Cls.class}
* (see class description)
* @param classFileCacheResourceCreator Stores compiled class {@code pkg.Cls} in resource {@code pkg/Cls.class} (see
* class description)
*/
public
CachingJavaSourceClassLoader(
ClassLoader parentClassLoader,
ResourceFinder sourceFinder,
String optionalCharacterEncoding,
ResourceFinder classFileCacheResourceFinder,
ResourceCreator classFileCacheResourceCreator
) {
super(parentClassLoader, sourceFinder, optionalCharacterEncoding);
this.classFileCacheResourceFinder = classFileCacheResourceFinder;
this.classFileCacheResourceCreator = classFileCacheResourceCreator;
this.sourceFinder = sourceFinder;
}
/**
* Override {@link JavaSourceClassLoader#generateBytecodes(String)} to implement class file caching.
*
* @return String name => byte[] bytecode, or {@code null} if no source code could be found
* @throws ClassNotFoundException Compilation problems or class file cache I/O problems
*/
@Override protected Map<String /*name*/, byte[] /*bytecode*/>
generateBytecodes(String className) throws ClassNotFoundException {
// Check whether a class file resource exists in the cache.
{
Resource classFileResource = this.classFileCacheResourceFinder.findResource(
ClassFile.getClassFileResourceName(className)
);
if (classFileResource != null) {
// Check whether a source file resource exists.
Resource sourceResource = this.sourceFinder.findResource(ClassFile.getSourceResourceName(className));
if (sourceResource == null) return null;
// Check whether the class file is up-to-date.
if (sourceResource.lastModified() < classFileResource.lastModified()) {
// Yes, it is... read the bytecode from the file and define the class.
byte[] bytecode;
try {
bytecode = CachingJavaSourceClassLoader.readResource(classFileResource);
} catch (IOException ex) {
throw new ClassNotFoundException("Reading class file from \"" + classFileResource + "\"", ex);
}
Map<String /*name*/, byte[] /*bytecode*/> m = new HashMap();
m.put(className, bytecode);
return m;
}
}
}
// Cache miss... generate the bytecode from source.
Map<String /*name*/, byte[] /*bytecode*/> bytecodes = super.generateBytecodes(className);
if (bytecodes == null) return null;
// Write the generated bytecodes to the class file cache.
for (Map.Entry<String, byte[]> me : bytecodes.entrySet()) {
String className2 = (String) me.getKey();
byte[] bytecode = (byte[]) me.getValue();
try {
CachingJavaSourceClassLoader.writeResource(
this.classFileCacheResourceCreator,
ClassFile.getClassFileResourceName(className2),
bytecode
);
} catch (IOException ex) {
throw new ClassNotFoundException(
"Writing class file to \"" + ClassFile.getClassFileResourceName(className2) + "\"",
ex
);
}
}
return bytecodes;
}
/** Reads all bytes from the given resource. */
private static byte[]
readResource(Resource r) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
InputStream is = r.open();
try {
for (;;) {
int cnt = is.read(buffer);
if (cnt == -1) break;
baos.write(buffer, 0, cnt);
}
} finally {
try { is.close(); } catch (IOException ex) {}
}
return baos.toByteArray();
}
/** Create a resource with the given name and store the data in it. */
private static void
writeResource(ResourceCreator resourceCreator, String resourceName, byte[] data) throws IOException {
OutputStream os = resourceCreator.createResource(resourceName);
try {
os.write(data);
} finally {
try { os.close(); } catch (IOException ex) {}
}
}
}

View File

@ -0,0 +1,445 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.CompilerFactoryFactory;
import org.codehaus.commons.compiler.Cookable;
import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.codehaus.commons.compiler.ICompilerFactory;
import org.codehaus.commons.compiler.Location;
/**
* The <code>optionalClassLoader</code> serves two purposes:
* <ul>
* <li>It is used to look for classes referenced by the class body.
* <li>It is used to load the generated Java&trade; class
* into the JVM; directly if it is a subclass of {@link
* ByteArrayClassLoader}, or by creation of a temporary
* {@link ByteArrayClassLoader} if not.
* </ul>
* A number of "convenience constructors" exist that execute the setup steps instantly.
*/
@SuppressWarnings("rawtypes") public
class ClassBodyEvaluator extends SimpleCompiler implements IClassBodyEvaluator {
private static final Class[] ZERO_CLASSES = new Class[0];
private String[] optionalDefaultImports;
private String className = IClassBodyEvaluator.DEFAULT_CLASS_NAME;
private Class optionalExtendedType;
private Class[] implementedTypes = ClassBodyEvaluator.ZERO_CLASSES;
private Class result; // null=uncooked
/**
* Equivalent to<pre>
* ClassBodyEvaluator cbe = new ClassBodyEvaluator();
* cbe.cook(classBody);</pre>
*
* @see #ClassBodyEvaluator()
* @see Cookable#cook(String)
*/
public
ClassBodyEvaluator(String classBody) throws CompileException { this.cook(classBody); }
/**
* Equivalent to<pre>
* ClassBodyEvaluator cbe = new ClassBodyEvaluator();
* cbe.cook(optionalFileName, is);</pre>
*
* @see #ClassBodyEvaluator()
* @see Cookable#cook(String, InputStream)
*/
public
ClassBodyEvaluator(String optionalFileName, InputStream is) throws CompileException, IOException {
this.cook(optionalFileName, is);
}
/**
* Equivalent to<pre>
* ClassBodyEvaluator cbe = new ClassBodyEvaluator();
* cbe.cook(optionalFileName, reader);</pre>
*
* @see #ClassBodyEvaluator()
* @see Cookable#cook(String, Reader)
*/
public
ClassBodyEvaluator(String optionalFileName, Reader reader) throws CompileException, IOException {
this.cook(optionalFileName, reader);
}
/**
* Equivalent to<pre>
* ClassBodyEvaluator cbe = new ClassBodyEvaluator();
* cbe.setParentClassLoader(optionalParentClassLoader);
* cbe.cook(scanner);</pre>
*
* @see #ClassBodyEvaluator()
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ClassBodyEvaluator(Scanner scanner, ClassLoader optionalParentClassLoader) throws CompileException, IOException {
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Equivalent to<pre>
* ClassBodyEvaluator cbe = new ClassBodyEvaluator();
* cbe.setExtendedType(optionalExtendedType);
* cbe.setImplementedTypes(implementedTypes);
* cbe.setParentClassLoader(optionalParentClassLoader);
* cbe.cook(scanner);</pre>
*
* @see #ClassBodyEvaluator()
* @see #setExtendedClass(Class)
* @see #setImplementedInterfaces(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ClassBodyEvaluator(
Scanner scanner,
Class optionalExtendedType,
Class[] implementedTypes,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Equivalent to<pre>
* ClassBodyEvaluator cbe = new ClassBodyEvaluator();
* cbe.setClassName(className);
* cbe.setExtendedType(optionalExtendedType);
* cbe.setImplementedTypes(implementedTypes);
* cbe.setParentClassLoader(optionalParentClassLoader);
* cbe.cook(scanner);</pre>
*
* @see #ClassBodyEvaluator()
* @see #setClassName(String)
* @see #setExtendedClass(Class)
* @see #setImplementedInterfaces(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ClassBodyEvaluator(
Scanner scanner,
String className,
Class optionalExtendedType,
Class[] implementedTypes,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
this.setClassName(className);
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
public ClassBodyEvaluator() {}
@Override public void
setDefaultImports(String[] optionalDefaultImports) {
this.assertNotCooked();
this.optionalDefaultImports = optionalDefaultImports;
}
@Override public void
setClassName(String className) {
if (className == null) throw new NullPointerException();
this.assertNotCooked();
this.className = className;
}
@Override public void
setExtendedClass(Class optionalExtendedType) {
this.assertNotCooked();
this.optionalExtendedType = optionalExtendedType;
}
/** @deprecated */
@Deprecated @Override public void
setExtendedType(Class optionalExtendedClass) {
this.setExtendedClass(optionalExtendedClass);
}
@Override public void
setImplementedInterfaces(Class[] implementedTypes) {
if (implementedTypes == null) {
throw new NullPointerException(
"Zero implemented types must be specified as 'new Class[0]', not 'null'"
);
}
this.assertNotCooked();
this.implementedTypes = implementedTypes;
}
/** @deprecated */
@Deprecated @Override public void
setImplementedTypes(Class[] implementedInterfaces) {
this.setImplementedInterfaces(implementedInterfaces);
}
@Override public void
cook(Scanner scanner) throws CompileException, IOException {
Parser parser = new Parser(scanner);
Java.CompilationUnit compilationUnit = this.makeCompilationUnit(parser);
// Add class declaration.
Java.ClassDeclaration cd = this.addPackageMemberClassDeclaration(scanner.location(), compilationUnit);
// Parse class body declarations (member declarations) until EOF.
while (!parser.peekEof()) {
parser.parseClassBodyDeclaration(cd);
}
// Compile and load it.
this.result = this.compileToClass(compilationUnit);
}
/**
* Create a {@link Java.CompilationUnit}, set the default imports, and parse the import declarations.
* <p>
* If the <code>optionalParser</code> is given, a sequence of IMPORT directives is parsed from it and added to the
* compilation unit.
*/
protected final Java.CompilationUnit
makeCompilationUnit(Parser optionalParser) throws CompileException, IOException {
Java.CompilationUnit cu = (
new Java.CompilationUnit(optionalParser == null
? null
: optionalParser.getScanner().getFileName())
);
// Set default imports.
if (this.optionalDefaultImports != null) {
for (String defaultImport : this.optionalDefaultImports) {
Scanner s = new Scanner(null, new StringReader(defaultImport));
Parser parser2 = new Parser(s);
cu.addImportDeclaration(parser2.parseImportDeclarationBody());
if (!parser2.peekEof()) {
throw new CompileException(
"Unexpected token '" + parser2.peek() + "' in default import",
s.location()
);
}
}
}
// Parse all available IMPORT declarations.
if (optionalParser != null) {
while (optionalParser.peek("import")) {
cu.addImportDeclaration(optionalParser.parseImportDeclaration());
}
}
return cu;
}
/**
* To the given {@link Java.CompilationUnit}, add
* <ul>
* <li>A class declaration with the configured name, superclass and interfaces
* <li>A method declaration with the given return type, name, parameter names and values and thrown exceptions
* </ul>
*
* @return The created {@link Java.ClassDeclaration} object
*/
protected Java.PackageMemberClassDeclaration
addPackageMemberClassDeclaration(Location location, Java.CompilationUnit compilationUnit) throws CompileException {
String cn = this.className;
int idx = cn.lastIndexOf('.');
if (idx != -1) {
compilationUnit.setPackageDeclaration(new Java.PackageDeclaration(location, cn.substring(0, idx)));
cn = cn.substring(idx + 1);
}
Java.PackageMemberClassDeclaration tlcd = new Java.PackageMemberClassDeclaration(
location, // location
null, // optionalDocComment
new Java.Modifiers(Mod.PUBLIC), // modifiers
cn, // name
null, // optionalTypeParameters
this.classToType(location, this.optionalExtendedType), // optionalExtendedType
this.classesToTypes(location, this.implementedTypes) // implementedTypes
);
compilationUnit.addPackageMemberTypeDeclaration(tlcd);
return tlcd;
}
/**
* Compile the given compilation unit, load all generated classes, and return the class with the given name.
*
* @param compilationUnit
* @return The loaded class
*/
protected final Class
compileToClass(Java.CompilationUnit compilationUnit) throws CompileException {
// Compile and load the compilation unit.
ClassLoader cl = this.compileToClassLoader(compilationUnit);
// Find the generated class by name.
try {
return cl.loadClass(this.className);
} catch (ClassNotFoundException ex) {
throw new JaninoRuntimeException((
"SNO: Generated compilation unit does not declare class '"
+ this.className
+ "'"
), ex);
}
}
@Override public Class
getClazz() {
if (this.getClass() != ClassBodyEvaluator.class) {
throw new IllegalStateException("Must not be called on derived instances");
}
if (this.result == null) throw new IllegalStateException("Must only be called after 'cook()'");
return this.result;
}
@Override public Object
createInstance(Reader reader) throws CompileException, IOException {
this.cook(reader);
try {
return this.getClazz().newInstance();
} catch (InstantiationException ie) {
CompileException ce = new CompileException((
"Class is abstract, an interface, an array class, a primitive type, or void; "
+ "or has no zero-parameter constructor"
), null);
ce.initCause(ie);
throw ce; // SUPPRESS CHECKSTYLE AvoidHidingCause
} catch (IllegalAccessException iae) {
CompileException ce = new CompileException(
"The class or its zero-parameter constructor is not accessible",
null
);
ce.initCause(iae);
throw ce; // SUPPRESS CHECKSTYLE AvoidHidingCause
}
}
/**
* Use {@link #createInstance(Reader)} instead:
* <pre>
* IClassBodyEvaluator cbe = {@link CompilerFactoryFactory}.{@link
* CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
* ICompilerFactory#newClassBodyEvaluator() newClassBodyEvaluator}();
* if (optionalBaseType != null) {
* if (optionalBaseType.isInterface()) {
* cbe.{@link #setImplementedInterfaces setImplementedInterfaces}(new Class[] { optionalBaseType });
* } else {
* cbe.{@link #setExtendedClass(Class) setExtendedClass}(optionalBaseType);
* }
* }
* cbe.{@link #setParentClassLoader(ClassLoader) setParentClassLoader}(optionalParentClassLoader);
* cbe.{@link IClassBodyEvaluator#createInstance(Reader) createInstance}(reader);
* </pre>
*
* @see #createInstance(Reader)
*/
public static Object
createFastClassBodyEvaluator(
Scanner scanner,
Class optionalBaseType,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
return ClassBodyEvaluator.createFastClassBodyEvaluator(
scanner, // scanner
IClassBodyEvaluator.DEFAULT_CLASS_NAME, // className
( // optionalExtendedType
optionalBaseType != null && !optionalBaseType.isInterface()
? optionalBaseType
: null
),
( // implementedTypes
optionalBaseType != null && optionalBaseType.isInterface()
? new Class[] { optionalBaseType }
: new Class[0]
),
optionalParentClassLoader // optionalParentClassLoader
);
}
/**
* Use {@link #createInstance(Reader)} instead:
* <pre>
* IClassBodyEvaluator cbe = {@link CompilerFactoryFactory}.{@link
* CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
* ICompilerFactory#newClassBodyEvaluator() newClassBodyEvaluator}();
* cbe.{@link #setExtendedClass(Class) setExtendedClass}(optionalExtendedClass);
* cbe.{@link #setImplementedInterfaces(Class[]) setImplementedInterfaces}(implementedInterfaces);
* cbe.{@link #setParentClassLoader(ClassLoader) setParentClassLoader}(optionalParentClassLoader);
* cbe.{@link IClassBodyEvaluator#createInstance(Reader) createInstance}(reader);
* </pre>
*
* @see #createInstance(Reader)
* @deprecated Use {@link #createInstance(Reader)} instead.
*/
@Deprecated public static Object
createFastClassBodyEvaluator(
Scanner scanner,
String className,
Class optionalExtendedClass,
Class[] implementedInterfaces,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
ClassBodyEvaluator cbe = new ClassBodyEvaluator();
cbe.setClassName(className);
cbe.setExtendedClass(optionalExtendedClass);
cbe.setImplementedInterfaces(implementedInterfaces);
cbe.setParentClassLoader(optionalParentClassLoader);
cbe.cook(scanner);
Class c = cbe.getClazz();
try {
return c.newInstance();
} catch (InstantiationException e) {
throw new CompileException( // SUPPRESS CHECKSTYLE AvoidHidingCause
e.getMessage(),
null
);
} catch (IllegalAccessException e) {
// SNO - type and default constructor of generated class are PUBLIC.
throw new JaninoRuntimeException(e.toString(), e);
}
}
}

View File

@ -0,0 +1,438 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.ClassFile.ConstantClassInfo;
/** A wrapper object that turns a {@link ClassFile} object into an {@link IClass}. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class ClassFileIClass extends IClass {
private static final boolean DEBUG = false;
private final ClassFile classFile;
private final IClassLoader iClassLoader;
private final short accessFlags;
private final Map<ClassFile.FieldInfo, IField> resolvedFields = new HashMap();
/**
* @param classFile Source of data
* @param iClassLoader {@link IClassLoader} through which to load other classes
*/
public
ClassFileIClass(ClassFile classFile, IClassLoader iClassLoader) {
this.classFile = classFile;
this.iClassLoader = iClassLoader;
// Determine class access flags.
this.accessFlags = classFile.accessFlags;
}
// Implement IClass.
@Override protected IConstructor[]
getDeclaredIConstructors2() {
List iConstructors = new ArrayList();
for (ClassFile.MethodInfo mi : this.classFile.methodInfos) {
IInvocable ii;
try {
ii = this.resolveMethod(mi);
} catch (ClassNotFoundException ex) {
throw new JaninoRuntimeException(ex.getMessage(), ex);
}
if (ii instanceof IConstructor) iConstructors.add(ii);
}
return (IConstructor[]) iConstructors.toArray(new IConstructor[iConstructors.size()]);
}
@Override protected IMethod[]
getDeclaredIMethods2() {
List<IMethod> iMethods = new ArrayList();
for (ClassFile.MethodInfo mi : this.classFile.methodInfos) {
// Skip JDK 1.5 synthetic methods (e.g. those generated for
// covariant return values).
if (Mod.isSynthetic(mi.getModifierFlags())) continue;
IInvocable ii;
try {
ii = this.resolveMethod(mi);
} catch (ClassNotFoundException ex) {
throw new JaninoRuntimeException(ex.getMessage(), ex);
}
if (ii instanceof IMethod) iMethods.add((IMethod) ii);
}
return (IMethod[]) iMethods.toArray(new IMethod[iMethods.size()]);
}
@Override protected IField[]
getDeclaredIFields2() {
IField[] ifs = new IClass.IField[this.classFile.fieldInfos.size()];
for (int i = 0; i < this.classFile.fieldInfos.size(); ++i) {
try {
ifs[i] = this.resolveField((ClassFile.FieldInfo) this.classFile.fieldInfos.get(i));
} catch (ClassNotFoundException ex) {
throw new JaninoRuntimeException(ex.getMessage(), ex);
}
}
return ifs;
}
@Override protected IClass[]
getDeclaredIClasses2() throws CompileException {
ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute();
if (ica == null) return new IClass[0];
List<IClass> res = new ArrayList();
for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) {
if (e.outerClassInfoIndex == this.classFile.thisClass) {
try {
res.add(this.resolveClass(e.innerClassInfoIndex));
} catch (ClassNotFoundException ex) {
throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
}
}
}
return (IClass[]) res.toArray(new IClass[res.size()]);
}
@Override protected IClass
getDeclaringIClass2() throws CompileException {
ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute();
if (ica == null) return null;
for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) {
if (e.innerClassInfoIndex == this.classFile.thisClass) {
// Is this an anonymous class?
if (e.outerClassInfoIndex == 0) return null;
try {
return this.resolveClass(e.outerClassInfoIndex);
} catch (ClassNotFoundException ex) {
throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
}
}
}
return null;
}
@Override protected IClass
getOuterIClass2() throws CompileException {
ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute();
if (ica == null) return null;
for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) {
if (e.innerClassInfoIndex == this.classFile.thisClass) {
if (e.outerClassInfoIndex == 0) {
// Anonymous class or local class.
// TODO: Determine enclosing instance of anonymous class or local class
return null;
} else {
// Member type.
if (Mod.isStatic(e.innerClassAccessFlags)) return null;
try {
return this.resolveClass(e.outerClassInfoIndex);
} catch (ClassNotFoundException ex) {
throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
}
}
}
}
return null;
}
@Override protected IClass
getSuperclass2() throws CompileException {
if (this.classFile.superclass == 0) return null;
try {
return this.resolveClass(this.classFile.superclass);
} catch (ClassNotFoundException e) {
throw new CompileException(e.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
}
}
@Override public Access
getAccess() { return ClassFileIClass.accessFlags2Access(this.accessFlags); }
@Override public boolean
isFinal() { return Mod.isFinal(this.accessFlags); }
@Override protected IClass[]
getInterfaces2() throws CompileException { return this.resolveClasses(this.classFile.interfaces); }
@Override public boolean
isAbstract() { return Mod.isAbstract(this.accessFlags); }
@Override protected String
getDescriptor2() { return Descriptor.fromClassName(this.classFile.getThisClassName()); }
@Override public boolean
isInterface() { return Mod.isInterface(this.accessFlags); }
@Override public boolean
isArray() { return false; }
@Override public boolean
isPrimitive() { return false; }
@Override public boolean
isPrimitiveNumeric() { return false; }
@Override protected IClass
getComponentType2() { return null; }
/** Resolves all classes referenced by this class file. */
public void
resolveAllClasses() throws ClassNotFoundException {
for (short i = 0; i < this.classFile.getConstantPoolSize(); ++i) {
ClassFile.ConstantPoolInfo cpi = this.classFile.getConstantPoolInfo(i);
if (cpi instanceof ClassFile.ConstantClassInfo) {
this.resolveClass(i);
} else
if (cpi instanceof ClassFile.ConstantNameAndTypeInfo) {
String descriptor = ((ClassFile.ConstantNameAndTypeInfo) cpi).getDescriptor(this.classFile);
if (descriptor.charAt(0) == '(') {
MethodDescriptor md = new MethodDescriptor(descriptor);
this.resolveClass(md.returnFd);
for (String parameterFd : md.parameterFds) this.resolveClass(parameterFd);
} else {
this.resolveClass(descriptor);
}
}
}
}
/** @param index Index of the CONSTANT_Class_info to resolve (JVMS 4.4.1) */
private IClass
resolveClass(short index) throws ClassNotFoundException {
if (ClassFileIClass.DEBUG) System.out.println("index=" + index);
ConstantClassInfo cci = (ConstantClassInfo) this.classFile.getConstantPoolInfo(index);
return this.resolveClass(Descriptor.fromInternalForm(cci.getName(this.classFile)));
}
private IClass
resolveClass(String descriptor) throws ClassNotFoundException {
if (ClassFileIClass.DEBUG) System.out.println("descriptor=" + descriptor);
IClass result = (IClass) this.resolvedClasses.get(descriptor);
if (result != null) return result;
result = this.iClassLoader.loadIClass(descriptor);
if (result == null) throw new ClassNotFoundException(descriptor);
this.resolvedClasses.put(descriptor, result);
return result;
}
private final Map<String /*descriptor*/, IClass> resolvedClasses = new HashMap();
private IClass[]
resolveClasses(short[] ifs) throws CompileException {
IClass[] result = new IClass[ifs.length];
for (int i = 0; i < result.length; ++i) {
try {
result[i] = this.resolveClass(ifs[i]);
} catch (ClassNotFoundException e) {
throw new CompileException(e.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
}
}
return result;
}
/**
* Turn a {@link ClassFile.MethodInfo} into an {@link IInvocable}. This includes the checking and the
* removal of the magic first parameter of an inner class constructor.
*
* @param methodInfo
* @throws ClassNotFoundException
*/
private IInvocable
resolveMethod(final ClassFile.MethodInfo methodInfo) throws ClassNotFoundException {
IInvocable result = (IInvocable) this.resolvedMethods.get(methodInfo);
if (result != null) return result;
// Determine method name.
final String name = methodInfo.getName();
// Determine return type.
MethodDescriptor md = new MethodDescriptor(methodInfo.getDescriptor());
final IClass returnType = this.resolveClass(md.returnFd);
// Determine parameter types.
final IClass[] parameterTypes = new IClass[md.parameterFds.length];
for (int i = 0; i < parameterTypes.length; ++i) parameterTypes[i] = this.resolveClass(md.parameterFds[i]);
// Determine thrown exceptions.
IClass[] tes = null;
ClassFile.AttributeInfo[] ais = methodInfo.getAttributes();
for (ClassFile.AttributeInfo ai : ais) {
if (ai instanceof ClassFile.ExceptionsAttribute) {
ConstantClassInfo[] ccis = ((ClassFile.ExceptionsAttribute) ai).getExceptions(this.classFile);
tes = new IClass[ccis.length];
for (int i = 0; i < tes.length; ++i) {
tes[i] = this.resolveClass(Descriptor.fromInternalForm(ccis[i].getName(this.classFile)));
}
}
}
final IClass[] thrownExceptions = tes == null ? new IClass[0] : tes;
// Determine access.
final Access access = ClassFileIClass.accessFlags2Access(methodInfo.getModifierFlags());
if ("<init>".equals(name)) {
result = new IClass.IConstructor() {
@Override public boolean
isVarargs() { return Mod.isVarargs(methodInfo.getModifierFlags()); }
@Override public IClass[]
getParameterTypes2() throws CompileException {
// Process magic first parameter of inner class constructor.
IClass outerIClass = ClassFileIClass.this.getOuterIClass();
if (outerIClass != null) {
if (parameterTypes.length < 1) {
throw new JaninoRuntimeException("Inner class constructor lacks magic first parameter");
}
if (parameterTypes[0] != outerIClass) {
throw new JaninoRuntimeException(
"Magic first parameter of inner class constructor has type \""
+ parameterTypes[0].toString()
+ "\" instead of that of its enclosing instance (\""
+ outerIClass.toString()
+ "\")"
);
}
IClass[] tmp = new IClass[parameterTypes.length - 1];
System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
return tmp;
}
return parameterTypes;
}
@Override public IClass[] getThrownExceptions2() { return thrownExceptions; }
@Override public Access getAccess() { return access; }
@Override public Java.Annotation[] getAnnotations() { return methodInfo.getAnnotations(); }
};
} else {
result = new IClass.IMethod() {
@Override public String
getName() { return name; }
@Override public IClass
getReturnType() { return returnType; }
@Override public boolean
isStatic() { return Mod.isStatic(methodInfo.getModifierFlags()); }
@Override public boolean
isAbstract() { return Mod.isAbstract(methodInfo.getModifierFlags()); }
@Override public boolean
isVarargs() { return Mod.isVarargs(methodInfo.getModifierFlags()); }
@Override public IClass[]
getParameterTypes2() { return parameterTypes; }
@Override public IClass[]
getThrownExceptions2() { return thrownExceptions; }
@Override public Access
getAccess() { return access; }
@Override public Java.Annotation[]
getAnnotations() { return methodInfo.getAnnotations(); }
};
}
this.resolvedMethods.put(methodInfo, result);
return result;
}
private final Map<ClassFile.MethodInfo, IInvocable> resolvedMethods = new HashMap();
private IField
resolveField(final ClassFile.FieldInfo fieldInfo) throws ClassNotFoundException {
IField result = (IField) this.resolvedFields.get(fieldInfo);
if (result != null) return result;
// Determine field name.
final String name = fieldInfo.getName(this.classFile);
// Determine field type.
final String descriptor = fieldInfo.getDescriptor(this.classFile);
final IClass type = this.resolveClass(descriptor);
// Determine optional "constant value" of the field (JLS7 15.28, bullet 14). If a field has a "ConstantValue"
// attribute, we assume that it has a constant value. Notice that this assumption is not always correct,
// because typical Java&trade; compilers do not generate a "ConstantValue" attribute for fields like
// "int RED = 0", because "0" is the default value for an integer field.
ClassFile.ConstantValueAttribute cva = null;
for (ClassFile.AttributeInfo ai : fieldInfo.getAttributes()) {
if (ai instanceof ClassFile.ConstantValueAttribute) {
cva = (ClassFile.ConstantValueAttribute) ai;
break;
}
}
final Object optionalConstantValue = cva == null ? IClass.NOT_CONSTANT : cva.getConstantValue(this.classFile);
final Access access = ClassFileIClass.accessFlags2Access(fieldInfo.getModifierFlags());
result = new IField() {
@Override public Object getConstantValue() { return optionalConstantValue; }
@Override public String getName() { return name; }
@Override public IClass getType() { return type; }
@Override public boolean isStatic() { return Mod.isStatic(fieldInfo.getModifierFlags()); }
@Override public Access getAccess() { return access; }
@Override public Java.Annotation[] getAnnotations() { return fieldInfo.getAnnotations(); }
};
this.resolvedFields.put(fieldInfo, result);
return result;
}
private static Access
accessFlags2Access(short accessFlags) {
return (
Mod.isPublicAccess(accessFlags) ? Access.PUBLIC
: Mod.isProtectedAccess(accessFlags) ? Access.PROTECTED
: Mod.isPrivateAccess(accessFlags) ? Access.PRIVATE
: Access.DEFAULT
);
}
}

View File

@ -0,0 +1,95 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
/** An {@link IClassLoader} that loads {@link IClass}es through a reflection {@link ClassLoader}. */
@SuppressWarnings("rawtypes") public
class ClassLoaderIClassLoader extends IClassLoader {
private static final boolean DEBUG = false;
/** @param classLoader The delegate that loads the classes. */
public
ClassLoaderIClassLoader(ClassLoader classLoader) {
super(
null // optionalParentIClassLoader
);
if (classLoader == null) throw new NullPointerException();
this.classLoader = classLoader;
super.postConstruct();
}
/**
* Equivalent to
* <pre>
* ClassLoaderIClassLoader(Thread.currentThread().getContextClassLoader())
* </pre>
*/
public
ClassLoaderIClassLoader() { this(Thread.currentThread().getContextClassLoader()); }
/** @return The delegate {@link ClassLoader} */
public ClassLoader
getClassLoader() { return this.classLoader; }
@Override protected IClass
findIClass(String descriptor) throws ClassNotFoundException {
Class clazz;
try {
//
// See also [ 931385 ] Janino 2.0 throwing exception on arrays of java.io.File:
//
// "ClassLoader.loadClass()" and "Class.forName()" should be identical,
// but "ClassLoader.loadClass("[Ljava.lang.Object;")" throws a
// ClassNotFoundException under JDK 1.5.0 beta.
// Unclear whether this a beta version bug and SUN will fix this in the final
// release, but "Class.forName()" seems to work fine in all cases, so we
// use that.
//
// clazz = this.classLoader.loadClass(Descriptor.toClassName(descriptor));
clazz = Class.forName(Descriptor.toClassName(descriptor), false, this.classLoader);
} catch (ClassNotFoundException e) {
if (e.getException() == null) {
return null;
} else
{
throw e;
}
}
if (ClassLoaderIClassLoader.DEBUG) System.out.println("clazz = " + clazz);
IClass result = new ReflectionIClass(clazz, this);
this.defineIClass(result);
return result;
}
private final ClassLoader classLoader;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,830 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.ErrorHandler;
import org.codehaus.commons.compiler.Location;
import org.codehaus.commons.compiler.WarningHandler;
import org.codehaus.janino.Java.CompilationUnit;
import org.codehaus.janino.util.Benchmark;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.StringPattern;
import org.codehaus.janino.util.resource.DirectoryResourceCreator;
import org.codehaus.janino.util.resource.DirectoryResourceFinder;
import org.codehaus.janino.util.resource.FileResource;
import org.codehaus.janino.util.resource.FileResourceCreator;
import org.codehaus.janino.util.resource.PathResourceFinder;
import org.codehaus.janino.util.resource.Resource;
import org.codehaus.janino.util.resource.ResourceCreator;
import org.codehaus.janino.util.resource.ResourceFinder;
/**
* A simplified substitute for the <tt>javac</tt> tool.
*
* Usage:
* <pre>
* java org.codehaus.janino.Compiler \
* [ -d <i>destination-dir</i> ] \
* [ -sourcepath <i>dirlist</i> ] \
* [ -classpath <i>dirlist</i> ] \
* [ -extdirs <i>dirlist</i> ] \
* [ -bootclasspath <i>dirlist</i> ] \
* [ -encoding <i>encoding</i> ] \
* [ -verbose ] \
* [ -g:none ] \
* [ -g:{source,lines,vars} ] \
* [ -warn:<i>pattern-list</i> ] \
* <i>source-file</i> ...
* java org.codehaus.janino.Compiler -help
* </pre>
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class Compiler {
private static final boolean DEBUG = false;
/** Command line interface. */
public static void BCV(String[] args) throws Exception {
File destinationDirectory = Compiler.NO_DESTINATION_DIRECTORY;
File[] optionalSourcePath = null;
File[] classPath = { new File(".") };
File[] optionalExtDirs = null;
File[] optionalBootClassPath = null;
String optionalCharacterEncoding = null;
boolean verbose = false;
boolean debugSource = true;
boolean debugLines = true;
boolean debugVars = false;
StringPattern[] warningHandlePatterns = Compiler.DEFAULT_WARNING_HANDLE_PATTERNS;
boolean rebuild = false;
// Process command line options.
int i;
for (i = 0; i < args.length; ++i) {
String arg = args[i];
if (arg.charAt(0) != '-') break;
if ("-d".equals(arg)) {
destinationDirectory = new File(args[++i]);
} else
if ("-sourcepath".equals(arg)) {
optionalSourcePath = PathResourceFinder.parsePath(args[++i]);
} else
if ("-classpath".equals(arg)) {
classPath = PathResourceFinder.parsePath(args[++i]);
} else
if ("-extdirs".equals(arg)) {
optionalExtDirs = PathResourceFinder.parsePath(args[++i]);
} else
if ("-bootclasspath".equals(arg)) {
optionalBootClassPath = PathResourceFinder.parsePath(args[++i]);
} else
if ("-encoding".equals(arg)) {
optionalCharacterEncoding = args[++i];
} else
if ("-verbose".equals(arg)) {
verbose = true;
} else
if ("-g".equals(arg)) {
debugSource = true;
debugLines = true;
debugVars = true;
} else
if (arg.startsWith("-g:")) {
if (arg.indexOf("none") != -1) debugSource = (debugLines = (debugVars = false));
if (arg.indexOf("source") != -1) debugSource = true;
if (arg.indexOf("lines") != -1) debugLines = true;
if (arg.indexOf("vars") != -1) debugVars = true;
} else
if (arg.startsWith("-warn:")) {
warningHandlePatterns = StringPattern.parseCombinedPattern(arg.substring(6));
} else
if ("-rebuild".equals(arg)) {
rebuild = true;
} else
if ("-help".equals(arg)) {
System.out.printf(Compiler.USAGE, (Object[]) null);
} else
{
System.err.println("Unrecognized command line option \"" + arg + "\"; try \"-help\".");
}
}
// Get source file names.
if (i == args.length) {
System.err.println("No source files given on command line; try \"-help\".");
}
File[] sourceFiles = new File[args.length - i];
for (int j = i; j < args.length; ++j) sourceFiles[j - i] = new File(args[j]);
// Create the compiler object.
final Compiler compiler = new Compiler(
optionalSourcePath,
classPath,
optionalExtDirs,
optionalBootClassPath,
destinationDirectory,
optionalCharacterEncoding,
verbose,
debugSource,
debugLines,
debugVars,
warningHandlePatterns,
rebuild
);
// Compile source files.
compiler.compile(sourceFiles);
}
private static final String USAGE = (
""
+ "Usage:%n"
+ "%n"
+ " java " + Compiler.class.getName() + " [ <option> ] ... <source-file> ...%n"
+ "%n"
+ "Supported <option>s are:%n"
+ " -d <output-dir> Where to save class files%n"
+ " -sourcepath <dirlist> Where to look for other source files%n"
+ " -classpath <dirlist> Where to look for other class files%n"
+ " -extdirs <dirlist> Where to look for other class files%n"
+ " -bootclasspath <dirlist> Where to look for other class files%n"
+ " -encoding <encoding> Encoding of source files, e.g. \"UTF-8\" or \"ISO-8859-1\"%n"
+ " -verbose%n"
+ " -g Generate all debugging info%n"
+ " -g:none Generate no debugging info%n"
+ " -g:{source,lines,vars} Generate only some debugging info%n"
+ " -warn:<pattern-list> Issue certain warnings; examples:%n"
+ " -warn:* Enables all warnings%n"
+ " -warn:IASF Only warn against implicit access to static fields%n"
+ " -warn:*-IASF Enables all warnings, except those against implicit%n"
+ " access to static fields%n"
+ " -warn:*-IA*+IASF Enables all warnings, except those against implicit%n"
+ " accesses, but do warn against implicit access to%n"
+ " static fields%n"
+ " -rebuild Compile all source files, even if the class files%n"
+ " seems up-to-date%n"
+ " -help%n"
+ "%n"
+ "The default encoding in this environment is \"" + Charset.defaultCharset().toString() + "\"."
);
private final ResourceFinder classFileFinder;
/** Special value for "classFileResourceFinder". */
public static final ResourceFinder FIND_NEXT_TO_SOURCE_FILE = null;
private final ResourceCreator classFileCreator;
/** Special value for "classFileResourceCreator". */
public static final ResourceCreator CREATE_NEXT_TO_SOURCE_FILE = null;
private final String optionalCharacterEncoding;
private final Benchmark benchmark;
private final boolean debugSource;
private final boolean debugLines;
private final boolean debugVars;
private WarningHandler optionalWarningHandler;
private ErrorHandler optionalCompileErrorHandler;
private final IClassLoader iClassLoader;
private final List<UnitCompiler> parsedCompilationUnits = new ArrayList();
/**
* Initialize a Java&trade; compiler with the given parameters.
* <p>
* Classes are searched in the following order:
* <ul>
* <li>If {@code optionalBootClassPath} is {@code null}:
* <ul>
* <li>Through the system class loader of the JVM that runs JANINO
* </ul>
* <li>If {@code optionalBootClassPath} is not {@code null}:
* <ul>
* <li>Through the {@code optionalBootClassPath}
* </ul>
* <li>If {@code optionalExtDirs} is not {@code null}:
* <ul>
* <li>Through the {@code optionalExtDirs}
* </ul>
* <li>Through the {@code classPath}
* <li>If {@code optionalSourcePath} is {@code null}:
* <ul>
* <li>Through source files found on the {@code classPath}
* </ul>
* <li>If {@code optionalSourcePath} is not {@code null}:
* <ul>
* <li>Through source files found on the {@code sourcePath}
* </ul>
* </ul>
* <p>
* The file name of a class file that represents class "pkg.Example"
* is determined as follows:
* <ul>
* <li>
* If {@code optionalDestinationDirectory} is not {@link #NO_DESTINATION_DIRECTORY}:
* {@code <i>optionalDestinationDirectory</i>/pkg/Example.class}
* <li>
* If {@code optionalDestinationDirectory} is {@link #NO_DESTINATION_DIRECTORY}:
* {@code dir1/dir2/Example.class} (Assuming that the file name of the
* source file that declares the class was
* {@code dir1/dir2/Any.java}.)
* </ul>
*
* @see #DEFAULT_WARNING_HANDLE_PATTERNS
*/
public
Compiler(
final File[] optionalSourcePath,
final File[] classPath,
final File[] optionalExtDirs,
final File[] optionalBootClassPath,
final File destinationDirectory,
final String optionalCharacterEncoding,
boolean verbose,
boolean debugSource,
boolean debugLines,
boolean debugVars,
StringPattern[] warningHandlePatterns,
boolean rebuild
) {
this(
new PathResourceFinder( // sourceFinder
optionalSourcePath == null ? classPath : optionalSourcePath
),
IClassLoader.createJavacLikePathIClassLoader( // iClassLoader
optionalBootClassPath,
optionalExtDirs,
classPath
),
( // classFileFinder
rebuild
? ResourceFinder.EMPTY_RESOURCE_FINDER
: destinationDirectory == Compiler.NO_DESTINATION_DIRECTORY
? Compiler.FIND_NEXT_TO_SOURCE_FILE
: new DirectoryResourceFinder(destinationDirectory)
),
( // classFileCreator
destinationDirectory == Compiler.NO_DESTINATION_DIRECTORY
? Compiler.CREATE_NEXT_TO_SOURCE_FILE
: new DirectoryResourceCreator(destinationDirectory)
),
optionalCharacterEncoding, // optionalCharacterEncoding
verbose, // verbose
debugSource, // debugSource
debugLines, // debugLines
debugVars, // debugVars
new FilterWarningHandler( // optionalWarningHandler
warningHandlePatterns,
new SimpleWarningHandler() // <= Anonymous class here is complicated because the enclosing instance is
// not fully initialized yet
)
);
this.benchmark.report("*** JANINO - an embedded compiler for the Java(TM) programming language");
this.benchmark.report("*** For more information visit http://janino.codehaus.org");
this.benchmark.report("Source path", optionalSourcePath);
this.benchmark.report("Class path", classPath);
this.benchmark.report("Ext dirs", optionalExtDirs);
this.benchmark.report("Boot class path", optionalBootClassPath);
this.benchmark.report("Destination directory", destinationDirectory);
this.benchmark.report("Character encoding", optionalCharacterEncoding);
this.benchmark.report("Verbose", new Boolean(verbose));
this.benchmark.report("Debug source", new Boolean(debugSource));
this.benchmark.report("Debug lines", new Boolean(debugSource));
this.benchmark.report("Debug vars", new Boolean(debugSource));
this.benchmark.report("Warning handle patterns", warningHandlePatterns);
this.benchmark.report("Rebuild", new Boolean(rebuild));
}
/** Backwards compatibility -- previously, "null" was officially documented. */
public static final File NO_DESTINATION_DIRECTORY = null;
/** Prints warnings to STDERR. */
public static
class SimpleWarningHandler implements WarningHandler {
@Override public void
handleWarning(String handle, String message, Location optionalLocation) {
StringBuilder sb = new StringBuilder();
if (optionalLocation != null) sb.append(optionalLocation).append(": ");
sb.append("Warning ").append(handle).append(": ").append(message);
System.err.println(sb.toString());
}
}
/**
* The default value for the {@code warningHandlerPatterns} parameter of {@link Compiler#Compiler(File[], File[],
* File[], File[], File, String, boolean, boolean, boolean, boolean, StringPattern[], boolean)}.
*/
public static final StringPattern[] DEFAULT_WARNING_HANDLE_PATTERNS = StringPattern.PATTERNS_NONE;
/**
* To mimic the behavior of JAVAC with a missing "-d" command line option,
* pass {@link #FIND_NEXT_TO_SOURCE_FILE} as the {@code classFileResourceFinder} and
* {@link #CREATE_NEXT_TO_SOURCE_FILE} as the {@code classFileResourceCreator}.
* <p>
* If it is impossible to check whether an already-compiled class file
* exists, or if you want to enforce recompilation, pass
* {@link ResourceFinder#EMPTY_RESOURCE_FINDER} as the
* {@code classFileResourceFinder}.
*
* @param sourceFinder Finds extra Java compilation units that need to be compiled (a.k.a. "-sourcepath")
* @param iClassLoader Loads auxiliary {@link IClass}es (a.k.a. "-classpath"), e.g. <code>new
* ClassLoaderIClassLoader(ClassLoader)</code>
* @param classFileFinder Where to look for up-to-date class files that need not be compiled (a.k.a. "-d")
* @param classFileCreator Used to store generated class files (a.k.a. "-d")
* @param optionalWarningHandler Used to issue warnings
*/
public
Compiler(
ResourceFinder sourceFinder,
IClassLoader iClassLoader,
ResourceFinder classFileFinder,
ResourceCreator classFileCreator,
final String optionalCharacterEncoding,
boolean verbose,
boolean debugSource,
boolean debugLines,
boolean debugVars,
WarningHandler optionalWarningHandler
) {
this.classFileFinder = classFileFinder;
this.classFileCreator = classFileCreator;
this.optionalCharacterEncoding = optionalCharacterEncoding;
this.benchmark = new Benchmark(verbose);
this.debugSource = debugSource;
this.debugLines = debugLines;
this.debugVars = debugVars;
this.optionalWarningHandler = optionalWarningHandler;
// Set up the IClassLoader.
this.iClassLoader = new CompilerIClassLoader(sourceFinder, iClassLoader);
}
/**
* Install a custom {@link ErrorHandler}. The default {@link ErrorHandler} prints the first 20 compile errors to
* {@link System#err} and then throws a {@link CompileException}.
* <p>
* Passing {@code null} restores the default {@link ErrorHandler}.
* <p>
* Notice that scan and parse errors are <i>not</i> redirected to this {@link ErrorHandler}, instead, they cause a
* {@link CompileException} to be thrown. Also, the {@link Compiler} may choose to throw {@link CompileException}s
* in certain, fatal compile error situations, even if an {@link ErrorHandler} is installed.
* <p>
* In other words: In situations where compilation can reasonably continue after a compile error, the {@link
* ErrorHandler} is called; all other error conditions cause a {@link CompileException} to be thrown.
*/
public void
setCompileErrorHandler(ErrorHandler optionalCompileErrorHandler) {
this.optionalCompileErrorHandler = optionalCompileErrorHandler;
}
/**
* By default, warnings are discarded, but an application my install a custom {@link WarningHandler}.
*
* @param optionalWarningHandler {@code null} to indicate that no warnings be issued
*/
public void
setWarningHandler(WarningHandler optionalWarningHandler) {
this.optionalWarningHandler = optionalWarningHandler;
}
/**
* Reads a set of Java&trade; compilation units (a.k.a. "source
* files") from the file system, compiles them into a set of "class
* files" and stores these in the file system. Additional source files are
* parsed and compiled on demand through the "source path" set of
* directories.
* <p>
* For example, if the source path comprises the directories "A/B" and "../C",
* then the source file for class "com.acme.Main" is searched in
* <dl>
* <dd>A/B/com/acme/Main.java
* <dd>../C/com/acme/Main.java
* </dl>
* Notice that it does make a difference whether you pass multiple source
* files to {@link #compile(File[])} or if you invoke
* {@link #compile(File[])} multiply: In the former case, the source
* files may contain arbitrary references among each other (even circular
* ones). In the latter case, only the source files on the source path
* may contain circular references, not the {@code sourceFiles}.
* <p>
* This method must be called exactly once after object construction.
* <p>
* Compile errors are reported as described at
* {@link #setCompileErrorHandler(ErrorHandler)}.
*
* @param sourceFiles Contain the compilation units to compile
* @return {@code true} for backwards compatibility (return value can safely be ignored)
* @throws CompileException Fatal compilation error, or the {@link CompileException} thrown be the installed compile
* error handler
* @throws IOException Occurred when reading from the {@code sourceFiles}
*/
public boolean
compile(File[] sourceFiles) throws CompileException, IOException {
this.benchmark.report("Source files", sourceFiles);
Resource[] sourceFileResources = new Resource[sourceFiles.length];
for (int i = 0; i < sourceFiles.length; ++i) sourceFileResources[i] = new FileResource(sourceFiles[i]);
this.compile(sourceFileResources);
return true;
}
/**
* See {@link #compile(File[])}.
*
* @param sourceResources Contain the compilation units to compile
* @return {@code true} for backwards compatibility (return value can safely be ignored)
*/
public boolean
compile(Resource[] sourceResources) throws CompileException, IOException {
// Set up the compile error handler as described at "setCompileErrorHandler()".
final ErrorHandler ceh = (
this.optionalCompileErrorHandler != null
? this.optionalCompileErrorHandler
: new ErrorHandler() {
int compileErrorCount;
@Override public void
handleError(String message, Location optionalLocation) throws CompileException {
CompileException ex = new CompileException(message, optionalLocation);
if (++this.compileErrorCount >= 20) throw ex;
System.err.println(ex.getMessage());
}
}
);
this.benchmark.beginReporting();
try {
// Parse all source files.
this.parsedCompilationUnits.clear();
for (Resource sourceResource : sourceResources) {
if (Compiler.DEBUG) System.out.println("Compiling \"" + sourceResource + "\"");
this.parsedCompilationUnits.add(new UnitCompiler(this.parseCompilationUnit(
sourceResource.getFileName(), // fileName
new BufferedInputStream(sourceResource.open()), // inputStream
this.optionalCharacterEncoding // optionalCharacterEncoding
), this.iClassLoader));
}
// Compile all parsed compilation units. The vector of parsed CUs may grow while they are being compiled,
// but eventually all CUs will be compiled.
for (int i = 0; i < this.parsedCompilationUnits.size(); ++i) {
UnitCompiler unitCompiler = (UnitCompiler) this.parsedCompilationUnits.get(i);
File sourceFile;
{
CompilationUnit compilationUnit = unitCompiler.getCompilationUnit();
if (compilationUnit.optionalFileName == null) throw new JaninoRuntimeException();
sourceFile = new File(compilationUnit.optionalFileName);
}
unitCompiler.setCompileErrorHandler(ceh);
unitCompiler.setWarningHandler(this.optionalWarningHandler);
this.benchmark.beginReporting("Compiling compilation unit \"" + sourceFile + "\"");
ClassFile[] classFiles;
try {
// Compile the compilation unit.
classFiles = unitCompiler.compileUnit(this.debugSource, this.debugLines, this.debugVars);
} finally {
this.benchmark.endReporting();
}
// Store the compiled classes and interfaces into class files.
this.benchmark.beginReporting(
"Storing "
+ classFiles.length
+ " class file(s) resulting from compilation unit \""
+ sourceFile
+ "\""
);
try {
for (ClassFile classFile : classFiles) this.storeClassFile(classFile, sourceFile);
} finally {
this.benchmark.endReporting();
}
}
} finally {
this.benchmark.endReporting("Compiled " + this.parsedCompilationUnits.size() + " compilation unit(s)");
}
return true;
}
/**
* Read one compilation unit from a file and parse it.
* <p>
* The {@code inputStream} is closed before the method returns.
* @return the parsed compilation unit
*/
private Java.CompilationUnit
parseCompilationUnit(
String fileName,
InputStream inputStream,
String optionalCharacterEncoding
) throws CompileException, IOException {
try {
Scanner scanner = new Scanner(fileName, inputStream, optionalCharacterEncoding);
scanner.setWarningHandler(this.optionalWarningHandler);
Parser parser = new Parser(scanner);
parser.setWarningHandler(this.optionalWarningHandler);
this.benchmark.beginReporting("Parsing \"" + fileName + "\"");
try {
return parser.parseCompilationUnit();
} finally {
this.benchmark.endReporting();
}
} finally {
inputStream.close();
}
}
/**
* Construct the name of a file that could store the byte code of the class with the given
* name.
* <p>
* If {@code optionalDestinationDirectory} is non-null, the returned path is the
* {@code optionalDestinationDirectory} plus the package of the class (with dots replaced
* with file separators) plus the class name plus ".class". Example:
* "destdir/pkg1/pkg2/Outer$Inner.class"
* <p>
* If {@code optionalDestinationDirectory} is null, the returned path is the
* directory of the {@code sourceFile} plus the class name plus ".class". Example:
* "srcdir/Outer$Inner.class"
* @param className E.g. "pkg1.pkg2.Outer$Inner"
* @param sourceFile E.g. "srcdir/Outer.java"
* @param optionalDestinationDirectory E.g. "destdir"
*/
public static File
getClassFile(String className, File sourceFile, File optionalDestinationDirectory) {
if (optionalDestinationDirectory != null) {
return new File(optionalDestinationDirectory, ClassFile.getClassFileResourceName(className));
} else {
int idx = className.lastIndexOf('.');
return new File(
sourceFile.getParentFile(),
ClassFile.getClassFileResourceName(className.substring(idx + 1))
);
}
}
/**
* Store the byte code of this {@link ClassFile} in the file system. Directories are created
* as necessary.
* @param classFile
* @param sourceFile Required to compute class file path if no destination directory given
*/
public void
storeClassFile(ClassFile classFile, final File sourceFile) throws IOException {
String classFileResourceName = ClassFile.getClassFileResourceName(classFile.getThisClassName());
// Determine where to create the class file.
ResourceCreator rc;
if (this.classFileCreator != Compiler.CREATE_NEXT_TO_SOURCE_FILE) {
rc = this.classFileCreator;
} else {
// If the JAVAC option "-d" is given, place the class file next
// to the source file, irrespective of the package name.
rc = new FileResourceCreator() {
@Override protected File
getFile(String resourceName) {
return new File(
sourceFile.getParentFile(),
resourceName.substring(resourceName.lastIndexOf('/') + 1)
);
}
};
}
OutputStream os = rc.createResource(classFileResourceName);
try {
classFile.store(os);
} catch (IOException ioe) {
try { os.close(); } catch (IOException e) {}
os = null;
if (!rc.deleteResource(classFileResourceName)) {
IOException ioe2 = new IOException(
"Could not delete incompletely written class file \""
+ classFileResourceName
+ "\""
);
ioe2.initCause(ioe);
throw ioe2; // SUPPRESS CHECKSTYLE AvoidHidingCause
}
throw ioe;
} finally {
if (os != null) try { os.close(); } catch (IOException e) {}
}
}
/**
* A specialized {@link IClassLoader} that loads {@link IClass}es from the following
* sources:
* <ol>
* <li>An already-parsed compilation unit
* <li>A class file in the output directory (if existant and younger than source file)
* <li>A source file in any of the source path directories
* <li>The parent class loader
* </ol>
* Notice that the {@link CompilerIClassLoader} is an inner class of {@link Compiler} and
* heavily uses {@link Compiler}'s members.
*/
private
class CompilerIClassLoader extends IClassLoader {
private final ResourceFinder sourceFinder;
/**
* @param sourceFinder Where to look for source files
* @param optionalParentIClassLoader {@link IClassLoader} through which {@link IClass}es are to be loaded
*/
public
CompilerIClassLoader(ResourceFinder sourceFinder, IClassLoader optionalParentIClassLoader) {
super(optionalParentIClassLoader);
this.sourceFinder = sourceFinder;
super.postConstruct();
}
/**
* @param type field descriptor of the {@IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;"
* @return {@code null} if a the type could not be found
* @throws ClassNotFoundException if an exception was raised while loading the {@link IClass}
*/
@Override protected IClass
findIClass(final String type) throws ClassNotFoundException {
if (Compiler.DEBUG) System.out.println("type = " + type);
// Determine the class name.
String className = Descriptor.toClassName(type); // E.g. "pkg1.pkg2.Outer$Inner"
if (Compiler.DEBUG) System.out.println("2 className = \"" + className + "\"");
// Do not attempt to load classes from package "java".
if (className.startsWith("java.")) return null;
// Determine the name of the top-level class.
String topLevelClassName;
{
int idx = className.indexOf('$');
topLevelClassName = idx == -1 ? className : className.substring(0, idx);
}
// Check the already-parsed compilation units.
for (int i = 0; i < Compiler.this.parsedCompilationUnits.size(); ++i) {
UnitCompiler uc = (UnitCompiler) Compiler.this.parsedCompilationUnits.get(i);
IClass res = uc.findClass(topLevelClassName);
if (res != null) {
if (!className.equals(topLevelClassName)) {
res = uc.findClass(className);
if (res == null) return null;
}
this.defineIClass(res);
return res;
}
}
// Search source path for uncompiled class.
final Resource sourceResource = this.sourceFinder.findResource(ClassFile.getSourceResourceName(className));
if (sourceResource == null) return null;
// Find an existing class file.
Resource classFileResource;
if (Compiler.this.classFileFinder != Compiler.FIND_NEXT_TO_SOURCE_FILE) {
classFileResource = Compiler.this.classFileFinder.findResource(
ClassFile.getClassFileResourceName(className)
);
} else {
if (!(sourceResource instanceof FileResource)) return null;
File classFile = new File(
((FileResource) sourceResource).getFile().getParentFile(),
ClassFile.getClassFileResourceName(className.substring(className.lastIndexOf('.') + 1))
);
classFileResource = classFile.exists() ? new FileResource(classFile) : null;
}
// Compare source modification time against class file modification time.
if (classFileResource != null && sourceResource.lastModified() <= classFileResource.lastModified()) {
// The class file is up-to-date; load it.
return this.defineIClassFromClassFileResource(classFileResource);
} else {
// Source file not yet compiled or younger than class file.
return this.defineIClassFromSourceResource(sourceResource, className);
}
}
/**
* Parse the compilation unit stored in the given {@code sourceResource}, remember it in
* {@code Compiler.this.parsedCompilationUnits} (it may declare other classes that
* are needed later), find the declaration of the type with the given
* {@code className}, and define it in the {@link IClassLoader}.
* <p>
* Notice that the CU is not compiled here!
*/
private IClass
defineIClassFromSourceResource(Resource sourceResource, String className) throws ClassNotFoundException {
// Parse the source file.
UnitCompiler uc;
try {
Java.CompilationUnit cu = Compiler.this.parseCompilationUnit(
sourceResource.getFileName(), // fileName
new BufferedInputStream(sourceResource.open()), // inputStream
Compiler.this.optionalCharacterEncoding // optionalCharacterEncoding
);
uc = new UnitCompiler(cu, Compiler.this.iClassLoader);
} catch (IOException ex) {
throw new ClassNotFoundException("Parsing compilation unit \"" + sourceResource + "\"", ex);
} catch (CompileException ex) {
throw new ClassNotFoundException("Parsing compilation unit \"" + sourceResource + "\"", ex);
}
// Remember compilation unit for later compilation.
Compiler.this.parsedCompilationUnits.add(uc);
// Define the class.
IClass res = uc.findClass(className);
if (res == null) {
// This is a really complicated case: We may find a source file on the source
// path that seemingly contains the declaration of the class we are looking
// for, but doesn't. This is possible if the underlying file system has
// case-insensitive file names and/or file names that are limited in length
// (e.g. DOS 8.3).
return null;
}
this.defineIClass(res);
return res;
}
/**
* Open the given {@code classFileResource}, read its contents, define it in the
* {@link IClassLoader}, and resolve it (this step may involve loading more classes).
*/
private IClass
defineIClassFromClassFileResource(Resource classFileResource) throws ClassNotFoundException {
Compiler.this.benchmark.beginReporting("Loading class file \"" + classFileResource.getFileName() + "\"");
try {
InputStream is = null;
ClassFile cf;
try {
is = classFileResource.open();
cf = new ClassFile(new BufferedInputStream(is));
} catch (IOException ex) {
throw new ClassNotFoundException("Opening class file resource \"" + classFileResource + "\"", ex);
} finally {
if (is != null) try { is.close(); } catch (IOException e) {}
}
ClassFileIClass result = new ClassFileIClass(
cf, // classFile
CompilerIClassLoader.this // iClassLoader
);
// Important: We must FIRST call "defineIClass()" so that the
// new IClass is known to the IClassLoader, and THEN
// "resolveAllClasses()", because otherwise endless recursion could
// occur.
this.defineIClass(result);
result.resolveAllClasses();
return result;
} finally {
Compiler.this.benchmark.endReporting();
}
}
}
}

View File

@ -0,0 +1,78 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.codehaus.commons.compiler.AbstractCompilerFactory;
import org.codehaus.commons.compiler.AbstractJavaSourceClassLoader;
import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.codehaus.commons.compiler.ICompilerFactory;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.codehaus.commons.compiler.IScriptEvaluator;
import org.codehaus.commons.compiler.ISimpleCompiler;
/** The JANINO implementation of {@link ICompilerFactory}. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class CompilerFactory extends AbstractCompilerFactory {
@Override public String
getId() { return "org.codehaus.janino"; }
@Override public String
toString() { return "janino"; }
@Override public String
getImplementationVersion() { return CompilerFactory.class.getPackage().getImplementationVersion(); }
@Override public IExpressionEvaluator
newExpressionEvaluator() { return new ExpressionEvaluator(); }
@Override public IScriptEvaluator
newScriptEvaluator() { return new ScriptEvaluator(); }
@Override public IClassBodyEvaluator
newClassBodyEvaluator() { return new ClassBodyEvaluator(); }
@Override public ISimpleCompiler
newSimpleCompiler() { return new SimpleCompiler(); }
@Override public AbstractJavaSourceClassLoader
newJavaSourceClassLoader() {
return (AbstractJavaSourceClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
@Override public Object run() { return new JavaSourceClassLoader(); }
});
}
@Override public AbstractJavaSourceClassLoader
newJavaSourceClassLoader(final ClassLoader parentClassLoader) {
return (AbstractJavaSourceClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
@Override public Object run() { return new JavaSourceClassLoader(parentClassLoader); }
});
}
}

View File

@ -0,0 +1,389 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Helper class that defines useful methods for handling "field descriptors"
* (JVMS 4.3.2) and "method descriptors" (JVMS 4.3.3).<p>
* Typical descriptors are:
* <ul>
* <li><code>I</code> Integer
* <li><code>[I</code> Array of integer
* <li><code>Lpkg1/pkg2/Cls;</code> Class
* <li><code>Lpkg1/pkg2/Outer$Inner;</code> Member class
* </ul>
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public final
class Descriptor {
private Descriptor() {}
/** @return Whether this {@link Descriptor} describes a reference (i.e. non-primitive) type */
public static boolean
isReference(String d) { return d.length() > 1; }
/**
* @return Whether this {@link Descriptor} describes a class or an interface (and not an array or a primitive type)
*/
public static boolean
isClassOrInterfaceReference(String d) { return d.charAt(0) == 'L'; }
/** @return Whether this {@link Descriptor} describes an array type */
public static boolean
isArrayReference(String d) { return d.charAt(0) == '['; }
/**
* @return The descriptor of the component of the array type {@code d}
* @throws JaninoRuntimeException {@code d} does not describe an array type
*/
public static String
getComponentDescriptor(String d) {
if (d.charAt(0) != '[') {
throw new JaninoRuntimeException(
"Cannot determine component descriptor from non-array descriptor \""
+ d
+ "\""
);
}
return d.substring(1);
}
/**
* @return The number of slots (1 or two) that a value of the type described by {@code d} occupies on the operand
* stack or in the local variable array, or 0 iff {@code d} describes the type VOID
*/
public static short
size(String d) {
if (d.equals(Descriptor.VOID)) return 0;
if (Descriptor.hasSize1(d)) return 1;
if (Descriptor.hasSize2(d)) return 2;
throw new JaninoRuntimeException("No size defined for type \"" + Descriptor.toString(d) + "\"");
}
/** @return {@code true} iff {@code d} describes a primitive type except LONG and DOUBLE, or a reference type */
public static boolean
hasSize1(String d) {
if (d.length() == 1) return "BCFISZ".indexOf(d) != -1;
return Descriptor.isReference(d);
}
/** @return {@code true} iff {@code d} LONG or DOUBLE */
public static boolean
hasSize2(String d) {
return d.equals(Descriptor.LONG) || d.equals(Descriptor.DOUBLE);
}
/**
* Pretty-prints the given descriptor.
*
* @param d A valid field or method descriptor
*/
public static String
toString(String d) {
int idx = 0;
StringBuilder sb = new StringBuilder();
if (d.charAt(0) == '(') {
++idx;
sb.append("(");
while (idx < d.length() && d.charAt(idx) != ')') {
if (idx != 1) sb.append(", ");
idx = Descriptor.toString(d, idx, sb);
}
if (idx >= d.length()) throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
sb.append(") => ");
++idx;
}
Descriptor.toString(d, idx, sb);
return sb.toString();
}
private static int
toString(String d, int idx, StringBuilder sb) {
int dimensions = 0;
while (idx < d.length() && d.charAt(idx) == '[') {
++dimensions;
++idx;
}
if (idx >= d.length()) throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
switch (d.charAt(idx)) {
case 'L':
{
int idx2 = d.indexOf(';', idx);
if (idx2 == -1) throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
sb.append(d.substring(idx + 1, idx2).replace('/', '.'));
idx = idx2;
}
break;
case 'V':
sb.append("void");
break;
case 'B':
sb.append("byte");
break;
case 'C':
sb.append("char");
break;
case 'D':
sb.append("double");
break;
case 'F':
sb.append("float");
break;
case 'I':
sb.append("int");
break;
case 'J':
sb.append("long");
break;
case 'S':
sb.append("short");
break;
case 'Z':
sb.append("boolean");
break;
default:
throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
}
for (; dimensions > 0; --dimensions) sb.append("[]");
return idx + 1;
}
/** Converts a class name as defined by "Class.getName()" into a descriptor. */
public static String
fromClassName(String className) {
String res = (String) Descriptor.CLASS_NAME_TO_DESCRIPTOR.get(className);
if (res != null) { return res; }
if (className.startsWith("[")) return className.replace('.', '/');
return 'L' + className.replace('.', '/') + ';';
}
/**
* Convert a class name in the "internal form" as described in JVMS 4.2 into a descriptor.
* <p>
* Also implement the encoding of array types as described in JVMS 4.4.1.
*/
public static String
fromInternalForm(String internalForm) {
if (internalForm.charAt(0) == '[') return internalForm;
return 'L' + internalForm + ';';
}
/** Converts a field descriptor into a class name as defined by {@link Class#getName()}. */
public static String
toClassName(String d) {
String res = (String) Descriptor.DESCRIPTOR_TO_CLASSNAME.get(d);
if (res != null) { return res; }
char firstChar = d.charAt(0);
if (firstChar == 'L' && d.endsWith(";")) {
// Class or interface -- convert "Ljava/lang/String;" to "java.lang.String".
return d.substring(1, d.length() - 1).replace('/', '.');
}
if (firstChar == '[') {
// Array type -- convert "[Ljava/lang/String;" to "[Ljava.lang.String;".
return d.replace('/', '.');
}
throw new JaninoRuntimeException("(Invalid field descriptor \"" + d + "\")");
}
/** Converts a descriptor into the "internal form" as defined by JVMS 4.2. */
public static String
toInternalForm(String d) {
if (d.charAt(0) != 'L') {
throw new JaninoRuntimeException(
"Attempt to convert non-class descriptor \""
+ d
+ "\" into internal form"
);
}
return d.substring(1, d.length() - 1);
}
/** @return Whether {@code d} describes a primitive type or VOID */
public static boolean
isPrimitive(String d) { return d.length() == 1 && "VBCDFIJSZ".indexOf(d.charAt(0)) != -1; }
/** @return Whether {@code d} describes a primitive type except BOOLEAN and VOID */
public static boolean
isPrimitiveNumeric(String d) { return d.length() == 1 && "BDFIJSC".indexOf(d.charAt(0)) != -1; }
/**
* Returns the package name of a class or interface reference descriptor,
* or <code>null</code> if the class or interface is declared in the
* default package.
*/
public static String
getPackageName(String d) {
if (d.charAt(0) != 'L') {
throw new JaninoRuntimeException("Attempt to get package name of non-class descriptor \"" + d + "\"");
}
int idx = d.lastIndexOf('/');
return idx == -1 ? null : d.substring(1, idx).replace('/', '.');
}
/** Checks whether two reference types are declared in the same package. */
public static boolean
areInSamePackage(String d1, String d2) {
String packageName1 = Descriptor.getPackageName(d1);
String packageName2 = Descriptor.getPackageName(d2);
return packageName1 == null ? packageName2 == null : packageName1.equals(packageName2);
}
/** The field descriptor for the type VOID. */
public static final String VOID = "V";
// Primitive types.
/** The field descriptor for the primitive type BYTE. */
public static final String BYTE = "B";
/** The field descriptor for the primitive type CHAR. */
public static final String CHAR = "C";
/** The field descriptor for the primitive type DOUBLE. */
public static final String DOUBLE = "D";
/** The field descriptor for the primitive type FLOAT. */
public static final String FLOAT = "F";
/** The field descriptor for the primitive type INT. */
public static final String INT = "I";
/** The field descriptor for the primitive type LONG. */
public static final String LONG = "J";
/** The field descriptor for the primitive type SHORT. */
public static final String SHORT = "S";
/** The field descriptor for the primitive type BOOLEAN. */
public static final String BOOLEAN = "Z";
// Annotations.
/** The field descriptor for the annotation {@link java.lang.Override}. */
public static final String JAVA_LANG_OVERRIDE = "Ljava/lang/Override;";
// Classes.
/** The field descriptor for the class {@link java.lang.AssertionError}. */
public static final String JAVA_LANG_ASSERTIONERROR = "Ljava/lang/AssertionError;";
/** The field descriptor for the class {@link java.lang.Boolean}. */
public static final String JAVA_LANG_BOOLEAN = "Ljava/lang/Boolean;";
/** The field descriptor for the class {@link java.lang.Byte}. */
public static final String JAVA_LANG_BYTE = "Ljava/lang/Byte;";
/** The field descriptor for the class {@link java.lang.Character}. */
public static final String JAVA_LANG_CHARACTER = "Ljava/lang/Character;";
/** The field descriptor for the class {@link java.lang.Class}. */
public static final String JAVA_LANG_CLASS = "Ljava/lang/Class;";
/** The field descriptor for the class {@link java.lang.Double}. */
public static final String JAVA_LANG_DOUBLE = "Ljava/lang/Double;";
/** The field descriptor for the class {@link java.lang.Exception}. */
public static final String JAVA_LANG_EXCEPTION = "Ljava/lang/Exception;";
/** The field descriptor for the class {@link java.lang.Error}. */
public static final String JAVA_LANG_ERROR = "Ljava/lang/Error;";
/** The field descriptor for the class {@link java.lang.Float}. */
public static final String JAVA_LANG_FLOAT = "Ljava/lang/Float;";
/** The field descriptor for the class {@link java.lang.Integer}. */
public static final String JAVA_LANG_INTEGER = "Ljava/lang/Integer;";
/** The field descriptor for the class {@link java.lang.Long}. */
public static final String JAVA_LANG_LONG = "Ljava/lang/Long;";
/** The field descriptor for the class {@link java.lang.Object}. */
public static final String JAVA_LANG_OBJECT = "Ljava/lang/Object;";
/** The field descriptor for the class {@link java.lang.RuntimeException}. */
public static final String JAVA_LANG_RUNTIMEEXCEPTION = "Ljava/lang/RuntimeException;";
/** The field descriptor for the class {@link java.lang.Short}. */
public static final String JAVA_LANG_SHORT = "Ljava/lang/Short;";
/** The field descriptor for the class {@link java.lang.String}. */
public static final String JAVA_LANG_STRING = "Ljava/lang/String;";
/** The field descriptor for the class {@link java.lang.StringBuilder}. */
public static final String JAVA_LANG_STRINGBUILDER = "Ljava/lang/StringBuilder;"; // Since 1.5!
/** The field descriptor for the class {@link java.lang.Throwable}. */
public static final String JAVA_LANG_THROWABLE = "Ljava/lang/Throwable;";
// Interfaces.
/** The field descriptor for the interface {@link java.io.Serializable}. */
public static final String JAVA_IO_SERIALIZABLE = "Ljava/io/Serializable;";
/** The field descriptor for the interface {@link java.lang.Cloneable}. */
public static final String JAVA_LANG_CLONEABLE = "Ljava/lang/Cloneable;";
/** The field descriptor for the interface {@link java.lang.Iterable}. */
public static final String JAVA_LANG_ITERABLE = "Ljava/lang/Iterable;";
/** The field descriptor for the interface {@link java.util.Iterator}. */
public static final String JAVA_UTIL_ITERATOR = "Ljava/util/Iterator;";
private static final Map<String, String> DESCRIPTOR_TO_CLASSNAME;
static {
Map<String, String> m = new HashMap();
m.put(Descriptor.VOID, "void");
// Primitive types.
m.put(Descriptor.BYTE, "byte");
m.put(Descriptor.CHAR, "char");
m.put(Descriptor.DOUBLE, "double");
m.put(Descriptor.FLOAT, "float");
m.put(Descriptor.INT, "int");
m.put(Descriptor.LONG, "long");
m.put(Descriptor.SHORT, "short");
m.put(Descriptor.BOOLEAN, "boolean");
// Annotations.
m.put(Descriptor.JAVA_LANG_OVERRIDE, "java.lang.Override");
// Classes.
m.put(Descriptor.JAVA_LANG_ASSERTIONERROR, "java.lang.AssertionError");
m.put(Descriptor.JAVA_LANG_BOOLEAN, "java.lang.Boolean");
m.put(Descriptor.JAVA_LANG_BYTE, "java.lang.Byte");
m.put(Descriptor.JAVA_LANG_CHARACTER, "java.lang.Character");
m.put(Descriptor.JAVA_LANG_CLASS, "java.lang.Class");
m.put(Descriptor.JAVA_LANG_DOUBLE, "java.lang.Double");
m.put(Descriptor.JAVA_LANG_EXCEPTION, "java.lang.Exception");
m.put(Descriptor.JAVA_LANG_ERROR, "java.lang.Error");
m.put(Descriptor.JAVA_LANG_FLOAT, "java.lang.Float");
m.put(Descriptor.JAVA_LANG_INTEGER, "java.lang.Integer");
m.put(Descriptor.JAVA_LANG_LONG, "java.lang.Long");
m.put(Descriptor.JAVA_LANG_OBJECT, "java.lang.Object");
m.put(Descriptor.JAVA_LANG_RUNTIMEEXCEPTION, "java.lang.RuntimeException");
m.put(Descriptor.JAVA_LANG_SHORT, "java.lang.Short");
m.put(Descriptor.JAVA_LANG_STRING, "java.lang.String");
m.put(Descriptor.JAVA_LANG_STRINGBUILDER, "java.lang.StringBuilder");
m.put(Descriptor.JAVA_LANG_THROWABLE, "java.lang.Throwable");
// Interfaces.
m.put(Descriptor.JAVA_IO_SERIALIZABLE, "java.io.Serializable");
m.put(Descriptor.JAVA_LANG_CLONEABLE, "java.lang.Cloneable");
m.put(Descriptor.JAVA_LANG_ITERABLE, "java.lang.Iterable");
m.put(Descriptor.JAVA_UTIL_ITERATOR, "java.util.Iterator");
DESCRIPTOR_TO_CLASSNAME = Collections.unmodifiableMap(m);
}
private static final Map<String, String> CLASS_NAME_TO_DESCRIPTOR;
static {
Map<String, String> m = new HashMap();
for (Map.Entry<String, String> e : Descriptor.DESCRIPTOR_TO_CLASSNAME.entrySet()) {
m.put(e.getValue(), e.getKey());
}
CLASS_NAME_TO_DESCRIPTOR = Collections.unmodifiableMap(m);
}
}

View File

@ -0,0 +1,445 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.CompilerFactoryFactory;
import org.codehaus.commons.compiler.Cookable;
import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.codehaus.commons.compiler.ICompilerFactory;
import org.codehaus.commons.compiler.ICookable;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.codehaus.commons.compiler.IScriptEvaluator;
import org.codehaus.commons.compiler.ISimpleCompiler;
import org.codehaus.commons.compiler.PrimitiveWrapper;
import org.codehaus.janino.Java.AmbiguousName;
import org.codehaus.janino.Java.BlockStatement;
import org.codehaus.janino.Java.Rvalue;
import org.codehaus.janino.Visitor.RvalueVisitor;
import org.codehaus.janino.util.Traverser;
/**
* This {@link IExpressionEvaluator} is implemented by creating and compiling a temporary
* compilation unit defining one class with one static method with one RETURN statement.
* <p>
* A number of "convenience constructors" exist that execute the set-up steps described for {@link
* IExpressionEvaluator} instantly.
* <p>
* If the parameter and return types of the expression are known at compile time, then a "fast"
* expression evaluator can be instantiated through
* {@link #createFastExpressionEvaluator(String, Class, String[], ClassLoader)}. Expression
* evaluation is faster than through {@link #evaluate(Object[])}, because it is not done through
* reflection but through direct method invocation.
* <p>
* Example:
* <pre>
* public interface Foo {
* int bar(int a, int b);
* }
* ...
* Foo f = (Foo) ExpressionEvaluator.createFastExpressionEvaluator(
* "a + b", // expression to evaluate
* Foo.class, // interface that describes the expression's signature
* new String[] { "a", "b" }, // the parameters' names
* (ClassLoader) null // Use current thread's context class loader
* );
* System.out.println("1 + 2 = " + f.bar(1, 2)); // Evaluate the expression
* </pre>
* Notice: The <code>interfaceToImplement</code> must either be declared <code>public</code>,
* or with package scope in the root package (i.e. "no" package).
* <p>
* On my system (Intel P4, 2 GHz, MS Windows XP, JDK 1.4.1), expression "x + 1"
* evaluates as follows:
* <table>
* <tr><td></td><th>Server JVM</th><th>Client JVM</th></td></tr>
* <tr><td>Normal EE</td><td>23.7 ns</td><td>64.0 ns</td></tr>
* <tr><td>Fast EE</td><td>31.2 ns</td><td>42.2 ns</td></tr>
* </table>
* (How can it be that interface method invocation is slower than reflection for
* the server JVM?)
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class ExpressionEvaluator extends ScriptEvaluator implements IExpressionEvaluator {
private Class[] optionalExpressionTypes;
/**
* Equivalent to<pre>
* ExpressionEvaluator ee = new ExpressionEvaluator();
* ee.setExpressionType(expressionType);
* ee.setParameters(parameterNames, parameterTypes);
* ee.cook(expression);</pre>
*
* @see #ExpressionEvaluator()
* @see ExpressionEvaluator#setExpressionType(Class)
* @see ScriptEvaluator#setParameters(String[], Class[])
* @see Cookable#cook(String)
*/
public
ExpressionEvaluator(
String expression,
Class expressionType,
String[] parameterNames,
Class[] parameterTypes
) throws CompileException {
this.setExpressionType(expressionType);
this.setParameters(parameterNames, parameterTypes);
this.cook(expression);
}
/**
* Equivalent to<pre>
* ExpressionEvaluator ee = new ExpressionEvaluator();
* ee.setExpressionType(expressionType);
* ee.setParameters(parameterNames, parameterTypes);
* ee.setThrownExceptions(thrownExceptions);
* ee.setParentClassLoader(optionalParentClassLoader);
* ee.cook(expression);</pre>
*
* @see #ExpressionEvaluator()
* @see ExpressionEvaluator#setExpressionType(Class)
* @see ScriptEvaluator#setParameters(String[], Class[])
* @see ScriptEvaluator#setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(String)
*/
public
ExpressionEvaluator(
String expression,
Class expressionType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader
) throws CompileException {
this.setExpressionType(expressionType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(expression);
}
/**
* Equivalent to<pre>
* ExpressionEvaluator ee = new ExpressionEvaluator();
* ee.setExpressionType(expressionType);
* ee.setParameters(parameterNames, parameterTypes);
* ee.setThrownExceptions(thrownExceptions);
* ee.setExtendedType(optionalExtendedType);
* ee.setImplementedTypes(implementedTypes);
* ee.setParentClassLoader(optionalParentClassLoader);
* ee.cook(expression);</pre>
*
* @see #ExpressionEvaluator()
* @see ExpressionEvaluator#setExpressionType(Class)
* @see ScriptEvaluator#setParameters(String[], Class[])
* @see ScriptEvaluator#setThrownExceptions(Class[])
* @see ClassBodyEvaluator#setExtendedClass(Class)
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(String)
*/
public
ExpressionEvaluator(
String expression,
Class expressionType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
Class optionalExtendedType,
Class[] implementedTypes,
ClassLoader optionalParentClassLoader
) throws CompileException {
this.setExpressionType(expressionType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(expression);
}
/**
* Equivalent to<pre>
* ExpressionEvaluator ee = new ExpressionEvaluator();
* ee.setClassName(className);
* ee.setExtendedType(optionalExtendedType);
* ee.setImplementedTypes(implementedTypes);
* ee.setStaticMethod(staticMethod);
* ee.setExpressionType(expressionType);
* ee.setMethodName(methodName);
* ee.setParameters(parameterNames, parameterTypes);
* ee.setThrownExceptions(thrownExceptions);
* ee.setParentClassLoader(optionalParentClassLoader);
* ee.cook(scanner);
*
* @see IExpressionEvaluator
* @see IClassBodyEvaluator#setClassName(String)
* @see IClassBodyEvaluator#setExtendedClass(Class)
* @see IClassBodyEvaluator#setImplementedInterfaces(Class[])
* @see IScriptEvaluator#setStaticMethod(boolean)
* @see IExpressionEvaluator#setExpressionType(Class)
* @see IScriptEvaluator#setMethodName(String)
* @see IScriptEvaluator#setParameters(String[], Class[])
* @see IScriptEvaluator#setThrownExceptions(Class[])
* @see ISimpleCompiler#setParentClassLoader(ClassLoader)
* @see ICookable#cook(Reader)
*/
public
ExpressionEvaluator(
Scanner scanner,
String className,
Class optionalExtendedType,
Class[] implementedTypes,
boolean staticMethod,
Class expressionType,
String methodName,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
this.setClassName(className);
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setStaticMethod(staticMethod);
this.setExpressionType(expressionType);
this.setMethodName(methodName);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
public ExpressionEvaluator() {}
@Override public void
setExpressionType(Class expressionType) { this.setExpressionTypes(new Class[] { expressionType }); }
@Override public void
setExpressionTypes(Class[] expressionTypes) {
this.assertNotCooked();
this.optionalExpressionTypes = expressionTypes;
Class[] returnTypes = new Class[expressionTypes.length];
for (int i = 0; i < returnTypes.length; ++i) {
Class et = expressionTypes[i];
returnTypes[i] = et == IExpressionEvaluator.ANY_TYPE ? Object.class : et;
}
super.setReturnTypes(returnTypes);
}
/** @deprecated {@link #setExpressionType(Class)} should be called instead. */
@Override @Deprecated public final void
setReturnType(Class returnType) {
throw new AssertionError("Must not be used on an ExpressionEvaluator; use 'setExpressionType()' instead");
}
/** @deprecated {@link #setExpressionTypes(Class[])} should be called instead. */
@Override @Deprecated public final void
setReturnTypes(Class[] returnTypes) {
throw new AssertionError("Must not be used on an ExpressionEvaluator; use 'setExpressionTypes()' instead");
}
@Override protected Class
getDefaultReturnType() { return Object.class; }
@Override protected List<BlockStatement>
makeStatements(int idx, Parser parser) throws CompileException, IOException {
List<BlockStatement> statements = new ArrayList();
// Parse the expression.
Rvalue value = parser.parseExpression().toRvalueOrCompileException();
Class et = (
this.optionalExpressionTypes == null
? IExpressionEvaluator.ANY_TYPE
: this.optionalExpressionTypes[idx]
);
if (et == void.class) {
// ExpressionEvaluator with an expression type "void" is a simple expression statement.
statements.add(new Java.ExpressionStatement(value));
} else {
// Special case: Expression type "ANY_TYPE" means return type "Object" and automatic
// wrapping of primitive types.
if (et == IExpressionEvaluator.ANY_TYPE) {
value = new Java.MethodInvocation(
parser.location(), // location
new Java.ReferenceType( // optionalTarget
parser.location(), // location
new String[] { // identifiers
"org", "codehaus", "commons", "compiler", "PrimitiveWrapper"
},
null // optionalTypeArguments
),
"wrap", // methodName
new Java.Rvalue[] { value } // arguments
);
// Make sure "PrimitiveWrapper" is compiled.
PrimitiveWrapper.wrap(99);
// Verify that "PrimitiveWrapper" is loadable.
this.classToType(null, PrimitiveWrapper.class);
}
// Add a return statement.
statements.add(new Java.ReturnStatement(parser.location(), value));
}
if (!parser.peekEof()) {
throw new CompileException("Unexpected token \"" + parser.peek() + "\"", parser.location());
}
return statements;
}
/**
* <pre>
* {@link IExpressionEvaluator} ee = {@link CompilerFactoryFactory}.{@link
* CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
* ICompilerFactory#newExpressionEvaluator() newExpressionEvaluator}();
* ee.setParentClassLoader(optionalParentClassLoader);
* return ee.{@link #createFastEvaluator createFastEvaluator}(expression, interfaceToImplement, parameterNames);
* </pre>
*
* @deprecated Use {@link #createFastEvaluator(String, Class, String[])} instead:
*/
@Deprecated public static Object
createFastExpressionEvaluator(
String expression,
Class interfaceToImplement,
String[] parameterNames,
ClassLoader optionalParentClassLoader
) throws CompileException {
IExpressionEvaluator ee = new ExpressionEvaluator();
ee.setParentClassLoader(optionalParentClassLoader);
return ee.createFastEvaluator(expression, interfaceToImplement, parameterNames);
}
/**
* Notice: This method is not declared in {@link IExpressionEvaluator}, and is hence only available in <i>this</i>
* implementation of <code>org.codehaus.commons.compiler</code>. To be independent from this particular
* implementation, try to switch to {@link #createFastEvaluator(Reader, Class, String[])}.
*
* @deprecated Use {@link #createFastEvaluator(Reader, Class, String[])} instead
*/
@Deprecated public static Object
createFastExpressionEvaluator(
Scanner scanner,
String className,
Class optionalExtendedType,
Class interfaceToImplement,
String[] parameterNames,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
ExpressionEvaluator ee = new ExpressionEvaluator();
ee.setClassName(className);
ee.setExtendedClass(optionalExtendedType);
ee.setParentClassLoader(optionalParentClassLoader);
return ee.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
}
/**
* Notice: This method is not declared in {@link IExpressionEvaluator}, and is hence only available in <i>this</i>
* implementation of <code>org.codehaus.commons.compiler</code>. To be independent from this particular
* implementation, try to switch to {@link #createFastEvaluator(Reader, Class, String[])}.
*
* @deprecated Use {@link #createFastEvaluator(Reader, Class, String[])} instead
*/
@Deprecated public static Object
createFastExpressionEvaluator(
Scanner scanner,
String[] optionalDefaultImports,
String className,
Class optionalExtendedType,
Class interfaceToImplement,
String[] parameterNames,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
ExpressionEvaluator ee = new ExpressionEvaluator();
ee.setClassName(className);
ee.setExtendedClass(optionalExtendedType);
ee.setDefaultImports(optionalDefaultImports);
ee.setParentClassLoader(optionalParentClassLoader);
return ee.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
}
/**
* Guess the names of the parameters used in the given expression. The strategy is to look
* at all "ambiguous names" in the expression (e.g. in "a.b.c.d()", the ambiguous name
* is "a.b.c"), and then at the first components of the ambiguous name.
* <ul>
* <li>If any component starts with an upper-case letter, then ambiguous name is assumed to
* be a type name.
* <li>Otherwise, it is assumed to be a parameter name.
* </ul>
*
* @see Scanner#Scanner(String, Reader)
*/
public static String[]
guessParameterNames(Scanner scanner) throws CompileException, IOException {
Parser parser = new Parser(scanner);
// Eat optional leading import declarations.
while (parser.peek("import")) parser.parseImportDeclaration();
// Parse the expression.
Rvalue rvalue = parser.parseExpression().toRvalueOrCompileException();
if (!parser.peekEof()) {
throw new CompileException("Unexpected token \"" + parser.peek() + "\"", scanner.location());
}
// Traverse the expression for ambiguous names and guess which of them are parameter names.
final Set<String> parameterNames = new HashSet();
rvalue.accept((RvalueVisitor) new Traverser() {
@Override public void
traverseAmbiguousName(AmbiguousName an) {
// If any of the components starts with an upper-case letter, then the ambiguous
// name is most probably a type name, e.g. "System.out" or "java.lang.System.out".
for (String identifier : an.identifiers) {
if (Character.isUpperCase(identifier.charAt(0))) return;
}
// It's most probably a parameter name (although it could be a field name as well).
parameterNames.add(an.identifiers[0]);
}
}.comprehensiveVisitor());
return (String[]) parameterNames.toArray(new String[parameterNames.size()]);
}
}

View File

@ -0,0 +1,56 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.Location;
import org.codehaus.commons.compiler.WarningHandler;
import org.codehaus.janino.util.StringPattern;
/** Invokes a delegate iff the handle of the warning matches one or more of a set of {@link StringPattern}s. */
public
class FilterWarningHandler implements WarningHandler {
private final StringPattern[] handlePatterns;
private final WarningHandler delegate;
/**
* Popular values for the <code>handlePatterns</code> parameter are
* {@link StringPattern#PATTERNS_ALL} and {@link StringPattern#PATTERNS_NONE}.
*/
public
FilterWarningHandler(StringPattern[] handlePatterns, WarningHandler delegate) {
this.handlePatterns = handlePatterns;
this.delegate = delegate;
}
@Override public void
handleWarning(String handle, String message, Location optionalLocation) throws CompileException {
if (StringPattern.matches(this.handlePatterns, handle)) {
this.delegate.handleWarning(handle, message, optionalLocation);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,384 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.codehaus.janino.IClass.IConstructor;
import org.codehaus.janino.IClass.IMethod;
import org.codehaus.janino.util.resource.JarDirectoriesResourceFinder;
import org.codehaus.janino.util.resource.PathResourceFinder;
import org.codehaus.janino.util.resource.ResourceFinder;
/** Loads an {@link IClass} by type name. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public abstract
class IClassLoader {
private static final boolean DEBUG = false;
// The following are constants, but cannot be declared FINAL, because they are only initialized by
// "postConstruct()".
// CHECKSTYLE MemberName:OFF
// CHECKSTYLE AbbreviationAsWordInName:OFF
/** Representation of the {@link java.lang.Override} annotation. */
public IClass ANNO_java_lang_Override;
/** Representation of the {@link java.lang.AssertionError} type. */
public IClass TYPE_java_lang_AssertionError;
/** Representation of the {@link java.lang.Boolean} type. */
public IClass TYPE_java_lang_Boolean;
/** Representation of the {@link java.lang.Byte} type. */
public IClass TYPE_java_lang_Byte;
/** Representation of the {@link java.lang.Character} type. */
public IClass TYPE_java_lang_Character;
/** Representation of the {@link java.lang.Class} type. */
public IClass TYPE_java_lang_Class;
/** Representation of the {@link java.lang.Cloneable} type. */
public IClass TYPE_java_lang_Cloneable;
/** Representation of the {@link java.lang.Double} type. */
public IClass TYPE_java_lang_Double;
/** Representation of the {@link java.lang.Exception} type. */
public IClass TYPE_java_lang_Exception;
/** Representation of the {@link java.lang.Error} type. */
public IClass TYPE_java_lang_Error;
/** Representation of the {@link java.lang.Float} type. */
public IClass TYPE_java_lang_Float;
/** Representation of the {@link java.lang.Integer} type. */
public IClass TYPE_java_lang_Integer;
/** Representation of the {@link java.lang.Iterable} type. */
public IClass TYPE_java_lang_Iterable;
/** Representation of the {@link java.lang.Long} type. */
public IClass TYPE_java_lang_Long;
/** Representation of the {@link java.lang.Object} type. */
public IClass TYPE_java_lang_Object;
/** Representation of the {@link java.lang.RuntimeException} type. */
public IClass TYPE_java_lang_RuntimeException;
/** Representation of the {@link java.lang.Short} type. */
public IClass TYPE_java_lang_Short;
/** Representation of the {@link java.lang.String} type. */
public IClass TYPE_java_lang_String;
/** Representation of the {@link java.lang.StringBuilder} type. */
public IClass TYPE_java_lang_StringBuilder;
/** Representation of the {@link java.lang.Throwable} type. */
public IClass TYPE_java_lang_Throwable;
/** Representation of the {@link java.io.Serializable} type. */
public IClass TYPE_java_io_Serializable;
/** Representation of the {@link java.util.Iterator} type. */
public IClass TYPE_java_util_Iterator;
/** Representation of the {@link Iterable#iterator()} method. */
public IMethod METH_java_lang_Iterable__iterator;
/** Representation of the {@link String#concat(String)} method. */
public IMethod METH_java_lang_String__concat__java_lang_String;
/** Representation of the {@link String#valueOf(int)} method. */
public IMethod METH_java_lang_String__valueOf__int;
/** Representation of the {@link String#valueOf(long)} method. */
public IMethod METH_java_lang_String__valueOf__long;
/** Representation of the {@link String#valueOf(float)} method. */
public IMethod METH_java_lang_String__valueOf__float;
/** Representation of the {@link String#valueOf(double)} method. */
public IMethod METH_java_lang_String__valueOf__double;
/** Representation of the {@link String#valueOf(char)} method. */
public IMethod METH_java_lang_String__valueOf__char;
/** Representation of the {@link String#valueOf(boolean)} method. */
public IMethod METH_java_lang_String__valueOf__boolean;
/** Representation of the {@link String#valueOf(Object)} method. */
public IMethod METH_java_lang_String__valueOf__java_lang_Object;
/** Representation of the {@link StringBuilder#append(String)} method. */
public IMethod METH_java_lang_StringBuilder__append__java_lang_String;
/** Representation of the {@link StringBuilder#toString()} method. */
public IMethod METH_java_lang_StringBuilder__toString;
/** Representation of the {@link java.util.Iterator#hasNext()} method. */
public IMethod METH_java_util_Iterator__hasNext;
/** Representation of the {@link java.util.Iterator#next()} method. */
public IMethod METH_java_util_Iterator__next;
/** Representation of the {@link StringBuilder#StringBuilder(String)} constructor. */
public IConstructor CTOR_java_lang_StringBuilder__java_lang_String;
// CHECKSTYLE AbbreviationAsWordInName:ON
// CHECKSTYLE MemberName:ON
public
IClassLoader(IClassLoader optionalParentIClassLoader) {
this.optionalParentIClassLoader = optionalParentIClassLoader;
}
/**
* This method must be called by the constructor of the directly derived
* class. (The reason being is that this method invokes abstract
* {@link #loadIClass(String)} which will not work until the implementing
* class is constructed.)
*/
protected final void
postConstruct() {
try {
this.ANNO_java_lang_Override = this.loadIClass(Descriptor.JAVA_LANG_OVERRIDE);
this.TYPE_java_lang_AssertionError = this.loadIClass(Descriptor.JAVA_LANG_ASSERTIONERROR);
this.TYPE_java_lang_Boolean = this.loadIClass(Descriptor.JAVA_LANG_BOOLEAN);
this.TYPE_java_lang_Byte = this.loadIClass(Descriptor.JAVA_LANG_BYTE);
this.TYPE_java_lang_Character = this.loadIClass(Descriptor.JAVA_LANG_CHARACTER);
this.TYPE_java_lang_Class = this.loadIClass(Descriptor.JAVA_LANG_CLASS);
this.TYPE_java_lang_Cloneable = this.loadIClass(Descriptor.JAVA_LANG_CLONEABLE);
this.TYPE_java_lang_Double = this.loadIClass(Descriptor.JAVA_LANG_DOUBLE);
this.TYPE_java_lang_Exception = this.loadIClass(Descriptor.JAVA_LANG_EXCEPTION);
this.TYPE_java_lang_Error = this.loadIClass(Descriptor.JAVA_LANG_ERROR);
this.TYPE_java_lang_Float = this.loadIClass(Descriptor.JAVA_LANG_FLOAT);
this.TYPE_java_lang_Integer = this.loadIClass(Descriptor.JAVA_LANG_INTEGER);
this.TYPE_java_lang_Iterable = this.loadIClass(Descriptor.JAVA_LANG_ITERABLE);
this.TYPE_java_lang_Long = this.loadIClass(Descriptor.JAVA_LANG_LONG);
this.TYPE_java_lang_Object = this.loadIClass(Descriptor.JAVA_LANG_OBJECT);
this.TYPE_java_lang_RuntimeException = this.loadIClass(Descriptor.JAVA_LANG_RUNTIMEEXCEPTION);
this.TYPE_java_lang_Short = this.loadIClass(Descriptor.JAVA_LANG_SHORT);
this.TYPE_java_lang_String = this.loadIClass(Descriptor.JAVA_LANG_STRING);
this.TYPE_java_lang_StringBuilder = this.loadIClass(Descriptor.JAVA_LANG_STRINGBUILDER);
this.TYPE_java_lang_Throwable = this.loadIClass(Descriptor.JAVA_LANG_THROWABLE);
this.TYPE_java_io_Serializable = this.loadIClass(Descriptor.JAVA_IO_SERIALIZABLE);
this.TYPE_java_util_Iterator = this.loadIClass(Descriptor.JAVA_UTIL_ITERATOR);
// CHECKSTYLE LineLength:OFF
// CHECKSTYLE Whitespace:OFF
this.METH_java_lang_Iterable__iterator = this.TYPE_java_lang_Iterable .findIMethod("iterator", new IClass[0]);
this.METH_java_lang_String__concat__java_lang_String = this.TYPE_java_lang_String .findIMethod("concat", new IClass[] { this.TYPE_java_lang_String });
this.METH_java_lang_String__valueOf__int = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.INT });
this.METH_java_lang_String__valueOf__long = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.LONG });
this.METH_java_lang_String__valueOf__float = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.FLOAT });
this.METH_java_lang_String__valueOf__double = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.DOUBLE });
this.METH_java_lang_String__valueOf__char = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.CHAR });
this.METH_java_lang_String__valueOf__boolean = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.BOOLEAN });
this.METH_java_lang_String__valueOf__java_lang_Object = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { this.TYPE_java_lang_Object });
this.METH_java_lang_StringBuilder__append__java_lang_String = this.TYPE_java_lang_StringBuilder.findIMethod("append", new IClass[] { this.TYPE_java_lang_String });
this.METH_java_lang_StringBuilder__toString = this.TYPE_java_lang_StringBuilder.findIMethod("toString", new IClass[0]);
this.METH_java_util_Iterator__hasNext = this.TYPE_java_util_Iterator .findIMethod("hasNext", new IClass[0]);
this.METH_java_util_Iterator__next = this.TYPE_java_util_Iterator .findIMethod("next", new IClass[0]);
this.CTOR_java_lang_StringBuilder__java_lang_String = this.TYPE_java_lang_StringBuilder.findIConstructor(new IClass[] { this.TYPE_java_lang_String });
// CHECKSTYLE Whitespace:ON
// CHECKSTYLE LineLength:ON
} catch (Exception e) {
throw new JaninoRuntimeException("Cannot load simple types", e);
}
}
/**
* Get an {@link IClass} by field descriptor.
*
* @param fieldDescriptor E.g. 'Lpkg1/pkg2/Outer$Inner;'
* @return {@code null} if an {@link IClass} could not be loaded
* @throws ClassNotFoundException An exception was raised while loading the {@link IClass}
*/
public final IClass
loadIClass(String fieldDescriptor) throws ClassNotFoundException {
if (IClassLoader.DEBUG) System.out.println(this + ": Load type \"" + fieldDescriptor + "\"");
if (Descriptor.isPrimitive(fieldDescriptor)) {
return (
fieldDescriptor.equals(Descriptor.VOID) ? IClass.VOID :
fieldDescriptor.equals(Descriptor.BYTE) ? IClass.BYTE :
fieldDescriptor.equals(Descriptor.CHAR) ? IClass.CHAR :
fieldDescriptor.equals(Descriptor.DOUBLE) ? IClass.DOUBLE :
fieldDescriptor.equals(Descriptor.FLOAT) ? IClass.FLOAT :
fieldDescriptor.equals(Descriptor.INT) ? IClass.INT :
fieldDescriptor.equals(Descriptor.LONG) ? IClass.LONG :
fieldDescriptor.equals(Descriptor.SHORT) ? IClass.SHORT :
fieldDescriptor.equals(Descriptor.BOOLEAN) ? IClass.BOOLEAN :
null
);
}
// Ask parent IClassLoader first.
if (this.optionalParentIClassLoader != null) {
IClass res = this.optionalParentIClassLoader.loadIClass(fieldDescriptor);
if (res != null) return res;
}
// We need to synchronize here because "unloadableIClasses" and
// "loadedIClasses" are unsynchronized containers.
IClass result;
synchronized (this) {
// Class could not be loaded before?
if (this.unloadableIClasses.contains(fieldDescriptor)) return null;
// Class already loaded?
result = (IClass) this.loadedIClasses.get(fieldDescriptor);
if (result != null) return result;
// Special handling for array types.
if (Descriptor.isArrayReference(fieldDescriptor)) {
// Load the component type.
IClass componentIClass = this.loadIClass(
Descriptor.getComponentDescriptor(fieldDescriptor)
);
if (componentIClass == null) return null;
// Now get and define the array type.
IClass arrayIClass = componentIClass.getArrayIClass(this.TYPE_java_lang_Object);
this.loadedIClasses.put(fieldDescriptor, arrayIClass);
return arrayIClass;
}
if (IClassLoader.DEBUG) System.out.println("call IClassLoader.findIClass(\"" + fieldDescriptor + "\")");
// Load the class through the {@link #findIClass(String)} method implemented by the
// derived class.
result = this.findIClass(fieldDescriptor);
if (result == null) {
this.unloadableIClasses.add(fieldDescriptor);
return null;
}
}
if (!result.getDescriptor().equalsIgnoreCase(fieldDescriptor)) {
throw new JaninoRuntimeException(
"\"findIClass()\" returned \""
+ result.getDescriptor()
+ "\" instead of \""
+ fieldDescriptor
+ "\""
);
}
if (IClassLoader.DEBUG) System.out.println(this + ": Loaded type \"" + fieldDescriptor + "\" as " + result);
return result;
}
/**
* Find a new {@link IClass} by descriptor; return <code>null</code> if a class
* for that <code>descriptor</code> could not be found.
* <p>
* Similar {@link java.lang.ClassLoader#findClass(java.lang.String)}, this method
* must
* <ul>
* <li>Get an {@link IClass} object from somewhere for the given type
* <li>Call {@link #defineIClass(IClass)} with that {@link IClass} object as
* the argument
* <li>Return the {@link IClass} object
* </ul>
* <p>
* The format of a <code>descriptor</code> is defined in JVMS 4.3.2. Typical
* descriptors are:
* <ul>
* <li><code>I</code> (Integer)
* <li><code>Lpkg1/pkg2/Cls;</code> (Class declared in package)
* <li><code>Lpkg1/pkg2/Outer$Inner;</code> Member class
* </ul>
* Notice that this method is never called for array types.
* <p>
* Notice that this method is never called from more than one thread at a time.
* In other words, implementations of this method need not be synchronized.
*
* @return <code>null</code> if a class with that descriptor could not be found
* @throws ClassNotFoundException if an exception was raised while loading the class
*/
protected abstract IClass findIClass(String descriptor) throws ClassNotFoundException;
/**
* Define an {@link IClass} in the context of this {@link IClassLoader}.
* If an {@link IClass} with that descriptor already exists, a
* {@link RuntimeException} is thrown.
* <p>
* This method should only be called from an implementation of
* {@link #findIClass(String)}.
*
* @throws RuntimeException A different {@link IClass} object is already defined for this type
*/
protected final void
defineIClass(IClass iClass) {
String descriptor = iClass.getDescriptor();
// Already defined?
IClass loadedIClass = (IClass) this.loadedIClasses.get(descriptor);
if (loadedIClass != null) {
if (loadedIClass == iClass) return;
throw new JaninoRuntimeException("Non-identical definition of IClass \"" + descriptor + "\"");
}
// Define.
this.loadedIClasses.put(descriptor, iClass);
if (IClassLoader.DEBUG) System.out.println(this + ": Defined type \"" + descriptor + "\"");
}
/**
* Create an {@link IClassLoader} that looks for classes in the given "boot class
* path", then in the given "extension directories", and then in the given
* "class path".
* <p>
* The default for the <code>optionalBootClassPath</code> is the path defined in
* the system property "sun.boot.class.path", and the default for the
* <code>optionalExtensionDirs</code> is the path defined in the "java.ext.dirs"
* system property.
*/
public static IClassLoader
createJavacLikePathIClassLoader(
final File[] optionalBootClassPath,
final File[] optionalExtDirs,
final File[] classPath
) {
ResourceFinder bootClassPathResourceFinder = new PathResourceFinder(
optionalBootClassPath == null
? PathResourceFinder.parsePath(System.getProperty("sun.boot.class.path"))
: optionalBootClassPath
);
ResourceFinder extensionDirectoriesResourceFinder = new JarDirectoriesResourceFinder(
optionalExtDirs == null
? PathResourceFinder.parsePath(System.getProperty("java.ext.dirs"))
: optionalExtDirs
);
final ResourceFinder classPathResourceFinder = new PathResourceFinder(classPath);
// We can load classes through "ResourceFinderIClassLoader"s, which means
// they are read into "ClassFile" objects, or we can load classes through
// "ClassLoaderIClassLoader"s, which means they are loaded into the JVM.
//
// In my environment, the latter is slightly faster. No figures about
// resource usage yet.
//
// In applications where the generated classes are not loaded into the
// same JVM instance, we should avoid to use the
// ClassLoaderIClassLoader, because that assumes that final fields have
// a constant value, even if not compile-time-constant but only
// initialization-time constant. The classical example is
// "File.separator", which is non-blank final, but not compile-time-
// constant.
IClassLoader icl;
icl = new ResourceFinderIClassLoader(bootClassPathResourceFinder, null);
icl = new ResourceFinderIClassLoader(extensionDirectoriesResourceFinder, icl);
icl = new ResourceFinderIClassLoader(classPathResourceFinder, icl);
return icl;
}
private final IClassLoader optionalParentIClassLoader;
private final Map<String /*descriptor*/, IClass> loadedIClasses = new HashMap();
private final Set<String /*descriptor*/> unloadableIClasses = new HashSet();
}

View File

@ -0,0 +1,40 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
/**
* All Janino components that throw {@link RuntimeException} throw this subclass
* to allow for client libraries to intercept them more easily.
*/
public
class JaninoRuntimeException extends RuntimeException {
private static final long serialVersionUID = 7155453370536273589L;
public JaninoRuntimeException() {}
public JaninoRuntimeException(String message) { super(message); }
public JaninoRuntimeException(String message, Throwable t) { super(message, t); }
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,256 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.File;
import java.io.Reader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.codehaus.commons.compiler.AbstractJavaSourceClassLoader;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.ErrorHandler;
import org.codehaus.commons.compiler.ICookable;
import org.codehaus.commons.compiler.WarningHandler;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.resource.DirectoryResourceFinder;
import org.codehaus.janino.util.resource.PathResourceFinder;
import org.codehaus.janino.util.resource.ResourceFinder;
/**
* A {@link ClassLoader} that, unlike usual {@link ClassLoader}s,
* does not load byte code, but reads Java&trade; source code and then scans, parses,
* compiles and loads it into the virtual machine.
* <p>
* As with any {@link ClassLoader}, it is not possible to "update" classes after they've been
* loaded. The way to achieve this is to give up on the {@link JavaSourceClassLoader} and create
* a new one.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class JavaSourceClassLoader extends AbstractJavaSourceClassLoader {
public
JavaSourceClassLoader() { this(ClassLoader.getSystemClassLoader()); }
public
JavaSourceClassLoader(ClassLoader parentClassLoader) {
this(
parentClassLoader,
(File[]) null, // optionalSourcePath
null // optionalCharacterEncoding
);
}
/**
* Set up a {@link JavaSourceClassLoader} that finds Java&trade; source code in a file that resides in either of
* the directories specified by the given source path.
*
* @param parentClassLoader See {@link ClassLoader}
* @param optionalSourcePath A collection of directories that are searched for Java&trade; source files in
* the given order
* @param optionalCharacterEncoding The encoding of the Java&trade; source files (<code>null</code> for platform
* default encoding)
*/
public
JavaSourceClassLoader(
ClassLoader parentClassLoader,
File[] optionalSourcePath,
String optionalCharacterEncoding
) {
this(
parentClassLoader, // parentClassLoader
( // sourceFinder
optionalSourcePath == null
? (ResourceFinder) new DirectoryResourceFinder(new File("."))
: (ResourceFinder) new PathResourceFinder(optionalSourcePath)
),
optionalCharacterEncoding // optionalCharacterEncoding
);
}
/**
* Constructs a {@link JavaSourceClassLoader} that finds Java&trade; source code through a given {@link
* ResourceFinder}.
* <p>
* You can specify to include certain debugging information in the generated class files, which
* is useful if you want to debug through the generated classes (see
* {@link Scanner#Scanner(String, Reader)}).
*
* @param parentClassLoader See {@link ClassLoader}
* @param sourceFinder Used to locate additional source files
* @param optionalCharacterEncoding The encoding of the Java&trade; source files (<code>null</code> for platform
* default encoding)
*/
public
JavaSourceClassLoader(
ClassLoader parentClassLoader,
ResourceFinder sourceFinder,
String optionalCharacterEncoding
) {
this(parentClassLoader, new JavaSourceIClassLoader(
sourceFinder, // sourceFinder
optionalCharacterEncoding, // optionalCharacterEncoding
new ClassLoaderIClassLoader(parentClassLoader) // optionalParentIClassLoader
));
}
/**
* Constructs a {@link JavaSourceClassLoader} that finds classes through an {@link JavaSourceIClassLoader}.
*/
public
JavaSourceClassLoader(ClassLoader parentClassLoader, JavaSourceIClassLoader iClassLoader) {
super(parentClassLoader);
this.iClassLoader = iClassLoader;
}
@Override public void
setSourcePath(File[] sourcePath) {
this.iClassLoader.setSourceFinder(new PathResourceFinder(sourcePath));
}
@Override public void
setSourceFileCharacterEncoding(String optionalCharacterEncoding) {
this.iClassLoader.setCharacterEncoding(optionalCharacterEncoding);
}
@Override public void
setDebuggingInfo(boolean debugSource, boolean debugLines, boolean debugVars) {
this.debugSource = debugSource;
this.debugLines = debugLines;
this.debugVars = debugVars;
}
/** @see UnitCompiler#setCompileErrorHandler */
public void
setCompileErrorHandler(ErrorHandler optionalCompileErrorHandler) {
this.iClassLoader.setCompileErrorHandler(optionalCompileErrorHandler);
}
/**
* @see Parser#setWarningHandler(WarningHandler)
* @see UnitCompiler#setCompileErrorHandler
*/
public void
setWarningHandler(WarningHandler optionalWarningHandler) {
this.iClassLoader.setWarningHandler(optionalWarningHandler);
}
/**
* Implementation of {@link ClassLoader#findClass(String)}.
*
* @throws ClassNotFoundException
*/
@Override protected /*synchronized <- No need to synchronize, because 'loadClass()' is synchronized */ Class
findClass(String name) throws ClassNotFoundException {
// Check if the bytecode for that class was generated already.
byte[] bytecode = (byte[]) this.precompiledClasses.remove(name);
if (bytecode == null) {
// Read, scan, parse and compile the right compilation unit.
{
Map<String /*name*/, byte[] /*bytecode*/> bytecodes = this.generateBytecodes(name);
if (bytecodes == null) throw new ClassNotFoundException(name);
this.precompiledClasses.putAll(bytecodes);
}
// Now the bytecode for our class should be available.
bytecode = (byte[]) this.precompiledClasses.remove(name);
if (bytecode == null) {
throw new JaninoRuntimeException(
"SNO: Scanning, parsing and compiling class \""
+ name
+ "\" did not create a class file!?"
);
}
}
return this.defineBytecode(name, bytecode);
}
/**
* This {@link Map} keeps those classes which were already compiled, but not
* yet defined i.e. which were not yet passed to
* {@link ClassLoader#defineClass(java.lang.String, byte[], int, int)}.
*/
private final Map<String /*name*/, byte[] /*bytecode*/> precompiledClasses = new HashMap();
/**
* Find, scan, parse the right compilation unit. Compile the parsed compilation unit to
* bytecode. This may cause more compilation units being scanned and parsed. Continue until
* all compilation units are compiled.
*
* @return String name => byte[] bytecode, or <code>null</code> if no source code could be found
* @throws ClassNotFoundException on compilation problems
*/
protected Map<String /*name*/, byte[] /*bytecode*/>
generateBytecodes(String name) throws ClassNotFoundException {
if (this.iClassLoader.loadIClass(Descriptor.fromClassName(name)) == null) return null;
Map<String /*name*/, byte[] /*bytecode*/> bytecodes = new HashMap();
Set<UnitCompiler> compiledUnitCompilers = new HashSet();
COMPILE_UNITS:
for (;;) {
for (UnitCompiler uc : this.iClassLoader.getUnitCompilers()) {
if (!compiledUnitCompilers.contains(uc)) {
ClassFile[] cfs;
try {
cfs = uc.compileUnit(this.debugSource, this.debugLines, this.debugVars);
} catch (CompileException ex) {
throw new ClassNotFoundException(ex.getMessage(), ex);
}
for (ClassFile cf : cfs) bytecodes.put(cf.getThisClassName(), cf.toByteArray());
compiledUnitCompilers.add(uc);
continue COMPILE_UNITS;
}
}
return bytecodes;
}
}
/**
* @throws ClassFormatError
* @see #setProtectionDomainFactory
*/
private Class
defineBytecode(String className, byte[] ba) {
return this.defineClass(className, ba, 0, ba.length, (
this.optionalProtectionDomainFactory == null
? null
: this.optionalProtectionDomainFactory.getProtectionDomain(ClassFile.getSourceResourceName(className))
));
}
private final JavaSourceIClassLoader iClassLoader;
private boolean debugSource = Boolean.getBoolean(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_ENABLE);
private boolean debugLines = this.debugSource;
private boolean debugVars = this.debugSource;
}

View File

@ -0,0 +1,208 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.ErrorHandler;
import org.codehaus.commons.compiler.Location;
import org.codehaus.commons.compiler.WarningHandler;
import org.codehaus.janino.Java.CompilationUnit;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.resource.Resource;
import org.codehaus.janino.util.resource.ResourceFinder;
/**
* This {@link org.codehaus.janino.IClassLoader} finds, scans and parses compilation units.
* <p>
* Notice that it does not compile them!
*/
public
class JavaSourceIClassLoader extends IClassLoader {
private static final boolean DEBUG = false;
private ResourceFinder sourceFinder;
private String optionalCharacterEncoding;
/** Collection of parsed compilation units. */
private final Set<UnitCompiler> unitCompilers = new HashSet<UnitCompiler>();
private ErrorHandler optionalCompileErrorHandler;
private WarningHandler optionalWarningHandler;
public
JavaSourceIClassLoader(
ResourceFinder sourceFinder,
String optionalCharacterEncoding,
IClassLoader optionalParentIClassLoader
) {
super(optionalParentIClassLoader);
this.sourceFinder = sourceFinder;
this.optionalCharacterEncoding = optionalCharacterEncoding;
super.postConstruct();
}
/**
* Returns the set of {@link UnitCompiler}s that were created so far.
*/
public Set<UnitCompiler>
getUnitCompilers() { return this.unitCompilers; }
/** @param pathResourceFinder The source path */
public void
setSourceFinder(ResourceFinder pathResourceFinder) {
this.sourceFinder = pathResourceFinder;
}
/**
* @param optionalCharacterEncoding The name of the charset that is used to read source files, or {@code null} to
* use the platform's 'default charset'
*/
public void
setCharacterEncoding(String optionalCharacterEncoding) {
this.optionalCharacterEncoding = optionalCharacterEncoding;
}
/** @see UnitCompiler#setCompileErrorHandler(ErrorHandler) */
public void
setCompileErrorHandler(ErrorHandler optionalCompileErrorHandler) {
this.optionalCompileErrorHandler = optionalCompileErrorHandler;
}
/**
* @see Parser#setWarningHandler(WarningHandler)
* @see UnitCompiler#setCompileErrorHandler(ErrorHandler)
*/
public void
setWarningHandler(WarningHandler optionalWarningHandler) {
this.optionalWarningHandler = optionalWarningHandler;
}
/**
* @param fieldDescriptor Field descriptor of the {@link IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;"
* @throws ClassNotFoundException An exception was raised while loading the {@link IClass}
*/
@Override public IClass
findIClass(final String fieldDescriptor) throws ClassNotFoundException {
if (JavaSourceIClassLoader.DEBUG) System.out.println("type = " + fieldDescriptor);
// Class type.
String className = Descriptor.toClassName(fieldDescriptor); // E.g. "pkg1.pkg2.Outer$Inner"
if (JavaSourceIClassLoader.DEBUG) System.out.println("2 className = \"" + className + "\"");
// Do not attempt to load classes from package "java".
if (className.startsWith("java.")) return null;
// Determine the name of the top-level class.
String topLevelClassName;
{
int idx = className.indexOf('$');
topLevelClassName = idx == -1 ? className : className.substring(0, idx);
}
// Check the already-parsed compilation units.
for (UnitCompiler uc : this.unitCompilers) {
IClass res = uc.findClass(topLevelClassName);
if (res != null) {
if (!className.equals(topLevelClassName)) {
res = uc.findClass(className);
if (res == null) return null;
}
this.defineIClass(res);
return res;
}
}
try {
Java.CompilationUnit cu = this.findCompilationUnit(className);
if (cu == null) return null;
UnitCompiler uc = new UnitCompiler(cu, this);
uc.setCompileErrorHandler(this.optionalCompileErrorHandler);
uc.setWarningHandler(this.optionalWarningHandler);
// Remember compilation unit for later compilation.
this.unitCompilers.add(uc);
// Find the class/interface declaration in the compiled unit.
IClass res = uc.findClass(className);
if (res == null) {
if (className.equals(topLevelClassName)) {
throw new CompileException(
"Compilation unit '" + className + "' does not declare a class with the same name",
(Location) null
);
}
return null;
}
this.defineIClass(res);
return res;
} catch (IOException e) {
throw new ClassNotFoundException("Parsing compilation unit '" + className + "'", e);
} catch (CompileException e) {
throw new ClassNotFoundException("Parsing compilation unit '" + className + "'", e);
}
}
/**
* Finds the Java&trade; source file for the named class through the configured 'source resource finder' and
* parses it.
*
* @return {@code null} iff the source file could not be found
*/
protected CompilationUnit
findCompilationUnit(String className) throws IOException, CompileException {
// Find source file.
Resource sourceResource = this.sourceFinder.findResource(ClassFile.getSourceResourceName(className));
if (sourceResource == null) return null;
if (JavaSourceIClassLoader.DEBUG) System.out.println("sourceResource=" + sourceResource);
// Scan and parse the source file.
InputStream inputStream = sourceResource.open();
try {
Scanner scanner = new Scanner(
sourceResource.getFileName(),
inputStream,
this.optionalCharacterEncoding
);
scanner.setWarningHandler(this.optionalWarningHandler);
Parser parser = new Parser(scanner);
parser.setWarningHandler(this.optionalWarningHandler);
return parser.parseCompilationUnit();
} finally {
try { inputStream.close(); } catch (IOException ex) {}
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.util.ArrayList;
import java.util.List;
/** Representation of a "method descriptor" (JVMS 4.3.3). */
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class MethodDescriptor {
/** The field descriptors of the method parameters. */
public final String[] parameterFds;
/** The field descriptor of the method return value. */
public final String returnFd;
/** */
public
MethodDescriptor(String[] parameterFds, String returnFd) {
this.parameterFds = parameterFds;
this.returnFd = returnFd;
}
/** Parse a method descriptor into parameter FDs and return FDs. */
public
MethodDescriptor(String s) {
if (s.charAt(0) != '(') throw new JaninoRuntimeException();
int from = 1;
List<String> parameterFDs = new ArrayList();
while (s.charAt(from) != ')') {
int to = from;
while (s.charAt(to) == '[') ++to;
if ("BCDFIJSZ".indexOf(s.charAt(to)) != -1) {
++to;
} else
if (s.charAt(to) == 'L') {
for (++to; s.charAt(to) != ';'; ++to);
++to;
} else {
throw new JaninoRuntimeException();
}
parameterFDs.add(s.substring(from, to));
from = to;
}
this.parameterFds = (String[]) parameterFDs.toArray(new String[parameterFDs.size()]);
this.returnFd = s.substring(++from);
}
/** @return The "method descriptor" (JVMS 4.3.3) */
@Override public String
toString() {
StringBuilder sb = new StringBuilder("(");
for (String parameterFd : this.parameterFds) sb.append(parameterFd);
return sb.append(')').append(this.returnFd).toString();
}
/** Patches an additional parameter into a given method descriptor. */
public static String
prependParameter(String md, String parameterFd) { return '(' + parameterFd + md.substring(1); }
}

View File

@ -0,0 +1,270 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
/**
* This class defines constants and convenience methods for the handling of modifiers as defined by the JVM.
* <p>
* Notice: This class should be named <code>IClass.IModifier</code>, but changing the name would break existing client
* code. Thus it won't be renamed until there's a really good reason to do it (maybe with a major design change).
*/
public final
class Mod {
private Mod() {} // Don't instantiate me!
/** An alias for '0' -- <i>no</i> modifiers. */
public static final short NONE = 0x0000;
/**
* The flag indicating 'public accessibility' of the modified element. Methods of interfaces are always {@link
* #PUBLIC}.
*
* @see #PPP
* @see #isPublicAccess(short)
*/
public static final short PUBLIC = 0x0001;
/** @return Whether the given modifier symbolizes {@link #PUBLIC} accessibility */
public static boolean isPublicAccess(short sh) { return (sh & Mod.PPP) == Mod.PUBLIC; }
/**
* The flag indicating 'private accessibility' of the modified element.
*
* @see #PPP
* @see #isPrivateAccess(short)
*/
public static final short PRIVATE = 0x0002;
/** @return Whether the given modifier symbolizes {@link #PRIVATE} accessibility */
public static boolean isPrivateAccess(short sh) { return (sh & Mod.PPP) == Mod.PRIVATE; }
/**
* The flag indicating 'protected accessibility' of the modified element.
*
* @see #PPP
* @see #isProtectedAccess(short)
*/
public static final short PROTECTED = 0x0004;
/** @return Whether the given modifier symbolizes {@link #PROTECTED} accessibility */
public static boolean isProtectedAccess(short sh) { return (sh & Mod.PPP) == Mod.PROTECTED; }
/**
* The flag indicating 'default accessibility' a.k.a. 'package accessibility' of the modified element.
*
* @see #PPP
* @see #isPackageAccess(short)
*/
public static final short PACKAGE = 0x0000;
/** @return Whether the given modifier symbolizes {@link #PACKAGE} (a.k.a. 'default') accessibility */
public static boolean isPackageAccess(short sh) { return (sh & Mod.PPP) == Mod.PACKAGE; }
/** The mask to select the accessibility flags from modifiers. */
public static final short PPP = 0x0007;
/** @return The given {@code modifiers}, but with the accessibility part changed to {@code newAccess} */
public static short
changeAccess(short modifiers, short newAccess) { return (short) ((modifiers & ~Mod.PPP) | newAccess); }
/**
* This flag is set on class or interface initialization methods, STATIC class fields, all interface fields, STATIC
* methods, and STATIC nested classes.
*/
public static final short STATIC = 0x0008;
/** @return Whether the given modifier includes {@link #STATIC} */
public static boolean isStatic(short sh) { return (sh & Mod.STATIC) != 0; }
/**
* This flag is set on FINAL classes, FINAL fields and FINAL methods, and is mutually exclusive with {@link
* #VOLATILE} and {@link #ABSTRACT}.
*/
public static final short FINAL = 0x0010;
/** @return Whether the given modifier includes {@link #INTERFACE} */
public static boolean isFinal(short sh) { return (sh & Mod.FINAL) != 0; }
/**
* This flag is always set on classes, and never set on any other element. Notice that it has the same value as
* {@link #SYNCHRONIZED}, which is OK because {@link #SYNCHRONIZED} is for methods and {@link #SUPER} for classes.
*/
public static final short SUPER = 0x0020;
/** @return Whether the given modifier includes {@link #SUPER} */
public static boolean isSuper(short sh) { return (sh & Mod.SUPER) != 0; }
/**
* This flag is set on SYNCHRONIZED methods. Notice that it has the same value as {@link #SUPER}, which is OK
* because {@link #SYNCHRONIZED} is for methods and {@link #SUPER} for classes.
*/
public static final short SYNCHRONIZED = 0x0020;
/** @return Whether the given modifier includes {@link #SYNCHRONIZED} */
public static boolean isSynchronized(short sh) { return (sh & Mod.SYNCHRONIZED) != 0; }
/**
* This flag is set on VOLATILE fields and is mutually exclusive with {@link #FINAL}. Notice that it has the same
* value as {@link #BRIDGE}, which is OK because {@link #BRIDGE} is for methods and {@link #VOLATILE} for fields.
*/
public static final short VOLATILE = 0x0040;
/** @return Whether the given modifier includes {@link #VOLATILE} */
public static boolean isVolatile(short sh) { return (sh & Mod.VOLATILE) != 0; }
/**
* This flag is set on 'bridge methods' generated by the compiler. Notice that it has the same value as {@link
* #VOLATILE}, which is OK because {@link #BRIDGE} is for methods and {@link #VOLATILE} for fields.
*/
public static final short BRIDGE = 0x0040;
/** @return Whether the given modifier includes {@link #BRIDGE} */
public static boolean isBridge(short sh) { return (sh & Mod.BRIDGE) != 0; }
/**
* This flag is set on TRANSIENT fields. Notice that it has the same value as {@link #VARARGS}, which is OK because
* {@link #VARARGS} is for methods and {@link #TRANSIENT} for fields.
*/
public static final short TRANSIENT = 0x0080;
/** @return Whether the given modifier includes {@link #TRANSIENT} */
public static boolean isTransient(short sh) { return (sh & Mod.TRANSIENT) != 0; }
/**
* This flag is set on 'variable arity' (a.k.a. 'varargs') methods and constructors. Notice that it has the same
* value as {@link #TRANSIENT}, which is OK because {@link #VARARGS} is for methods and {@link #TRANSIENT} for
* fields.
*/
public static final short VARARGS = 0x0080;
/** @return Whether the given modifier includes {@link #VARARGS} */
public static boolean isVarargs(short sh) { return (sh & Mod.VARARGS) != 0; }
/** This flag is set on NATIVE methods, and is mutually exclusive with {@link #ABSTRACT}. */
public static final short NATIVE = 0x0100;
/** @return Whether the given modifier includes {@link #NATIVE} */
public static boolean isNative(short sh) { return (sh & Mod.NATIVE) != 0; }
/**
* This flag is set on interfaces (including nested interfaces), and requires that {@link #ABSTRACT} must also be
* set. {@link #INTERFACE} is mutually exclusive with {@link #FINAL}, {@link #SUPER} and {@link #ENUM}.
*/
public static final short INTERFACE = 0x0200;
/** @return Whether the given modifier includes {@link #INTERFACE} */
public static boolean isInterface(short sh) { return (sh & Mod.INTERFACE) != 0; }
/**
* This flag is set on all interfaces, ABSTRACT classes and ABSTRACT methods, and is mutually exclusive with
* {@link #FINAL}, {@link #NATIVE}, {@link #PRIVATE}, {@link #STATIC} and {@link #SYNCHRONIZED}.
*/
public static final short ABSTRACT = 0x0400;
/** @return Whether the given modifier includes {@link #ABSTRACT} */
public static boolean isAbstract(short sh) { return (sh & Mod.ABSTRACT) != 0; }
/** This flag is set on STRICTFP methods, and is mutually exclusive with {@link #ABSTRACT}. */
public static final short STRICTFP = 0x0800;
/** @return Whether the given modifier includes {@link #STRICTFP} */
public static boolean isStrictfp(short sh) { return (sh & Mod.STRICTFP) != 0; }
// Poorly documented JDK 1.5 modifiers:
/**
* This flag is set on classes, methods and fields that were generated by the compiler and do not appear in the
* source code.
*/
public static final short SYNTHETIC = 0x1000;
/** @return Whether the given modifier includes {@link #SYNTHETIC} */
public static boolean isSynthetic(short sh) { return (sh & Mod.SYNTHETIC) != 0; }
/**
* This flag is set on annotation types (including nested annotation types), and requires that {@link #INTERFACE}
* is also set.
*/
public static final short ANNOTATION = 0x2000;
/** @return Whether the given modifier includes {@link #ANNOTATION} */
public static boolean isAnnotation(short sh) { return (sh & Mod.ANNOTATION) != 0; }
/**
* This flag is set on enumerated types (including nested enumerated types) and enumerated types' elements, and is
* mutually exclusive with {@link #INTERFACE}.
*/
public static final short ENUM = 0x4000;
/** @return Whether the given modifier includes {@link #ENUM} */
public static boolean isEnum(short sh) { return (sh & Mod.ENUM) != 0; }
/**
* Composes and returns a string that maps the given modifier as follows:
* <ul>
* <li>Value zero is mapped to "".
* <li>Non-zero values are mapped to a sequence of words, separated with blanks.
* <li>{@link #VARARGS} is mapped to "transient", because the two flags have the same value
* <li>{@link #SUPER} is mapped to "synchronized", because the two flags have the same value
* <li>{@link #BRIDGE} is mapped to "volatile", because the two flags have the same value
* </ul>
*/
public static String
shortToString(short sh) {
if (sh == 0) return "";
StringBuilder res = new StringBuilder();
for (int i = 0; i < Mod.MAPPINGS.length; i += 2) {
if ((sh & ((Short) Mod.MAPPINGS[i + 1]).shortValue()) == 0) continue;
if (res.length() > 0) res.append(' ');
res.append((String) Mod.MAPPINGS[i]);
}
return res.toString();
}
private static final Object[] MAPPINGS = {
"public", new Short(Mod.PUBLIC),
"private", new Short(Mod.PRIVATE),
"protected", new Short(Mod.PROTECTED),
// "???", new Short(Mod.PACKAGE),
"static", new Short(Mod.STATIC),
"final", new Short(Mod.FINAL),
"synchronized", new Short(Mod.SYNCHRONIZED), // Has the same value as SUPER
// "super", new Short(Mod.SUPER), // Has the same value as SYNCHRONIZED
"volatile", new Short(Mod.VOLATILE), // Has the same value as BRIDGE
// "bridge", new Short(Mod.BRIDGE), // Has the same value as VOLATILE
"transient", new Short(Mod.TRANSIENT), // Has the same value as VARARGS
// "varargs", new Short(Mod.VARARGS), // Has the same value as TRANSIENT
"native", new Short(Mod.NATIVE),
"interface", new Short(Mod.INTERFACE),
"abstract", new Short(Mod.ABSTRACT),
"strictfp", new Short(Mod.STRICTFP),
"enum", new Short(Mod.ENUM),
"synthetic", new Short(Mod.SYNTHETIC),
"@", new Short(Mod.ANNOTATION),
};
}

View File

@ -0,0 +1,614 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
/** Definitions of Java bytecode opcodes. */
final
class Opcode {
private Opcode() {}
// Symbolic JVM opcodes, in alphabetical order.
// CHECKSTYLE JavadocVariable:OFF
public static final byte AALOAD = 50;
public static final byte AASTORE = 83;
public static final byte ACONST_NULL = 1;
public static final byte ALOAD = 25;
public static final byte ALOAD_0 = 42;
public static final byte ALOAD_1 = 43;
public static final byte ALOAD_2 = 44;
public static final byte ALOAD_3 = 45;
public static final byte ANEWARRAY = (byte) 189;
public static final byte ARETURN = (byte) 176;
public static final byte ARRAYLENGTH = (byte) 190;
public static final byte ASTORE = 58;
public static final byte ASTORE_0 = 75;
public static final byte ASTORE_1 = 76;
public static final byte ASTORE_2 = 77;
public static final byte ASTORE_3 = 78;
public static final byte ATHROW = (byte) 191;
public static final byte BALOAD = 51;
public static final byte BASTORE = 84;
public static final byte BIPUSH = 16;
public static final byte CALOAD = 52;
public static final byte CASTORE = 85;
public static final byte CHECKCAST = (byte) 192;
public static final byte D2F = (byte) 144;
public static final byte D2I = (byte) 142;
public static final byte D2L = (byte) 143;
public static final byte DADD = 99;
public static final byte DALOAD = 49;
public static final byte DASTORE = 82;
public static final byte DCMPG = (byte) 152;
public static final byte DCMPL = (byte) 151;
public static final byte DCONST_0 = 14;
public static final byte DCONST_1 = 15;
public static final byte DDIV = 111;
public static final byte DLOAD = 24;
public static final byte DLOAD_0 = 38;
public static final byte DLOAD_1 = 39;
public static final byte DLOAD_2 = 40;
public static final byte DLOAD_3 = 41;
public static final byte DMUL = 107;
public static final byte DNEG = 119;
public static final byte DREM = 115;
public static final byte DRETURN = (byte) 175;
public static final byte DSTORE = 57;
public static final byte DSTORE_0 = 71;
public static final byte DSTORE_1 = 72;
public static final byte DSTORE_2 = 73;
public static final byte DSTORE_3 = 74;
public static final byte DSUB = 103;
public static final byte DUP = 89;
public static final byte DUP_X1 = 90;
public static final byte DUP_X2 = 91;
public static final byte DUP2 = 92;
public static final byte DUP2_X1 = 93;
public static final byte DUP2_X2 = 94;
public static final byte F2D = (byte) 141;
public static final byte F2I = (byte) 139;
public static final byte F2L = (byte) 140;
public static final byte FADD = 98;
public static final byte FALOAD = 48;
public static final byte FASTORE = 81;
public static final byte FCMPG = (byte) 150;
public static final byte FCMPL = (byte) 149;
public static final byte FCONST_0 = 11;
public static final byte FCONST_1 = 12;
public static final byte FCONST_2 = 13;
public static final byte FDIV = 110;
public static final byte FLOAD = 23;
public static final byte FLOAD_0 = 34;
public static final byte FLOAD_1 = 35;
public static final byte FLOAD_2 = 36;
public static final byte FLOAD_3 = 37;
public static final byte FMUL = 106;
public static final byte FNEG = 118;
public static final byte FREM = 114;
public static final byte FRETURN = (byte) 174;
public static final byte FSTORE = 56;
public static final byte FSTORE_0 = 67;
public static final byte FSTORE_1 = 68;
public static final byte FSTORE_2 = 69;
public static final byte FSTORE_3 = 70;
public static final byte FSUB = 102;
public static final byte GETFIELD = (byte) 180;
public static final byte GETSTATIC = (byte) 178;
public static final byte GOTO = (byte) 167;
public static final byte GOTO_W = (byte) 200;
public static final byte I2B = (byte) 145;
public static final byte I2C = (byte) 146;
public static final byte I2D = (byte) 135;
public static final byte I2F = (byte) 134;
public static final byte I2L = (byte) 133;
public static final byte I2S = (byte) 147;
public static final byte IADD = 96;
public static final byte IALOAD = 46;
public static final byte IAND = 126;
public static final byte IASTORE = 79;
public static final byte ICONST_M1 = 2;
public static final byte ICONST_0 = 3;
public static final byte ICONST_1 = 4;
public static final byte ICONST_2 = 5;
public static final byte ICONST_3 = 6;
public static final byte ICONST_4 = 7;
public static final byte ICONST_5 = 8;
public static final byte IDIV = 108;
public static final byte IF_ACMPEQ = (byte) 165;
public static final byte IF_ACMPNE = (byte) 166;
public static final byte IF_ICMPEQ = (byte) 159;
public static final byte IF_ICMPNE = (byte) 160;
public static final byte IF_ICMPLT = (byte) 161;
public static final byte IF_ICMPGE = (byte) 162;
public static final byte IF_ICMPGT = (byte) 163;
public static final byte IF_ICMPLE = (byte) 164;
public static final byte IFEQ = (byte) 153;
public static final byte IFNE = (byte) 154;
public static final byte IFLT = (byte) 155;
public static final byte IFGE = (byte) 156;
public static final byte IFGT = (byte) 157;
public static final byte IFLE = (byte) 158;
public static final byte IFNONNULL = (byte) 199;
public static final byte IFNULL = (byte) 198;
public static final byte IINC = (byte) 132;
public static final byte ILOAD = 21;
public static final byte ILOAD_0 = 26;
public static final byte ILOAD_1 = 27;
public static final byte ILOAD_2 = 28;
public static final byte ILOAD_3 = 29;
public static final byte IMUL = 104;
public static final byte INEG = 116;
public static final byte INSTANCEOF = (byte) 193;
public static final byte INVOKEINTERFACE = (byte) 185;
public static final byte INVOKESPECIAL = (byte) 183;
public static final byte INVOKESTATIC = (byte) 184;
public static final byte INVOKEVIRTUAL = (byte) 182;
public static final byte IOR = (byte) 128;
public static final byte IREM = 112;
public static final byte IRETURN = (byte) 172;
public static final byte ISHL = 120;
public static final byte ISHR = 122;
public static final byte ISTORE = 54;
public static final byte ISTORE_0 = 59;
public static final byte ISTORE_1 = 60;
public static final byte ISTORE_2 = 61;
public static final byte ISTORE_3 = 62;
public static final byte ISUB = 100;
public static final byte IUSHR = 124;
public static final byte IXOR = (byte) 130;
public static final byte JSR = (byte) 168;
public static final byte JSR_W = (byte) 201;
public static final byte L2D = (byte) 138;
public static final byte L2F = (byte) 137;
public static final byte L2I = (byte) 136;
public static final byte LADD = 97;
public static final byte LALOAD = 47;
public static final byte LAND = 127;
public static final byte LASTORE = 80;
public static final byte LCMP = (byte) 148;
public static final byte LCONST_0 = 9;
public static final byte LCONST_1 = 10;
public static final byte LDC = 18;
public static final byte LDC_W = 19;
public static final byte LDC2_W = 20;
public static final byte LDIV = 109;
public static final byte LLOAD = 22;
public static final byte LLOAD_0 = 30;
public static final byte LLOAD_1 = 31;
public static final byte LLOAD_2 = 32;
public static final byte LLOAD_3 = 33;
public static final byte LMUL = 105;
public static final byte LNEG = 117;
public static final byte LOOKUPSWITCH = (byte) 171;
public static final byte LOR = (byte) 129;
public static final byte LREM = 113;
public static final byte LRETURN = (byte) 173;
public static final byte LSHL = 121;
public static final byte LSHR = 123;
public static final byte LSTORE = 55;
public static final byte LSTORE_0 = 63;
public static final byte LSTORE_1 = 64;
public static final byte LSTORE_2 = 65;
public static final byte LSTORE_3 = 66;
public static final byte LSUB = 101;
public static final byte LUSHR = 125;
public static final byte LXOR = (byte) 131;
public static final byte MONITORENTER = (byte) 194;
public static final byte MONITOREXIT = (byte) 195;
public static final byte MULTIANEWARRAY = (byte) 197;
public static final byte NEW = (byte) 187;
public static final byte NEWARRAY = (byte) 188;
public static final byte NOP = 0;
public static final byte POP = 87;
public static final byte POP2 = 88;
public static final byte PUTFIELD = (byte) 181;
public static final byte PUTSTATIC = (byte) 179;
public static final byte RET = (byte) 169;
public static final byte RETURN = (byte) 177;
public static final byte SALOAD = 53;
public static final byte SASTORE = 86;
public static final byte SIPUSH = 17;
public static final byte SWAP = 95;
public static final byte TABLESWITCH = (byte) 170;
public static final byte WIDE = (byte) 196;
// CHECKSTYLE JavadocVariable:ON
// Constants for the "OPCODE_PROPERTIES" array.
/** Special value for {@link #OPCODE_PROPERTIES} indicating that this element represents an invalid opcode. */
public static final short INVALID_OPCODE = -1;
/** Masks the 'stack delta' portion of {@link #OPCODE_PROPERTIES}. */
public static final short SD_MASK = 31;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
* size by 4 elements.
*/
public static final short SD_M4 = 0;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
* size by 3 elements.
*/
public static final short SD_M3 = 1;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
* size by 2 elements.
*/
public static final short SD_M2 = 2;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
* size by 1 element.
*/
public static final short SD_M1 = 3;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} results in the same operand
* stack size.
*/
public static final short SD_P0 = 4;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} increases the operand stack
* size by 1 element.
*/
public static final short SD_P1 = 5;
/**
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} increases the operand stack
* size by 2 elements.
*/
public static final short SD_P2 = 6;
/** Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} clears the operand stack. */
public static final short SD_0 = 7;
/** This element of {@link #OPCODE_PROPERTIES} represents the GETFIELD opcode. */
public static final short SD_GETFIELD = 9;
/** This element of {@link #OPCODE_PROPERTIES} represents the GETSTATIC opcode. */
public static final short SD_GETSTATIC = 10;
/** This element of {@link #OPCODE_PROPERTIES} represents the PUTFIELD opcode. */
public static final short SD_PUTFIELD = 11;
/** This element of {@link #OPCODE_PROPERTIES} represents the PUTSTATIC opcode. */
public static final short SD_PUTSTATIC = 12;
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKEVIRTUAL opcode. */
public static final short SD_INVOKEVIRTUAL = 13;
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKESPECIAL opcode. */
public static final short SD_INVOKESPECIAL = 14;
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKESTATIC opcode. */
public static final short SD_INVOKESTATIC = 15;
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKEINTERFACE opcode. */
public static final short SD_INVOKEINTERFACE = 16;
/** This element of {@link #OPCODE_PROPERTIES} represents the MULTIANEWARRAY opcode. */
public static final short SD_MULTIANEWARRAY = 18;
// Properties of the opcode's first operand.
/** Masks the 'first operand' portion of {@link #OPCODE_PROPERTIES}. */
public static final short OP1_MASK = 15 * 32;
/** The first operand of this opcode is a signed byte. */
public static final short OP1_SB = 1 * 32;
/** The first operand of this opcode is an unsigned byte. */
public static final short OP1_UB = 2 * 32;
/** The first operand of this opcode is a signed short. */
public static final short OP1_SS = 3 * 32;
/** The first operand of this opcode is a one-byte constant pool index. */
public static final short OP1_CP1 = 4 * 32;
/** The first operand of this opcode is a two-byte constant pool index. */
public static final short OP1_CP2 = 5 * 32;
/** The first operand of this opcode is a one-byte local variable array index. */
public static final short OP1_LV1 = 6 * 32;
/** The first operand of this opcode is a two-byte local variable array index. */
public static final short OP1_LV2 = 7 * 32;
/** The first operand of this opcode is a two-byte branch offset. */
public static final short OP1_BO2 = 8 * 32;
/** The first operand of this opcode is a four-byte branch offset. */
public static final short OP1_BO4 = 9 * 32;
/** The first operand of this opcode is a signed byte. */
public static final short OP1_LOOKUPSWITCH = 10 * 32;
/** The first operand of this opcode is a signed byte. */
public static final short OP1_TABLESWITCH = 11 * 32;
/** The first operand of this opcode is a signed byte. */
public static final short OP1_JSR = 12 * 32;
// Properties of the opcode's second operand.
/** Masks the 'second operand' portion of {@link #OPCODE_PROPERTIES}. */
public static final short OP2_MASK = 3 * 512;
/** The second operand of this opcode is a signed byte. */
public static final short OP2_SB = 1 * 512;
/** The second operand of this opcode is a signed short. */
public static final short OP2_SS = 2 * 512;
// Properties of the opcode's third operand.
/** Masks the 'third operand' portion of {@link #OPCODE_PROPERTIES}. */
public static final short OP3_MASK = 1 * 2048;
/** The third operand of this opcode is a signed byte. */
public static final short OP3_SB = 1 * 2048;
// Properties of the opcode's 'implicit' operand.
/** Masks the 'implicit operand' portion of {@link #OPCODE_PROPERTIES}. */
public static final short IO_MASK = 7 * 4096;
/** The local variable wiht index 0 is the opcode's implicit operand. */
public static final short IO_LV_0 = 1 * 4096;
/** The local variable wiht index 1 is the opcode's implicit operand. */
public static final short IO_LV_1 = 2 * 4096;
/** The local variable wiht index 2 is the opcode's implicit operand. */
public static final short IO_LV_2 = 3 * 4096;
/** The local variable wiht index 3 is the opcode's implicit operand. */
public static final short IO_LV_3 = 4 * 4096;
/**
* This opcode never 'completes normally', i.e. it never passes the control flow to the immediately following
* opcode.
*/
public static final short NO_FALLTHROUGH = (short) 32768;
/** The {@code n}th element of this array describes the properties of the JVM opcode {@code n}. */
public static final short[] OPCODE_PROPERTIES = {
// CHECKSTYLE WrapAndIndent:OFF
/* 0*/ /*NOP*/ Opcode.SD_P0,
/*ACONST_NULL*/ Opcode.SD_P1,
/*ICONST_M1*/ Opcode.SD_P1,
/*ICONST_0*/ Opcode.SD_P1,
/*ICONST_1*/ Opcode.SD_P1,
/*ICONST_2*/ Opcode.SD_P1,
/*ICONST_3*/ Opcode.SD_P1,
/*ICONST_4*/ Opcode.SD_P1,
/*ICONST_5*/ Opcode.SD_P1,
/*LCONST_0*/ Opcode.SD_P2,
/* 10*/ /*LCONST_1*/ Opcode.SD_P2,
/*FCONST_0*/ Opcode.SD_P1,
/*FCONST_1*/ Opcode.SD_P1,
/*FCONST_2*/ Opcode.SD_P1,
/*DCONST_0*/ Opcode.SD_P2,
/*DCONST_1*/ Opcode.SD_P2,
/*BIPUSH*/ Opcode.SD_P1 | Opcode.OP1_SB,
/*SIPUSH*/ Opcode.SD_P1 | Opcode.OP1_SS,
/*LDC*/ Opcode.SD_P1 | Opcode.OP1_CP1,
/*LDC_W*/ Opcode.SD_P1 | Opcode.OP1_CP2,
/* 20*/ /*LDC2_W*/ Opcode.SD_P2 | Opcode.OP1_CP2,
/*ILOAD*/ Opcode.SD_P1 | Opcode.OP1_LV1,
/*LLOAD*/ Opcode.SD_P2 | Opcode.OP1_LV1,
/*FLOAD*/ Opcode.SD_P1 | Opcode.OP1_LV1,
/*DLOAD*/ Opcode.SD_P2 | Opcode.OP1_LV1,
/*ALOAD*/ Opcode.SD_P1 | Opcode.OP1_LV1,
/*ILOAD_0*/ Opcode.SD_P1 | Opcode.IO_LV_0,
/*ILOAD_1*/ Opcode.SD_P1 | Opcode.IO_LV_1,
/*ILOAD_2*/ Opcode.SD_P1 | Opcode.IO_LV_2,
/*ILOAD_3*/ Opcode.SD_P1 | Opcode.IO_LV_3,
/* 30*/ /*LLOAD_0*/ Opcode.SD_P2 | Opcode.IO_LV_0,
/*LLOAD_1*/ Opcode.SD_P2 | Opcode.IO_LV_1,
/*LLOAD_2*/ Opcode.SD_P2 | Opcode.IO_LV_2,
/*LLOAD_3*/ Opcode.SD_P2 | Opcode.IO_LV_3,
/*FLOAD_0*/ Opcode.SD_P1 | Opcode.IO_LV_0,
/*FLOAD_1*/ Opcode.SD_P1 | Opcode.IO_LV_1,
/*FLOAD_2*/ Opcode.SD_P1 | Opcode.IO_LV_2,
/*FLOAD_3*/ Opcode.SD_P1 | Opcode.IO_LV_3,
/*DLOAD_0*/ Opcode.SD_P2 | Opcode.IO_LV_0,
/*DLOAD_1*/ Opcode.SD_P2 | Opcode.IO_LV_1,
/* 40*/ /*DLOAD_2*/ Opcode.SD_P2 | Opcode.IO_LV_2,
/*DLOAD_3*/ Opcode.SD_P2 | Opcode.IO_LV_3,
/*ALOAD_0*/ Opcode.SD_P1 | Opcode.IO_LV_0,
/*ALOAD_1*/ Opcode.SD_P1 | Opcode.IO_LV_1,
/*ALOAD_2*/ Opcode.SD_P1 | Opcode.IO_LV_2,
/*ALOAD_3*/ Opcode.SD_P1 | Opcode.IO_LV_3,
/*IALOAD*/ Opcode.SD_M1,
/*LALOAD*/ Opcode.SD_P0,
/*FALOAD*/ Opcode.SD_M1,
/*DALOAD*/ Opcode.SD_P0,
/* 50*/ /*AALOAD*/ Opcode.SD_M1,
/*BALOAD*/ Opcode.SD_M1,
/*CALOAD*/ Opcode.SD_M1,
/*SALOAD*/ Opcode.SD_M1,
/*ISTORE*/ Opcode.SD_M1 | Opcode.OP1_LV1,
/*LSTORE*/ Opcode.SD_M2 | Opcode.OP1_LV1,
/*FSTORE*/ Opcode.SD_M1 | Opcode.OP1_LV1,
/*DSTORE*/ Opcode.SD_M2 | Opcode.OP1_LV1,
/*ASTORE*/ Opcode.SD_M1 | Opcode.OP1_LV1,
/*ISTORE_0*/ Opcode.SD_M1 | Opcode.IO_LV_0,
/* 60*/ /*ISTORE_1*/ Opcode.SD_M1 | Opcode.IO_LV_1,
/*ISTORE_2*/ Opcode.SD_M1 | Opcode.IO_LV_2,
/*ISTORE_3*/ Opcode.SD_M1 | Opcode.IO_LV_3,
/*LSTORE_0*/ Opcode.SD_M2 | Opcode.IO_LV_0,
/*LSTORE_1*/ Opcode.SD_M2 | Opcode.IO_LV_1,
/*LSTORE_2*/ Opcode.SD_M2 | Opcode.IO_LV_2,
/*LSTORE_3*/ Opcode.SD_M2 | Opcode.IO_LV_3,
/*FSTORE_0*/ Opcode.SD_M1 | Opcode.IO_LV_0,
/*FSTORE_1*/ Opcode.SD_M1 | Opcode.IO_LV_1,
/*FSTORE_2*/ Opcode.SD_M1 | Opcode.IO_LV_2,
/* 70*/ /*FSTORE_3*/ Opcode.SD_M1 | Opcode.IO_LV_3,
/*DSTORE_0*/ Opcode.SD_M2 | Opcode.IO_LV_0,
/*DSTORE_1*/ Opcode.SD_M2 | Opcode.IO_LV_1,
/*DSTORE_2*/ Opcode.SD_M2 | Opcode.IO_LV_2,
/*DSTORE_3*/ Opcode.SD_M2 | Opcode.IO_LV_3,
/*ASTORE_0*/ Opcode.SD_M1 | Opcode.IO_LV_0,
/*ASTORE_1*/ Opcode.SD_M1 | Opcode.IO_LV_1,
/*ASTORE_2*/ Opcode.SD_M1 | Opcode.IO_LV_2,
/*ASTORE_3*/ Opcode.SD_M1 | Opcode.IO_LV_3,
/*IASTORE*/ Opcode.SD_M3,
/* 80*/ /*LASTORE*/ Opcode.SD_M4,
/*FASTORE*/ Opcode.SD_M3,
/*DASTORE*/ Opcode.SD_M4,
/*AASTORE*/ Opcode.SD_M3,
/*BASTORE*/ Opcode.SD_M3,
/*CASTORE*/ Opcode.SD_M3,
/*SASTORE*/ Opcode.SD_M3,
/*POP*/ Opcode.SD_M1,
/*POP2*/ Opcode.SD_M2,
/*DUP*/ Opcode.SD_P1,
/* 90*/ /*DUP_X1*/ Opcode.SD_P1,
/*DUP_X2*/ Opcode.SD_P1,
/*DUP2*/ Opcode.SD_P2,
/*DUP2_X1*/ Opcode.SD_P2,
/*DUP2_X2*/ Opcode.SD_P2,
/*SWAP*/ Opcode.SD_P0,
/*IADD*/ Opcode.SD_M1,
/*LADD*/ Opcode.SD_M2,
/*FADD*/ Opcode.SD_M1,
/*DADD*/ Opcode.SD_M2,
/*100*/ /*ISUB*/ Opcode.SD_M1,
/*LSUB*/ Opcode.SD_M2,
/*FSUB*/ Opcode.SD_M1,
/*DSUB*/ Opcode.SD_M2,
/*IMUL*/ Opcode.SD_M1,
/*LMUL*/ Opcode.SD_M2,
/*FMUL*/ Opcode.SD_M1,
/*DMUL*/ Opcode.SD_M2,
/*IDIV*/ Opcode.SD_M1,
/*LDIV*/ Opcode.SD_M2,
/*110*/ /*FDIV*/ Opcode.SD_M1,
/*DDIV*/ Opcode.SD_M2,
/*IREM*/ Opcode.SD_M1,
/*LREM*/ Opcode.SD_M2,
/*FREM*/ Opcode.SD_M1,
/*DREM*/ Opcode.SD_M2,
/*INEG*/ Opcode.SD_P0,
/*LNEG*/ Opcode.SD_P0,
/*FNEG*/ Opcode.SD_P0,
/*DNEG*/ Opcode.SD_P0,
/*120*/ /*ISHL*/ Opcode.SD_M1,
/*LSHL*/ Opcode.SD_M1,
/*ISHR*/ Opcode.SD_M1,
/*LSHR*/ Opcode.SD_M1,
/*IUSHR*/ Opcode.SD_M1,
/*LUSHR*/ Opcode.SD_M1,
/*IAND*/ Opcode.SD_M1,
/*LAND*/ Opcode.SD_M2,
/*IOR*/ Opcode.SD_M1,
/*LOR*/ Opcode.SD_M2,
/*130*/ /*IXOR*/ Opcode.SD_M1,
/*LXOR*/ Opcode.SD_M2,
/*IINC*/ Opcode.SD_P0 | Opcode.OP1_LV1 | Opcode.OP2_SB,
/*I2L*/ Opcode.SD_P1,
/*I2F*/ Opcode.SD_P0,
/*I2D*/ Opcode.SD_P1,
/*L2I*/ Opcode.SD_M1,
/*L2F*/ Opcode.SD_M1,
/*L2D*/ Opcode.SD_P0,
/*F2I*/ Opcode.SD_P0,
/*140*/ /*F2L*/ Opcode.SD_P1,
/*F2D*/ Opcode.SD_P1,
/*D2I*/ Opcode.SD_M1,
/*D2L*/ Opcode.SD_P0,
/*D2F*/ Opcode.SD_M1,
/*I2B*/ Opcode.SD_P0,
/*I2C*/ Opcode.SD_P0,
/*I2S*/ Opcode.SD_P0,
/*LCMP*/ Opcode.SD_M3,
/*FCMPL*/ Opcode.SD_M1,
/*150*/ /*FCMPG*/ Opcode.SD_M1,
/*DCMPL*/ Opcode.SD_M3,
/*DCMPG*/ Opcode.SD_M3,
/*IFEQ*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IFNE*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IFLT*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IFGE*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IFGT*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IFLE*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IF_ICMPEQ*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*160*/ /*IF_ICMPNE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*IF_ICMPLT*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*IF_ICMPGE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*IF_ICMPGT*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*IF_ICMPLE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*IF_ACMPEQ*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*IF_ACMPNE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
/*GOTO*/ Opcode.SD_P0 | Opcode.OP1_BO2 | Opcode.NO_FALLTHROUGH,
/*JSR*/ Opcode.SD_P0 | Opcode.OP1_JSR,
/*RET*/ Opcode.SD_P0 | Opcode.OP1_LV1 | Opcode.NO_FALLTHROUGH,
/*170*/ /*TABLESWITCH*/ Opcode.SD_M1 | Opcode.OP1_TABLESWITCH,
/*LOOKUPSWITCH*/ Opcode.SD_M1 | Opcode.OP1_LOOKUPSWITCH,
/*IRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
/*LRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
/*FRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
/*DRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
/*ARETURN*/ Opcode.SD_M1 | Opcode.NO_FALLTHROUGH,
/*RETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
/*GETSTATIC*/ Opcode.SD_GETSTATIC | Opcode.OP1_CP2,
/*PUTSTATIC*/ Opcode.SD_PUTSTATIC | Opcode.OP1_CP2,
/*180*/ /*GETFIELD*/ Opcode.SD_GETFIELD | Opcode.OP1_CP2,
/*PUTFIELD*/ Opcode.SD_PUTFIELD | Opcode.OP1_CP2,
/*INVOKEVIRTUAL*/ Opcode.SD_INVOKEVIRTUAL | Opcode.OP1_CP2,
/*INVOKESPECIAL*/ Opcode.SD_INVOKESPECIAL | Opcode.OP1_CP2,
/*INVOKESTATIC*/ Opcode.SD_INVOKESTATIC | Opcode.OP1_CP2,
/*INVOKEINTERFACE*/ Opcode.SD_INVOKEINTERFACE | Opcode.OP1_CP2 | Opcode.OP2_SB | Opcode.OP3_SB,
/*UNUSED*/ Opcode.INVALID_OPCODE,
/*NEW*/ Opcode.SD_P1 | Opcode.OP1_CP2,
/*NEWARRAY*/ Opcode.SD_P0 | Opcode.OP1_UB,
/*ANEWARRAY*/ Opcode.SD_P0 | Opcode.OP1_CP2,
/*190*/ /*ARRAYLENGTH*/ Opcode.SD_P0,
/*ATHROW*/ Opcode.SD_M1 | Opcode.NO_FALLTHROUGH,
/*CHECKCAST*/ Opcode.SD_P0 | Opcode.OP1_CP2,
/*INSTANCEOF*/ Opcode.SD_P0 | Opcode.OP1_CP2,
/*MONITORENTER*/ Opcode.SD_M1,
/*MONITOREXIT*/ Opcode.SD_M1,
/*WIDE*/ Opcode.INVALID_OPCODE,
/*MULTIANEWARRAY*/ Opcode.SD_MULTIANEWARRAY | Opcode.OP1_CP2 | Opcode.OP2_SB,
/*IFNULL*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*IFNONNULL*/ Opcode.SD_M1 | Opcode.OP1_BO2,
/*200*/ /*GOTO_W*/ Opcode.SD_P0 | Opcode.OP1_BO4 | Opcode.NO_FALLTHROUGH,
/*JSR_W*/ Opcode.SD_P1 | Opcode.OP1_BO4,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
/*210*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
/*220*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
/*230*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
/*240*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
/*250*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
// CHECKSTYLE WrapAndIndent:ON
};
/** The {@code n}th element of this array describes the properties of the JVM opcode {@code WIDE n}. */
public static final short[] WIDE_OPCODE_PROPERTIES = new short[256];
static {
for (int i = 0; i < Opcode.WIDE_OPCODE_PROPERTIES.length; ++i) {
Opcode.WIDE_OPCODE_PROPERTIES[i] = Opcode.INVALID_OPCODE;
}
// load instructions
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ILOAD] = Opcode.SD_P1 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.FLOAD] = Opcode.SD_P1 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ALOAD] = Opcode.SD_P1 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.LLOAD] = Opcode.SD_P2 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.DLOAD] = Opcode.SD_P2 | Opcode.OP1_LV2;
// store instructions
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ISTORE] = Opcode.SD_M1 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.FSTORE] = Opcode.SD_M1 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ASTORE] = Opcode.SD_M1 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.LSTORE] = Opcode.SD_M2 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.DSTORE] = Opcode.SD_M2 | Opcode.OP1_LV2;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.IINC] = Opcode.SD_P0 | Opcode.OP1_LV2 | Opcode.OP2_SS;
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.RET] = Opcode.SD_P0 | Opcode.OP1_LV2;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,384 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.Location;
/** Wraps a {@link java.lang.Class} in an {@link org.codehaus.janino.IClass}. */
@SuppressWarnings("rawtypes")
class ReflectionIClass extends IClass {
private final Class clazz;
private final IClassLoader iClassLoader;
/** @param iClassLoader Required to load other {@link IClass}es on {@code get...()} */
public
ReflectionIClass(Class clazz, IClassLoader iClassLoader) {
this.clazz = clazz;
this.iClassLoader = iClassLoader;
}
@Override protected IConstructor[]
getDeclaredIConstructors2() {
Constructor[] constructors = this.clazz.getDeclaredConstructors();
IConstructor[] result = new IConstructor[constructors.length];
for (int i = 0; i < constructors.length; ++i) {
result[i] = new ReflectionIConstructor(constructors[i]);
}
return result;
}
@Override protected IMethod[]
getDeclaredIMethods2() {
Method[] methods = this.clazz.getDeclaredMethods();
if (methods.length == 0 && this.clazz.isArray()) {
return new IMethod[] { new IMethod() {
@Override public String getName() { return "clone"; }
@Override public IClass getReturnType() { return ReflectionIClass.this.iClassLoader.TYPE_java_lang_Object; } // SUPPRESS CHECKSTYLE LineLength
@Override public boolean isAbstract() { return false; }
@Override public boolean isStatic() { return false; }
@Override public Access getAccess() { return Access.PUBLIC; }
@Override public boolean isVarargs() { return false; }
@Override public IClass[] getParameterTypes2() { return new IClass[0]; }
@Override public IClass[] getThrownExceptions2() { return new IClass[0]; }
@Override public Java.Annotation[] getAnnotations() { return new Java.Annotation[0]; }
} };
}
IMethod[] result = new IMethod[methods.length];
for (int i = 0; i < result.length; i++) result[i] = new ReflectionIMethod(methods[i]);
return result;
}
@Override protected IField[]
getDeclaredIFields2() {
Field[] fields = this.clazz.getDeclaredFields();
IField[] result = new IField[fields.length];
for (int i = 0; i < fields.length; ++i) {
result[i] = new ReflectionIField(fields[i]);
}
return result;
}
@Override protected IClass[]
getDeclaredIClasses2() { return this.classesToIClasses(this.clazz.getDeclaredClasses()); }
@Override protected IClass
getDeclaringIClass2() {
Class declaringClass = this.clazz.getDeclaringClass();
if (declaringClass == null) return null;
return this.classToIClass(declaringClass);
}
@Override protected IClass
getOuterIClass2() throws CompileException {
if (Modifier.isStatic(this.clazz.getModifiers())) return null;
return this.getDeclaringIClass();
}
@Override protected IClass
getSuperclass2() {
Class superclass = this.clazz.getSuperclass();
return superclass == null ? null : this.classToIClass(superclass);
}
@Override protected IClass[]
getInterfaces2() {
return this.classesToIClasses(this.clazz.getInterfaces());
}
@Override protected String
getDescriptor2() {
return Descriptor.fromClassName(this.clazz.getName());
}
@Override public Access getAccess() { return ReflectionIClass.modifiers2Access(this.clazz.getModifiers()); }
@Override public boolean isFinal() { return Modifier.isFinal(this.clazz.getModifiers()); }
@Override public boolean isInterface() { return this.clazz.isInterface(); }
@Override public boolean isAbstract() { return Modifier.isAbstract(this.clazz.getModifiers()); }
@Override public boolean isArray() { return this.clazz.isArray(); }
@Override protected IClass
getComponentType2() {
Class componentType = this.clazz.getComponentType();
return componentType == null ? null : this.classToIClass(componentType);
}
@Override public boolean
isPrimitive() { return this.clazz.isPrimitive(); }
@Override public boolean
isPrimitiveNumeric() {
return (
this.clazz == byte.class
|| this.clazz == short.class
|| this.clazz == int.class
|| this.clazz == long.class
|| this.clazz == char.class
|| this.clazz == float.class
|| this.clazz == double.class
);
}
/** @return The underlying {@link Class java.lang.Class} */
public Class
getClazz() { return this.clazz; }
/** @return E.g. "int", "int[][]", "pkg1.pkg2.Outer$Inner[]" */
@Override public String
toString() {
int brackets = 0;
Class c = this.clazz;
while (c.isArray()) {
++brackets;
c = c.getComponentType();
}
String s = c.getName();
while (brackets-- > 0) s += "[]";
return s;
}
private
class ReflectionIConstructor extends IConstructor {
public
ReflectionIConstructor(Constructor constructor) { this.constructor = constructor; }
// Implement IMember.
@Override public Access
getAccess() {
int mod = this.constructor.getModifiers();
return ReflectionIClass.modifiers2Access(mod);
}
@Override public Java.Annotation[]
getAnnotations() { return new Java.Annotation[0]; }
@Override public boolean
isVarargs() {
// TRANSIENT is identical with VARARGS.
return Modifier.isTransient(this.constructor.getModifiers());
}
// Implement "IConstructor".
@Override public IClass[]
getParameterTypes2() throws CompileException {
IClass[] parameterTypes = ReflectionIClass.this.classesToIClasses(this.constructor.getParameterTypes());
// The JAVADOC of java.lang.reflect.Constructor does not document it, but
// "getParameterTypes()" includes the synthetic "enclosing instance" parameter.
IClass outerClass = ReflectionIClass.this.getOuterIClass();
if (outerClass != null) {
if (parameterTypes.length < 1) {
throw new CompileException(
"Constructor \"" + this.constructor + "\" lacks synthetic enclosing instance parameter",
null
);
}
if (parameterTypes[0] != outerClass) {
throw new CompileException((
"Enclosing instance parameter of constructor \""
+ this.constructor
+ "\" has wrong type -- \""
+ parameterTypes[0]
+ "\" vs. \""
+ outerClass
+ "\""
), null);
}
IClass[] tmp = new IClass[parameterTypes.length - 1];
System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
parameterTypes = tmp;
}
return parameterTypes;
}
@Override public String
getDescriptor2() {
Class[] parameterTypes = this.constructor.getParameterTypes();
String[] parameterDescriptors = new String[parameterTypes.length];
for (int i = 0; i < parameterDescriptors.length; ++i) {
parameterDescriptors[i] = Descriptor.fromClassName(parameterTypes[i].getName());
}
return new MethodDescriptor(parameterDescriptors, Descriptor.VOID).toString();
}
@Override public IClass[]
getThrownExceptions2() {
return ReflectionIClass.this.classesToIClasses(this.constructor.getExceptionTypes());
}
final Constructor constructor;
}
public
class ReflectionIMethod extends IMethod {
public
ReflectionIMethod(Method method) { this.method = method; }
// Implement IMember.
@Override public Access
getAccess() { return ReflectionIClass.modifiers2Access(this.method.getModifiers()); }
@Override public Java.Annotation[]
getAnnotations() { return new Java.Annotation[0]; }
// Implement "IMethod".
@Override public String
getName() { return this.method.getName(); }
@Override public boolean
isVarargs() {
// VARARGS is identical with TRANSIENT.
return Modifier.isTransient(this.method.getModifiers());
}
@Override public IClass[]
getParameterTypes2() { return ReflectionIClass.this.classesToIClasses(this.method.getParameterTypes()); }
@Override public boolean
isStatic() { return Modifier.isStatic(this.method.getModifiers()); }
@Override public boolean
isAbstract() { return Modifier.isAbstract(this.method.getModifiers()); }
@Override public IClass
getReturnType() { return ReflectionIClass.this.classToIClass(this.method.getReturnType()); }
@Override public IClass[]
getThrownExceptions2() { return ReflectionIClass.this.classesToIClasses(this.method.getExceptionTypes()); }
private final Method method;
}
private
class ReflectionIField extends IField {
public
ReflectionIField(Field field) { this.field = field; }
// Implement IMember.
@Override public Access
getAccess() { return ReflectionIClass.modifiers2Access(this.field.getModifiers()); }
@Override public Java.Annotation[]
getAnnotations() { return new Java.Annotation[0]; }
// Implement "IField".
@Override public String
getName() { return this.field.getName(); }
@Override public boolean
isStatic() { return Modifier.isStatic(this.field.getModifiers()); }
@Override public IClass
getType() { return ReflectionIClass.this.classToIClass(this.field.getType()); }
@Override public String
toString() {
return Descriptor.toString(this.getDeclaringIClass().getDescriptor()) + "." + this.getName();
}
/**
* This implementation of {@link IClass.IField#getConstantValue()} is
* not completely correct:
* <ul>
* <li>
* It treats non-static fields as non-constant
* <li>
* Even fields with a <i>non-constant</i> initializer are identified
* as constant. (The value of that field may be different in a
* different JVM instance -- the classical example is
* {@link java.io.File#separator}.)
* </ul>
*/
@Override public Object
getConstantValue() throws CompileException {
int mod = this.field.getModifiers();
Class clazz = this.field.getType();
if (
Modifier.isStatic(mod)
&& Modifier.isFinal(mod)
&& (clazz.isPrimitive() || clazz == String.class)
) {
try {
return this.field.get(null);
} catch (IllegalAccessException ex) {
throw new CompileException( // SUPPRESS CHECKSTYLE AvoidHidingCause
"Field \"" + this.field.getName() + "\" is not accessible",
(Location) null
);
}
}
return IClass.NOT_CONSTANT;
}
final Field field;
}
/** Loads {@link Class} through {@link IClassLoader} to ensure unique {@link IClass}es. */
private IClass
classToIClass(Class c) {
IClass iClass;
try {
iClass = this.iClassLoader.loadIClass(Descriptor.fromClassName(c.getName()));
} catch (ClassNotFoundException ex) {
throw new JaninoRuntimeException("Loading IClass \"" + c.getName() + "\": " + ex);
}
if (iClass == null) {
throw new JaninoRuntimeException("Cannot load class \"" + c.getName() + "\" through the given ClassLoader");
}
return iClass;
}
/** @see #classToIClass(Class) */
private IClass[]
classesToIClasses(Class[] cs) {
IClass[] result = new IClass[cs.length];
for (int i = 0; i < cs.length; ++i) result[i] = this.classToIClass(cs[i]);
return result;
}
private static Access
modifiers2Access(int modifiers) {
return (
Modifier.isPrivate(modifiers) ? Access.PRIVATE :
Modifier.isProtected(modifiers) ? Access.PROTECTED :
Modifier.isPublic(modifiers) ? Access.PUBLIC :
Access.DEFAULT
);
}
}

View File

@ -0,0 +1,82 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.IOException;
import java.io.InputStream;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.resource.Resource;
import org.codehaus.janino.util.resource.ResourceFinder;
/**
* This {@link org.codehaus.janino.IClassLoader} loads IClasses through a
* a {@link org.codehaus.janino.util.resource.ResourceFinder} that designates
* {@link org.codehaus.janino.util.ClassFile}s.
*/
public
class ResourceFinderIClassLoader extends IClassLoader {
private final ResourceFinder resourceFinder;
public
ResourceFinderIClassLoader(ResourceFinder resourceFinder, IClassLoader optionalParentIClassLoader) {
super(optionalParentIClassLoader);
this.resourceFinder = resourceFinder;
this.postConstruct();
}
@Override protected IClass
findIClass(String descriptor) throws ClassNotFoundException {
String className = Descriptor.toClassName(descriptor);
// Find the class file resource.
Resource classFileResource = this.resourceFinder.findResource(ClassFile.getClassFileResourceName(className));
if (classFileResource == null) return null;
// Open the class file resource.
InputStream is;
try {
is = classFileResource.open();
} catch (IOException ex) {
throw new ClassNotFoundException("Opening resource \"" + classFileResource.getFileName() + "\"", ex);
}
// Load the IClass from the class file.
ClassFile cf;
try {
cf = new ClassFile(is);
} catch (IOException e) {
throw new ClassNotFoundException("Reading resource \"" + classFileResource.getFileName() + "\"", e);
} finally {
try { is.close(); } catch (IOException e) {}
}
IClass iClass = new ClassFileIClass(cf, this);
this.defineIClass(iClass);
return iClass;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,993 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.Cookable;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.codehaus.commons.compiler.IScriptEvaluator;
import org.codehaus.commons.compiler.Location;
import org.codehaus.janino.Java.VariableDeclarator;
import org.codehaus.janino.util.Traverser;
/** A number of "convenience constructors" exist that execute the setup steps instantly. Their use is discouraged. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class ScriptEvaluator extends ClassBodyEvaluator implements IScriptEvaluator {
/** Whether methods override a method declared by a supertype; {@code null} means "none". */
protected boolean[] optionalOverrideMethod;
/** Whether methods are static; {@code null} means "all". */
protected boolean[] optionalStaticMethod;
/** The methods' return types; {@code null} means "none". */
protected Class[] optionalReturnTypes;
private String[] optionalMethodNames;
private String[][] optionalParameterNames;
private Class[][] optionalParameterTypes;
private Class[][] optionalThrownExceptions;
private Method[] result; // null=uncooked
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.cook(script);</pre>
*
* @see #ScriptEvaluator()
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(String script) throws CompileException {
this.cook(script);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.cook(script);</pre>
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(String script, Class returnType) throws CompileException {
this.setReturnType(returnType);
this.cook(script);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.cook(script);</pre>
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(String script, Class returnType, String[] parameterNames, Class[] parameterTypes)
throws CompileException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.cook(script);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.cook(script);</pre>
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(
String script,
Class returnType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions
) throws CompileException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.cook(script);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(optionalFileName, is);</pre>
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(String, InputStream)
*/
public
ScriptEvaluator(
String optionalFileName,
InputStream is,
Class returnType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(optionalFileName, is);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(reader);</pre>
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(String, Reader)
*/
public
ScriptEvaluator(
String optionalFileName,
Reader reader,
Class returnType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(optionalFileName, reader);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(scanner);</pre>
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ScriptEvaluator(
Scanner scanner,
Class returnType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setExtendedType(optionalExtendedType);
* se.setImplementedTypes(implementedTypes);
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(scanner);</pre>
*
* @see #ScriptEvaluator()
* @see ClassBodyEvaluator#setExtendedClass(Class)
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ScriptEvaluator(
Scanner scanner,
Class optionalExtendedType,
Class[] implementedTypes,
Class returnType,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Equivalent to<pre>
* ScriptEvaluator se = new ScriptEvaluator();
* se.setClassName(className);
* se.setExtendedType(optionalExtendedType);
* se.setImplementedTypes(implementedTypes);
* se.setStaticMethod(staticMethod);
* se.setReturnType(returnType);
* se.setMethodName(methodName);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(scanner);</pre>
*
* @see #ScriptEvaluator()
* @see ClassBodyEvaluator#setClassName(String)
* @see ClassBodyEvaluator#setExtendedClass(Class)
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
* @see #setStaticMethod(boolean)
* @see #setReturnType(Class)
* @see #setMethodName(String)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ScriptEvaluator(
Scanner scanner,
String className,
Class optionalExtendedType,
Class[] implementedTypes,
boolean staticMethod,
Class returnType,
String methodName,
String[] parameterNames,
Class[] parameterTypes,
Class[] thrownExceptions,
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setClassName(className);
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setStaticMethod(staticMethod);
this.setReturnType(returnType);
this.setMethodName(methodName);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Constructs a script evaluator with all the default settings (return type {@code void}
*/
public ScriptEvaluator() {}
@Override public void
setOverrideMethod(boolean overrideMethod) {
this.setOverrideMethod(new boolean[] { overrideMethod });
}
@Override public void
setStaticMethod(boolean staticMethod) {
this.setStaticMethod(new boolean[] { staticMethod });
}
/**
* Defines the return types of the generated methods.
*
* @param returnType The method's return type; {@code null} means the "default return type", which is the type
* returned by {@link #getDefaultReturnType()} ({@code void.class} for {@link ScriptEvaluator}
* and {@code Object.class} for {@link ExpressionEvaluator})
* @see ScriptEvaluator#getDefaultReturnType()
* @see ExpressionEvaluator#getDefaultReturnType()
*/
@Override public void
setReturnType(Class returnType) {
this.setReturnTypes(new Class[] { returnType });
}
@Override public void
setMethodName(String methodName) {
this.setMethodNames(new String[] { methodName });
}
@Override public void
setParameters(String[] parameterNames, Class[] parameterTypes) {
this.setParameters(new String[][] { parameterNames }, new Class[][] { parameterTypes });
}
@Override public void
setThrownExceptions(Class[] thrownExceptions) {
this.setThrownExceptions(new Class[][] { thrownExceptions });
}
@Override public final void
cook(Scanner scanner) throws CompileException, IOException {
this.cook(new Scanner[] { scanner });
}
@Override public Object
evaluate(Object[] arguments) throws InvocationTargetException {
return this.evaluate(0, arguments);
}
@Override public Method
getMethod() { return this.getMethod(0); }
@Override public void
setOverrideMethod(boolean[] overrideMethod) {
this.assertNotCooked();
this.optionalOverrideMethod = overrideMethod.clone();
}
@Override public void
setStaticMethod(boolean[] staticMethod) {
this.assertNotCooked();
this.optionalStaticMethod = staticMethod.clone();
}
/**
* Defines the return types of the generated methods.
*
* @param returnTypes The methods' return types; {@code null} elements mean the "default return type", which is the
* type returned by {@link #getDefaultReturnType()} ({@code void.class} for {@link
* ScriptEvaluator} and {@code Object.class} for {@link ExpressionEvaluator})
* @see ScriptEvaluator#getDefaultReturnType()
* @see ExpressionEvaluator#getDefaultReturnType()
*/
@Override public void
setReturnTypes(Class[] returnTypes) {
this.assertNotCooked();
this.optionalReturnTypes = returnTypes.clone();
}
@Override public void
setMethodNames(String[] methodNames) {
this.assertNotCooked();
this.optionalMethodNames = methodNames.clone();
}
@Override public void
setParameters(String[][] parameterNames, Class[][] parameterTypes) {
this.assertNotCooked();
this.optionalParameterNames = parameterNames.clone();
this.optionalParameterTypes = parameterTypes.clone();
}
@Override public void
setThrownExceptions(Class[][] thrownExceptions) {
this.assertNotCooked();
this.optionalThrownExceptions = thrownExceptions.clone();
}
/**
* Like {@link #cook(Scanner)}, but cooks a <i>set</i> of scripts into one class. Notice that
* if <i>any</i> of the scripts causes trouble, the entire compilation will fail. If you
* need to report <i>which</i> of the scripts causes the exception, you may want to use the
* <code>optionalFileName</code> argument of {@link Scanner#Scanner(String, Reader)} to
* distinguish between the individual token sources.
* <p>
* 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.
* <p>
* The number and the complexity of the scripts is restricted by the
* <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88659">Limitations
* of the Java Virtual Machine</a>, 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.
*
* @throws IllegalStateException Any of the preceeding <code>set...()</code> had an array size different from that
* of <code>scanners</code>
*/
public final void
cook(Scanner[] scanners) throws CompileException, IOException {
if (scanners == null) throw new NullPointerException();
Parser[] parsers = new Parser[scanners.length];
for (int i = 0; i < scanners.length; ++i) {
parsers[i] = new Parser(scanners[i]);
}
this.cook(parsers);
}
/** @see #cook(Scanner[]) */
public final void
cook(Parser[] parsers) throws CompileException, IOException {
// The "dimension" of this ScriptEvaluator, i.e. how many scripts are cooked at the same
// time.
int count = parsers.length;
// Check array sizes.
if (this.optionalMethodNames != null && this.optionalMethodNames.length != count) {
throw new IllegalStateException("methodName count");
}
if (this.optionalParameterNames != null && this.optionalParameterNames.length != count) {
throw new IllegalStateException("parameterNames count");
}
if (this.optionalParameterTypes != null && this.optionalParameterTypes.length != count) {
throw new IllegalStateException("parameterTypes count");
}
if (this.optionalOverrideMethod != null && this.optionalOverrideMethod.length != count) {
throw new IllegalStateException("overrideMethod count");
}
if (this.optionalReturnTypes != null && this.optionalReturnTypes.length != count) {
throw new IllegalStateException("returnTypes count");
}
if (this.optionalStaticMethod != null && this.optionalStaticMethod.length != count) {
throw new IllegalStateException("staticMethod count");
}
if (this.optionalThrownExceptions != null && this.optionalThrownExceptions.length != count) {
throw new IllegalStateException("thrownExceptions count");
}
// Create compilation unit.
Java.CompilationUnit compilationUnit = this.makeCompilationUnit(count == 1 ? parsers[0] : null);
// Create class declaration.
Java.ClassDeclaration cd = this.addPackageMemberClassDeclaration(parsers[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) {
Parser parser = parsers[i];
List<Java.BlockStatement> statements = this.makeStatements(i, parser);
// 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 || this.optionalStaticMethod[i];
boolean overrideMethod = this.optionalOverrideMethod != null && this.optionalOverrideMethod[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]
);
// If the method is non-static, assume that it overrides a method in a supertype.
Location loc = parser.location();
cd.addDeclaredMethod(this.makeMethodDeclaration(
loc, // location
( // annotations
overrideMethod
? new Java.Annotation[] { new Java.MarkerAnnotation(this.classToType(loc, Override.class)) }
: new Java.Annotation[0]
),
staticMethod, // staticMethod
returnType, // returnType
methodNames[i], // methodName
parameterTypes, // parameterTypes
parameterNames, // parameterNames
thrownExceptions, // thrownExceptions
statements // statements
));
}
// Compile and load the compilation unit.
Class c = this.compileToClass(compilationUnit);
// 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 JaninoRuntimeException((
"SNO: Loaded class does not declare method \""
+ methodNames[i]
+ "\""
), ex);
}
}
} else
{
class MethodWrapper {
private final String name;
private final Class[] parameterTypes;
MethodWrapper(String name, Class[] parameterTypes) {
this.name = name;
this.parameterTypes = parameterTypes;
}
@Override 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;
}
@Override public int
hashCode() {
int hc = this.name.hashCode();
for (Class parameterType : this.parameterTypes) hc ^= parameterType.hashCode();
return hc;
}
}
Method[] ma = c.getDeclaredMethods();
Map<MethodWrapper, Method> dms = new HashMap(2 * count);
for (Method m : ma) 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 JaninoRuntimeException(
"SNO: Loaded class does not declare method \""
+ methodNames[i]
+ "\""
);
}
this.result[i] = m;
}
}
}
@Override public final void
cook(Reader[] readers) throws CompileException, IOException {
this.cook(new String[readers.length], readers);
}
/**
* 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.
* <p>
* The number and the complexity of the scripts is restricted by the
* <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88659">Limitations
* of the Java Virtual Machine</a>, 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.
*/
@Override public final void
cook(String[] optionalFileNames, Reader[] readers) throws CompileException, IOException {
Scanner[] scanners = new Scanner[readers.length];
for (int i = 0; i < readers.length; ++i) {
scanners[i] = new Scanner(optionalFileNames == null ? null : optionalFileNames[i], readers[i]);
}
this.cook(scanners);
}
@Override public final void
cook(String[] strings) throws CompileException { this.cook(null, strings); }
@Override public final void
cook(String[] optionalFileNames, String[] strings) throws CompileException {
Reader[] readers = new Reader[strings.length];
for (int i = 0; i < strings.length; ++i) readers[i] = new StringReader(strings[i]);
try {
this.cook(optionalFileNames, readers);
} catch (IOException ex) {
throw new JaninoRuntimeException("SNO: IOException despite StringReader", ex);
}
}
/**
* @return {@code void.class}
* @see #setReturnTypes(Class[])
*/
protected Class
getDefaultReturnType() { return void.class; }
/** Fills the given <code>block</code> by parsing statements until EOF and adding them to the block. */
protected List<Java.BlockStatement>
makeStatements(int idx, Parser parser) throws CompileException, IOException {
List<Java.BlockStatement> statements = new ArrayList();
while (!parser.peekEof()) {
statements.add(parser.parseBlockStatement());
}
return statements;
}
/**
* To the given {@link Java.ClassDeclaration}, add
* <ul>
* <li>A public method declaration with the given return type, name, parameter
* names and values and thrown exceptions
* <li>A block
* </ul>
*
* @param returnType Return type of the declared method
*/
protected Java.MethodDeclarator
makeMethodDeclaration(
Location location,
Java.Annotation[] annotations,
boolean staticMethod,
Class returnType,
String methodName,
Class[] parameterTypes,
String[] parameterNames,
Class[] thrownExceptions,
List<Java.BlockStatement> statements
) {
if (parameterNames.length != parameterTypes.length) {
throw new JaninoRuntimeException(
"Lengths of \"parameterNames\" ("
+ parameterNames.length
+ ") and \"parameterTypes\" ("
+ parameterTypes.length
+ ") do not match"
);
}
Java.FunctionDeclarator.FormalParameters fps = new Java.FunctionDeclarator.FormalParameters(
location,
new Java.FunctionDeclarator.FormalParameter[parameterNames.length],
false
);
for (int i = 0; i < fps.parameters.length; ++i) {
fps.parameters[i] = new Java.FunctionDeclarator.FormalParameter(
location, // location
true, // finaL
this.classToType(location, parameterTypes[i]), // type
parameterNames[i] // name
);
}
return new Java.MethodDeclarator(
location, // location
null, // optionalDocComment
new Java.Modifiers( // modifiers
staticMethod ? (short) (Mod.PUBLIC | Mod.STATIC) : (short) Mod.PUBLIC,
annotations
),
this.classToType(location, returnType), // type
methodName, // name
fps, // formalParameters
this.classesToTypes(location, thrownExceptions), // thrownExceptions
statements // optionalStatements
);
}
/**
* @deprecated Use {@link #createFastScriptEvaluator(Scanner, String[], String, Class, Class, String[],
* ClassLoader)} instead
*/
@Deprecated public static Object
createFastScriptEvaluator(String script, Class interfaceToImplement, String[] parameterNames)
throws CompileException {
ScriptEvaluator se = new ScriptEvaluator();
return se.createFastEvaluator(script, interfaceToImplement, parameterNames);
}
/**
* @deprecated Use {@link #createFastScriptEvaluator(Scanner, String[], String, Class, Class, String[],
* ClassLoader)} instead
*/
@Deprecated public static Object
createFastScriptEvaluator(
Scanner scanner,
Class interfaceToImplement,
String[] parameterNames,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
ScriptEvaluator se = new ScriptEvaluator();
se.setParentClassLoader(optionalParentClassLoader);
return se.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
}
/**
* @deprecated Use {@link #createFastScriptEvaluator(Scanner, String[], String, Class, Class, String[],
* ClassLoader)} instead
*/
@Deprecated public static Object
createFastScriptEvaluator(
Scanner scanner,
String className,
Class optionalExtendedType,
Class interfaceToImplement,
String[] parameterNames,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
ScriptEvaluator se = new ScriptEvaluator();
se.setClassName(className);
se.setExtendedClass(optionalExtendedType);
se.setParentClassLoader(optionalParentClassLoader);
return se.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
}
/**
* <pre>
* {@link ScriptEvaluator} se = new {@link ScriptEvaluator#ScriptEvaluator() ScriptEvaluator}();
* se.{@link #setDefaultImports(String[]) setDefaultImports}.(optionalDefaultImports);
* se.{@link #setClassName(String) setClassName}.(className);
* se.{@link #setExtendedClass(Class) setExtendedClass}.(optionalExtendedClass);
* se.{@link #setParentClassLoader(ClassLoader) setParentClassLoader}(optionalParentClassLoader);
* return se.{@link #createFastEvaluator(Scanner, Class, String[]) createFastEvaluator}(scanner,
* interfaceToImplement, parameterNames);
* </pre>
*
* @deprecated Use {@link #createFastEvaluator(Scanner,Class,String[])} instead:
*/
@Deprecated public static Object
createFastScriptEvaluator(
Scanner scanner,
String[] optionalDefaultImports,
String className,
Class optionalExtendedClass,
Class interfaceToImplement,
String[] parameterNames,
ClassLoader optionalParentClassLoader
) throws CompileException, IOException {
ScriptEvaluator se = new ScriptEvaluator();
se.setDefaultImports(optionalDefaultImports);
se.setClassName(className);
se.setExtendedClass(optionalExtendedClass);
se.setParentClassLoader(optionalParentClassLoader);
return se.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
}
/** Don't use. */
@Override public final Object
createInstance(Reader reader) {
throw new UnsupportedOperationException("createInstance");
}
@Override public Object
createFastEvaluator(Reader reader, Class interfaceToImplement, String[] parameterNames)
throws CompileException, IOException {
return this.createFastEvaluator(new Scanner(null, reader), interfaceToImplement, parameterNames);
}
@Override public Object
createFastEvaluator(String script, Class interfaceToImplement, String[] parameterNames) throws CompileException {
try {
return this.createFastEvaluator(
new StringReader(script),
interfaceToImplement,
parameterNames
);
} catch (IOException ex) {
throw new JaninoRuntimeException("IOException despite StringReader", ex);
}
}
/**
* Notice: This method is not declared in {@link IScriptEvaluator}, and is hence only available in <i>this</i>
* implementation of <code>org.codehaus.commons.compiler</code>. To be independent from this particular
* implementation, try to switch to {@link #createFastEvaluator(Reader, Class, String[])}.
*
* @param scanner Source of tokens to read
* @see #createFastEvaluator(Reader, Class, String[])
*/
public Object
createFastEvaluator(Scanner scanner, Class interfaceToImplement, String[] parameterNames)
throws CompileException, IOException {
if (!interfaceToImplement.isInterface()) {
throw new JaninoRuntimeException("\"" + interfaceToImplement + "\" is not an interface");
}
Method methodToImplement;
{
Method[] methods = interfaceToImplement.getDeclaredMethods();
if (methods.length != 1) {
throw new JaninoRuntimeException(
"Interface \""
+ interfaceToImplement
+ "\" must declare exactly one method"
);
}
methodToImplement = methods[0];
}
this.setImplementedInterfaces(new Class[] { interfaceToImplement });
this.setOverrideMethod(true);
this.setStaticMethod(false);
if (this instanceof IExpressionEvaluator) {
// Must not call "IExpressionEvaluator.setReturnType()".
((IExpressionEvaluator) this).setExpressionType(methodToImplement.getReturnType());
} else {
this.setReturnType(methodToImplement.getReturnType());
}
this.setMethodName(methodToImplement.getName());
this.setParameters(parameterNames, methodToImplement.getParameterTypes());
this.setThrownExceptions(methodToImplement.getExceptionTypes());
this.cook(scanner);
Class c = this.getMethod().getDeclaringClass();
try {
return c.newInstance();
} catch (InstantiationException e) {
// SNO - Declared class is always non-abstract.
throw new JaninoRuntimeException(e.toString(), e);
} catch (IllegalAccessException e) {
// SNO - interface methods are always PUBLIC.
throw new JaninoRuntimeException(e.toString(), e);
}
}
/**
* Guess the names of the parameters used in the given expression. The strategy is to look
* at all "ambiguous names" in the expression (e.g. in "a.b.c.d()", the ambiguous name
* is "a.b.c"), and then at the components of the ambiguous name.
* <ul>
* <li>If any component starts with an upper-case letter, then ambiguous name is assumed to
* be a type name.
* <li>Otherwise, if the first component of the ambiguous name matches the name of a
* previously defined local variable, then the first component of the ambiguous name is
* assumed to be a local variable name. (Notice that this strategy does not consider that
* the scope of a local variable declaration may end before the end of the script.)
* <li>Otherwise, the first component of the ambiguous name is assumed to be a parameter name.
* </ul>
*
* @see Scanner#Scanner(String, Reader)
*/
public static String[]
guessParameterNames(Scanner scanner) throws CompileException, IOException {
Parser parser = new Parser(scanner);
// Eat optional leading import declarations.
while (parser.peek("import")) parser.parseImportDeclaration();
// Parse the script statements into a block.
Java.Block block = new Java.Block(scanner.location());
while (!parser.peekEof()) block.addStatement(parser.parseBlockStatement());
// Traverse the block for ambiguous names and guess which of them are parameter names.
final Set<String> localVariableNames = new HashSet();
final Set<String> parameterNames = new HashSet();
new Traverser() {
@Override public void
traverseLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
for (VariableDeclarator vd : lvds.variableDeclarators) localVariableNames.add(vd.name);
super.traverseLocalVariableDeclarationStatement(lvds);
}
@Override public void
traverseAmbiguousName(Java.AmbiguousName an) {
// If any of the components starts with an upper-case letter, then the ambiguous
// name is most probably a type name, e.g. "System.out" or "java.lang.System.out".
for (int i = 0; i < an.identifiers.length; ++i) {
if (Character.isUpperCase(an.identifiers[i].charAt(0))) return;
}
// Is it a local variable's name?
if (localVariableNames.contains(an.identifiers[0])) return;
// It's most probably a parameter name (although it could be a field name as well).
parameterNames.add(an.identifiers[0]);
}
}.traverseBlock(block);
return (String[]) parameterNames.toArray(new String[parameterNames.size()]);
}
@Override public Object
evaluate(int idx, Object[] arguments) throws InvocationTargetException {
if (this.result == null) throw new IllegalStateException("Must only be called after \"cook()\"");
try {
return this.result[idx].invoke(null, arguments);
} catch (IllegalAccessException ex) {
throw new JaninoRuntimeException(ex.toString(), ex);
}
}
@Override public Method
getMethod(int idx) {
if (this.result == null) throw new IllegalStateException("Must only be called after \"cook()\"");
return this.result[idx];
}
}

View File

@ -0,0 +1,425 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.Cookable;
import org.codehaus.commons.compiler.ErrorHandler;
import org.codehaus.commons.compiler.ICookable;
import org.codehaus.commons.compiler.ISimpleCompiler;
import org.codehaus.commons.compiler.Location;
import org.codehaus.commons.compiler.WarningHandler;
import org.codehaus.janino.Java.Type;
import org.codehaus.janino.Visitor.AtomVisitor;
import org.codehaus.janino.Visitor.TypeVisitor;
import org.codehaus.janino.util.ClassFile;
/**
* To set up a {@link SimpleCompiler} object, proceed as described for {@link ISimpleCompiler}.
* Alternatively, a number of "convenience constructors" exist that execute the described steps
* instantly.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class SimpleCompiler extends Cookable implements ISimpleCompiler {
private static final boolean DEBUG = false;
private ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
// Set when "cook()"ing.
private ClassLoaderIClassLoader classLoaderIClassLoader;
private ClassLoader result;
private ErrorHandler optionalCompileErrorHandler;
private WarningHandler optionalWarningHandler;
private boolean debugSource = Boolean.getBoolean(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_ENABLE);
private boolean debugLines = this.debugSource;
private boolean debugVars = this.debugSource;
public static void // SUPPRESS CHECKSTYLE JavadocMethod
main(String[] args) throws Exception {
if (args.length >= 1 && "-help".equals(args[0])) {
System.out.println("Usage:");
System.out.println(" org.codehaus.janino.SimpleCompiler <source-file> <class-name> { <argument> }");
System.out.println("Reads a compilation unit from the given <source-file> and invokes method");
System.out.println("\"public static void main(String[])\" of class <class-name>, passing the");
System.out.println("given <argument>s.");
System.exit(1);
}
if (args.length < 2) {
System.err.println("Source file and/or class name missing; try \"-help\".");
System.exit(1);
}
// Get source file.
String sourceFileName = args[0];
// Get class name.
String className = args[1];
// Get arguments.
String[] arguments = new String[args.length - 2];
System.arraycopy(args, 2, arguments, 0, arguments.length);
// Compile the source file.
ClassLoader cl = new SimpleCompiler(sourceFileName, new FileInputStream(sourceFileName)).getClassLoader();
// Load the class.
Class c = cl.loadClass(className);
// Invoke the "public static main(String[])" method.
Method m = c.getMethod("main", new Class[] { String[].class });
m.invoke(null, new Object[] { arguments });
}
/**
* Equivalent to<pre>
* SimpleCompiler sc = new SimpleCompiler();
* sc.cook(optionalFileName, in);</pre>
*
* @see #SimpleCompiler()
* @see Cookable#cook(String, Reader)
*/
public
SimpleCompiler(String optionalFileName, Reader in) throws IOException, CompileException {
this.cook(optionalFileName, in);
}
/**
* Equivalent to<pre>
* SimpleCompiler sc = new SimpleCompiler();
* sc.cook(optionalFileName, is);</pre>
*
* @see #SimpleCompiler()
* @see Cookable#cook(String, InputStream)
*/
public
SimpleCompiler(String optionalFileName, InputStream is) throws IOException, CompileException {
this.cook(optionalFileName, is);
}
/**
* Equivalent to<pre>
* SimpleCompiler sc = new SimpleCompiler();
* sc.cook(fileName);</pre>
*
* @see #SimpleCompiler()
* @see Cookable#cookFile(String)
*/
public
SimpleCompiler(String fileName) throws IOException, CompileException {
this.cookFile(fileName);
}
/**
* Equivalent to<pre>
* SimpleCompiler sc = new SimpleCompiler();
* sc.setParentClassLoader(optionalParentClassLoader);
* sc.cook(scanner);</pre>
*
* @see #SimpleCompiler()
* @see #setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
SimpleCompiler(Scanner scanner, ClassLoader optionalParentClassLoader) throws IOException, CompileException {
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
public SimpleCompiler() {}
@Override public void
setParentClassLoader(ClassLoader optionalParentClassLoader) {
this.assertNotCooked();
this.parentClassLoader = (
optionalParentClassLoader != null
? optionalParentClassLoader
: Thread.currentThread().getContextClassLoader()
);
}
@Override public void
setDebuggingInformation(boolean debugSource, boolean debugLines, boolean debugVars) {
this.debugSource = debugSource;
this.debugLines = debugLines;
this.debugVars = debugVars;
}
/**
* Scans, parses and compiles a given compilation unit from the given {@link Reader}. After completion, {@link
* #getClassLoader()} returns a {@link ClassLoader} that allows for access to the compiled classes.
*/
@Override public final void
cook(String optionalFileName, Reader r) throws CompileException, IOException {
this.cook(new Scanner(optionalFileName, r));
}
/**
* Scans, parses and ompiles a given compilation unit from the given scanner. After completion, {@link
* #getClassLoader()} returns a {@link ClassLoader} that allows for access to the compiled classes.
*/
public void
cook(Scanner scanner) throws CompileException, IOException {
this.compileToClassLoader(new Parser(scanner).parseCompilationUnit());
}
/**
* Cooks this compilation unit directly.
*
* @see Cookable#cook(Reader)
*/
public void
cook(Java.CompilationUnit compilationUnit) throws CompileException {
// Compile the classes and load them.
this.compileToClassLoader(compilationUnit);
}
@Override public ClassLoader
getClassLoader() {
if (this.getClass() != SimpleCompiler.class) {
throw new IllegalStateException("Must not be called on derived instances");
}
if (this.result == null) throw new IllegalStateException("Must only be called after \"cook()\"");
return this.result;
}
/**
* Two {@link SimpleCompiler}s are regarded equal iff
* <ul>
* <li>Both are objects of the same class (e.g. both are {@link ScriptEvaluator}s)
* <li>Both generated functionally equal classes as seen by {@link ByteArrayClassLoader#equals(Object)}
* </ul>
*/
@Override public boolean
equals(Object o) {
if (!(o instanceof SimpleCompiler)) return false;
SimpleCompiler that = (SimpleCompiler) o;
if (this.getClass() != that.getClass()) return false;
if (this.result == null || that.result == null) {
throw new IllegalStateException("Equality can only be checked after cooking");
}
return this.result.equals(that.result);
}
@Override public int
hashCode() { return this.parentClassLoader.hashCode(); }
@Override public void
setCompileErrorHandler(ErrorHandler optionalCompileErrorHandler) {
this.optionalCompileErrorHandler = optionalCompileErrorHandler;
}
@Override public void
setWarningHandler(WarningHandler optionalWarningHandler) {
this.optionalWarningHandler = optionalWarningHandler;
}
/** Wraps a reflection {@link Class} in a {@link Java.Type} object. */
protected Java.Type
classToType(final Location location, final Class clazz) {
if (clazz == null) return null;
// IClass iClass;
// synchronized (this.classes) {
// iClass = (IClass) this.classes.get(clazz);
// if (iClass == null) {
// if (clazz.isPrimitive()) {
// if (clazz == byte.class) { iClass = IClass.BYTE; } else
// if (clazz == short.class) { iClass = IClass.SHORT; } else
// if (clazz == int.class) { iClass = IClass.INT; } else
// if (clazz == long.class) { iClass = IClass.LONG; } else
// if (clazz == float.class) { iClass = IClass.FLOAT; } else
// if (clazz == double.class) { iClass = IClass.DOUBLE; } else
// if (clazz == char.class) { iClass = IClass.CHAR; } else
// if (clazz == boolean.class) { iClass = IClass.BOOLEAN; } else
// if (clazz == void.class) { iClass = IClass.VOID; } else
// { throw new AssertionError(clazz); }
// } else {
// iClass = new ReflectionIClass(clazz, null);
// }
// this.classes.put(clazz, iClass);
// }
// }
// return new Java.SimpleType(location, iClass);
// Can't use a SimpleType here because the classLoaderIClassLoader is not yet set up. Instead, create a
// Type that lazily creates a delegate Type at COMPILE TIME.
return new Java.Type(location) {
private Java.SimpleType delegate;
@Override public String toString() { return this.getDelegate().toString(); }
@Override public void accept(AtomVisitor visitor) { this.getDelegate().accept((TypeVisitor) visitor); }
@Override public void accept(TypeVisitor visitor) { this.getDelegate().accept(visitor); }
private Type
getDelegate() {
if (this.delegate == null) {
IClass iClass;
try {
iClass = SimpleCompiler.this.classLoaderIClassLoader.loadIClass(
Descriptor.fromClassName(clazz.getName())
);
} catch (ClassNotFoundException ex) {
throw new JaninoRuntimeException("Loading IClass \"" + clazz.getName() + "\": " + ex);
}
if (iClass == null) {
throw new JaninoRuntimeException(
"Cannot load class '"
+ clazz.getName()
+ "' through the parent loader"
);
}
// Verify that the class loaders match.
IClass iClass2 = iClass;
Class class2 = clazz;
for (;;) {
IClass ct = iClass2.getComponentType();
if (ct == null) {
if (class2.getComponentType() != null) {
throw new JaninoRuntimeException("Array type/class inconsistency");
}
break;
}
iClass2 = ct;
class2 = class2.getComponentType();
if (class2 == null) throw new JaninoRuntimeException("Array type/class inconsistency");
}
if (class2.isPrimitive()) {
if (!iClass2.isPrimitive()) {
throw new JaninoRuntimeException("Primitive type/class inconsistency");
}
} else {
if (iClass2.isPrimitive()) {
throw new JaninoRuntimeException("Primitive type/class inconsistency");
}
if (((ReflectionIClass) iClass2).getClazz() != class2) {
throw new JaninoRuntimeException(
"Class '"
+ class2.getName()
+ "' was loaded through a different loader"
);
}
}
this.delegate = new Java.SimpleType(location, iClass);
}
return this.delegate;
}
};
}
// private final Map<Class, IClass> classes = new HashMap();
/** Converts an array of {@link Class}es into an array of{@link Java.Type}s. */
protected Java.Type[]
classesToTypes(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;
}
/**
* Compile the given compilation unit. (A "compilation unit" is typically the contents
* of a Java&trade; source file.)
*
* @param compilationUnit The parsed compilation unit
* @return The {@link ClassLoader} into which the compiled classes were defined
* @throws CompileException
*/
protected final ClassLoader
compileToClassLoader(Java.CompilationUnit compilationUnit) throws CompileException {
if (SimpleCompiler.DEBUG) {
UnparseVisitor.unparse(compilationUnit, new OutputStreamWriter(System.out));
}
this.classLoaderIClassLoader = new ClassLoaderIClassLoader(this.parentClassLoader);
// Compile compilation unit to class files.
UnitCompiler unitCompiler = new UnitCompiler(compilationUnit, this.classLoaderIClassLoader);
unitCompiler.setCompileErrorHandler(this.optionalCompileErrorHandler);
unitCompiler.setWarningHandler(this.optionalWarningHandler);
ClassFile[] classFiles = unitCompiler.compileUnit(this.debugSource, this.debugLines, this.debugVars);
// Convert the class files to bytes and store them in a Map.
final Map<String /*className*/, byte[] /*bytecode*/> classes = new HashMap();
for (ClassFile cf : classFiles) {
byte[] contents = cf.toByteArray();
if (SimpleCompiler.DEBUG) {
try {
Class disassemblerClass = Class.forName("de.unkrig.jdisasm.Disassembler");
disassemblerClass.getMethod(
"disasm",
new Class[] { InputStream.class }
).invoke(
disassemblerClass.newInstance(),
new Object[] { new ByteArrayInputStream(contents) }
);
} catch (Exception e) {
e.printStackTrace();
}
}
classes.put(cf.getThisClassName(), contents);
}
// Create a ClassLoader that loads the generated classes.
this.result = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
@Override public Object
run() {
return new ByteArrayClassLoader(
classes, // classes
SimpleCompiler.this.parentClassLoader // parent
);
}
});
return this.result;
}
/** @throws IllegalStateException This {@link Cookable} is already cooked */
protected void
assertNotCooked() {
if (this.classLoaderIClassLoader != null) throw new IllegalStateException("Already cooked");
}
}

View File

@ -0,0 +1,12 @@
The raw, inofficial list of TODOs:
* Implement '@SuppressWarnings'; supersede JANINO's old '-warn:...' feature
* Implement non-SOURCE annotations
* Implement annotation declarations
* Implement ENUMs
* Implement type arguments ('List<String> l;')
* Implement type parameters ('class MyClass<T extends InputStream> { ... }')
* Enhanced FOR loop
Recently implemented:
* ASSERT (simplified, ASSERTions are ALWAYS enabled, as if '-ea' were set)

View File

@ -0,0 +1,43 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
/**
* Represents a problem that occurred while unescaping a unicode escape
* sequence through a {@link org.codehaus.janino.UnicodeUnescapeReader}.
*/
public
class UnicodeUnescapeException extends RuntimeException {
private static final long serialVersionUID = -8965331941165671541L;
public
UnicodeUnescapeException(String message) { super(message); }
public
UnicodeUnescapeException(String message, Throwable cause) { super(message, cause); }
}

View File

@ -0,0 +1,110 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;
/**
* A {@link FilterReader} that unescapes the "Unicode Escapes" as described in JLS7 3.10.6.
* <p>
* Notice that it is possible to formulate invalid escape sequences, e.g. "&#92;u123g" ("g" is not a valid hex
* character). This is handled by throwing a {@link java.lang.RuntimeException}-derived {@link
* org.codehaus.janino.UnicodeUnescapeException}.
*/
public
class UnicodeUnescapeReader extends FilterReader {
public
UnicodeUnescapeReader(Reader in) { super(in); }
/**
* Override {@link FilterReader#read()}.
*
* @throws UnicodeUnescapeException Invalid escape sequence encountered
*/
@Override public int
read() throws IOException {
int c;
// Read next character.
if (this.unreadChar == -1) {
c = this.in.read();
} else {
c = this.unreadChar;
this.unreadChar = -1;
}
// Check for backslash-u escape sequence, preceeded with an even number
// of backslashes.
if (c != '\\' || this.oddPrecedingBackslashes) {
this.oddPrecedingBackslashes = false;
return c;
}
// Read one character ahead and check if it is a "u".
c = this.in.read();
if (c != 'u') {
this.unreadChar = c;
this.oddPrecedingBackslashes = true;
return '\\';
}
// Skip redundant "u"s.
do {
c = this.in.read();
if (c == -1) throw new UnicodeUnescapeException("Incomplete escape sequence");
} while (c == 'u');
// Decode escape sequence.
char[] ca = new char[4];
ca[0] = (char) c;
if (this.in.read(ca, 1, 3) != 3) throw new UnicodeUnescapeException("Incomplete escape sequence");
try {
return 0xffff & Integer.parseInt(new String(ca), 16);
} catch (NumberFormatException ex) {
throw new UnicodeUnescapeException("Invalid escape sequence \"\\u" + new String(ca) + "\"", ex);
}
}
/** Overrides {@link FilterReader#read(char[], int, int)}. */
@Override public int
read(char[] cbuf, int off, int len) throws IOException {
if (len == 0) return 0;
int res = 0;
do {
int c = this.read();
if (c == -1) break;
cbuf[off++] = (char) c;
} while (++res < len);
return res == 0 ? -1 : res;
}
private int unreadChar = -1; // -1 == none
private boolean oddPrecedingBackslashes;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,274 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
/** Basis for the "visitor" pattern as described in "Gamma, Helm, Johnson, Vlissides: Design Patterns". */
public
class Visitor {
/**
* The union of {@link ImportVisitor}, {@link TypeDeclarationVisitor}, {@link TypeBodyDeclarationVisitor} and
* {@link AtomVisitor}.
*/
public
interface ComprehensiveVisitor
extends ImportVisitor, TypeDeclarationVisitor, TypeBodyDeclarationVisitor, BlockStatementVisitor, AtomVisitor,
ElementValueVisitor { // SUPPRESS CHECKSTYLE WrapAndIndent
}
/** The visitor for all kinds of {@link Java.CompilationUnit.ImportDeclaration}s. */
public
interface ImportVisitor {
/** Invoked by {@link Java.CompilationUnit.SingleTypeImportDeclaration#accept(Visitor.ImportVisitor)} */
void visitSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid);
/** Invoked by {@link Java.CompilationUnit.TypeImportOnDemandDeclaration#accept(Visitor.ImportVisitor)} */
void visitTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd);
/** Invoked by {@link Java.CompilationUnit.SingleStaticImportDeclaration#accept(Visitor.ImportVisitor)} */
void visitSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration ssid);
/** Invoked by {@link Java.CompilationUnit.StaticImportOnDemandDeclaration#accept(Visitor.ImportVisitor)} */
void visitStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd);
}
/** The visitor for all kinds of {@link Java.TypeDeclaration}s. */
public
interface TypeDeclarationVisitor {
/** Invoked by {@link Java.AnonymousClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
void visitAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd);
/** Invoked by {@link Java.LocalClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
void visitLocalClassDeclaration(Java.LocalClassDeclaration lcd);
/** Invoked by {@link Java.PackageMemberClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
void visitPackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd);
/** Invoked by {@link Java.MemberInterfaceDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid);
/** Invoked by {@link Java.PackageMemberInterfaceDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
void visitPackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid);
/** Invoked by {@link Java.MemberClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd);
}
/** The visitor for all kinds of {@link Java.FunctionDeclarator}s. */
public
interface FunctionDeclaratorVisitor {
/** Invoked by {@link Java.ConstructorDeclarator#accept(Visitor.TypeBodyDeclarationVisitor)} */
void visitConstructorDeclarator(Java.ConstructorDeclarator cd);
/** Invoked by {@link Java.MethodDeclarator#accept(Visitor.TypeBodyDeclarationVisitor)} */
void visitMethodDeclarator(Java.MethodDeclarator md);
}
/**
* The visitor for all kinds of {@link Java.TypeBodyDeclaration}s (declarations that may appear in the body of a
* type declaration).
*/
public
interface TypeBodyDeclarationVisitor extends FunctionDeclaratorVisitor {
/** Invoked by {@link Java.MemberInterfaceDeclaration#accept(Visitor.TypeBodyDeclarationVisitor)} */
void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid);
/** Invoked by {@link Java.MemberClassDeclaration#accept(Visitor.TypeBodyDeclarationVisitor)} */
void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd);
/** Invoked by {@link Java.Initializer#accept(Visitor.TypeBodyDeclarationVisitor)} */
void visitInitializer(Java.Initializer i);
/** Invoked by {@link Java.FieldDeclaration#accept(Visitor.TypeBodyDeclarationVisitor)} */
void visitFieldDeclaration(Java.FieldDeclaration fd);
}
/** The visitor for all kinds of {@link Java.BlockStatement}s (statements that may appear with a block). */
public
interface BlockStatementVisitor {
/** Invoked by {@link Java.Initializer#accept(Visitor.BlockStatementVisitor)} */
void visitInitializer(Java.Initializer i);
/** Invoked by {@link Java.FieldDeclaration#accept(Visitor.BlockStatementVisitor)} */
void visitFieldDeclaration(Java.FieldDeclaration fd);
/** Invoked by {@link Java.LabeledStatement#accept(Visitor.BlockStatementVisitor)} */
void visitLabeledStatement(Java.LabeledStatement ls);
/** Invoked by {@link Java.Block#accept(Visitor.BlockStatementVisitor)} */
void visitBlock(Java.Block b);
/** Invoked by {@link Java.ExpressionStatement#accept(Visitor.BlockStatementVisitor)} */
void visitExpressionStatement(Java.ExpressionStatement es);
/** Invoked by {@link Java.IfStatement#accept(Visitor.BlockStatementVisitor)} */
void visitIfStatement(Java.IfStatement is);
/** Invoked by {@link Java.ForStatement#accept(Visitor.BlockStatementVisitor)} */
void visitForStatement(Java.ForStatement fs);
/** Invoked by {@link Java.ForEachStatement#accept(Visitor.BlockStatementVisitor)} */
void visitForEachStatement(Java.ForEachStatement forEachStatement);
/** Invoked by {@link Java.WhileStatement#accept(Visitor.BlockStatementVisitor)} */
void visitWhileStatement(Java.WhileStatement ws);
/** Invoked by {@link Java.TryStatement#accept(Visitor.BlockStatementVisitor)} */
void visitTryStatement(Java.TryStatement ts);
/** Invoked by {@link Java.SwitchStatement#accept(Visitor.BlockStatementVisitor)} */
void visitSwitchStatement(Java.SwitchStatement ss);
/** Invoked by {@link Java.SynchronizedStatement#accept(Visitor.BlockStatementVisitor)} */
void visitSynchronizedStatement(Java.SynchronizedStatement ss);
/** Invoked by {@link Java.DoStatement#accept(Visitor.BlockStatementVisitor)} */
void visitDoStatement(Java.DoStatement ds);
/** Invoked by {@link Java.LocalVariableDeclarationStatement#accept(Visitor.BlockStatementVisitor)} */
void visitLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds);
/** Invoked by {@link Java.ReturnStatement#accept(Visitor.BlockStatementVisitor)} */
void visitReturnStatement(Java.ReturnStatement rs);
/** Invoked by {@link Java.ThrowStatement#accept(Visitor.BlockStatementVisitor)} */
void visitThrowStatement(Java.ThrowStatement ts);
/** Invoked by {@link Java.BreakStatement#accept(Visitor.BlockStatementVisitor)} */
void visitBreakStatement(Java.BreakStatement bs);
/** Invoked by {@link Java.ContinueStatement#accept(Visitor.BlockStatementVisitor)} */
void visitContinueStatement(Java.ContinueStatement cs);
/** Invoked by {@link Java.AssertStatement#accept(Visitor.BlockStatementVisitor)} */
void visitAssertStatement(Java.AssertStatement as);
/** Invoked by {@link Java.EmptyStatement#accept(Visitor.BlockStatementVisitor)} */
void visitEmptyStatement(Java.EmptyStatement es);
/** Invoked by {@link Java.LocalClassDeclarationStatement#accept(Visitor.BlockStatementVisitor)} */
void visitLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds);
/** Invoked by {@link Java.AlternateConstructorInvocation#accept(Visitor.BlockStatementVisitor)} */
void visitAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci);
/** Invoked by {@link Java.SuperConstructorInvocation#accept(Visitor.BlockStatementVisitor)} */
void visitSuperConstructorInvocation(Java.SuperConstructorInvocation sci);
}
/** The visitor for all kinds of {@link Java.Atom}s. */
public
interface AtomVisitor extends RvalueVisitor, TypeVisitor {
/** Invoked by {@link Java.Package#accept(Visitor.AtomVisitor)}. */
void visitPackage(Java.Package p);
}
/** The visitor for all kinds of {@link Java.Type}s. */
public
interface TypeVisitor {
/** Invoked by {@link Java.ArrayType#accept(Visitor.TypeVisitor)} */
void visitArrayType(Java.ArrayType at);
/** Invoked by {@link Java.BasicType#accept(Visitor.TypeVisitor)} */
void visitBasicType(Java.BasicType bt);
/** Invoked by {@link Java.ReferenceType#accept(Visitor.TypeVisitor)} */
void visitReferenceType(Java.ReferenceType rt);
/** Invoked by {@link Java.RvalueMemberType#accept(Visitor.TypeVisitor)} */
void visitRvalueMemberType(Java.RvalueMemberType rmt);
/** Invoked by {@link Java.SimpleType#accept(Visitor.TypeVisitor)} */
void visitSimpleType(Java.SimpleType st);
}
/** The visitor for all kinds of {@link Java.Rvalue}s. */
public
interface RvalueVisitor extends LvalueVisitor {
/** Invoked by {@link Java.ArrayLength#accept(Visitor.RvalueVisitor)} */
void visitArrayLength(Java.ArrayLength al);
/** Invoked by {@link Java.Assignment#accept(Visitor.RvalueVisitor)} */
void visitAssignment(Java.Assignment a);
/** Invoked by {@link Java.UnaryOperation#accept(Visitor.RvalueVisitor)} */
void visitUnaryOperation(Java.UnaryOperation uo);
/** Invoked by {@link Java.BinaryOperation#accept(Visitor.RvalueVisitor)} */
void visitBinaryOperation(Java.BinaryOperation bo);
/** Invoked by {@link Java.Cast#accept(Visitor.RvalueVisitor)} */
void visitCast(Java.Cast c);
/** Invoked by {@link Java.ClassLiteral#accept(Visitor.RvalueVisitor)} */
void visitClassLiteral(Java.ClassLiteral cl);
/** Invoked by {@link Java.ConditionalExpression#accept(Visitor.RvalueVisitor)} */
void visitConditionalExpression(Java.ConditionalExpression ce);
/** Invoked by {@link Java.Crement#accept(Visitor.RvalueVisitor)} */
void visitCrement(Java.Crement c);
/** Invoked by {@link Java.Instanceof#accept(Visitor.RvalueVisitor)} */
void visitInstanceof(Java.Instanceof io);
/** Invoked by {@link Java.MethodInvocation#accept(Visitor.RvalueVisitor)} */
void visitMethodInvocation(Java.MethodInvocation mi);
/** Invoked by {@link Java.SuperclassMethodInvocation#accept(Visitor.RvalueVisitor)} */
void visitSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi);
/** Invoked by {@link Java.IntegerLiteral#accept(Visitor.RvalueVisitor)} */
void visitIntegerLiteral(Java.IntegerLiteral il);
/** Invoked by {@link Java.FloatingPointLiteral#accept(Visitor.RvalueVisitor)} */
void visitFloatingPointLiteral(Java.FloatingPointLiteral fpl);
/** Invoked by {@link Java.BooleanLiteral#accept(Visitor.RvalueVisitor)} */
void visitBooleanLiteral(Java.BooleanLiteral bl);
/** Invoked by {@link Java.CharacterLiteral#accept(Visitor.RvalueVisitor)} */
void visitCharacterLiteral(Java.CharacterLiteral cl);
/** Invoked by {@link Java.StringLiteral#accept(Visitor.RvalueVisitor)} */
void visitStringLiteral(Java.StringLiteral sl);
/** Invoked by {@link Java.NullLiteral#accept(Visitor.RvalueVisitor)} */
void visitNullLiteral(Java.NullLiteral nl);
/** Invoked by {@link Java.SimpleConstant#accept(Visitor.RvalueVisitor)} */
void visitSimpleConstant(Java.SimpleConstant sl);
/** Invoked by {@link Java.NewAnonymousClassInstance#accept(Visitor.RvalueVisitor)} */
void visitNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci);
/** Invoked by {@link Java.NewArray#accept(Visitor.RvalueVisitor)} */
void visitNewArray(Java.NewArray na);
/** Invoked by {@link Java.NewInitializedArray#accept(Visitor.RvalueVisitor)} */
void visitNewInitializedArray(Java.NewInitializedArray nia);
/** Invoked by {@link Java.NewClassInstance#accept(Visitor.RvalueVisitor)} */
void visitNewClassInstance(Java.NewClassInstance nci);
/** Invoked by {@link Java.ParameterAccess#accept(Visitor.RvalueVisitor)} */
void visitParameterAccess(Java.ParameterAccess pa);
/** Invoked by {@link Java.QualifiedThisReference#accept(Visitor.RvalueVisitor)} */
void visitQualifiedThisReference(Java.QualifiedThisReference qtr);
/** Invoked by {@link Java.ArrayLength#accept(Visitor.RvalueVisitor)} */
void visitThisReference(Java.ThisReference tr);
}
/** The visitor for all kinds of {@link Java.Lvalue}s. */
public
interface LvalueVisitor {
/** Invoked by {@link Java.AmbiguousName#accept(Visitor.LvalueVisitor)} */
void visitAmbiguousName(Java.AmbiguousName an);
/** Invoked by {@link Java.ArrayAccessExpression#accept(Visitor.LvalueVisitor)} */
void visitArrayAccessExpression(Java.ArrayAccessExpression aae);
/** Invoked by {@link Java.FieldAccess#accept(Visitor.LvalueVisitor)} */
void visitFieldAccess(Java.FieldAccess fa);
/** Invoked by {@link Java.FieldAccessExpression#accept(Visitor.LvalueVisitor)} */
void visitFieldAccessExpression(Java.FieldAccessExpression fae);
/** Invoked by {@link Java.SuperclassFieldAccessExpression#accept(Visitor.LvalueVisitor)} */
void visitSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae);
/** Invoked by {@link Java.LocalVariableAccess#accept(Visitor.LvalueVisitor)} */
void visitLocalVariableAccess(Java.LocalVariableAccess lva);
/** Invoked by {@link Java.ParenthesizedExpression#accept(Visitor.LvalueVisitor)} */
void visitParenthesizedExpression(Java.ParenthesizedExpression pe);
}
/** The visitor for all kinds of {@link Java.Annotation}s. */
public
interface AnnotationVisitor {
/** Invoked by {@link Java.MarkerAnnotation#accept(Visitor.AnnotationVisitor)} */
void visitMarkerAnnotation(Java.MarkerAnnotation ma);
/** Invoked by {@link Java.NormalAnnotation#accept(Visitor.AnnotationVisitor)} */
void visitNormalAnnotation(Java.NormalAnnotation na);
/** Invoked by {@link Java.SingleElementAnnotation#accept(Visitor.AnnotationVisitor)} */
void visitSingleElementAnnotation(Java.SingleElementAnnotation sea);
}
/** The visitor for all kinds of {@link Java.ElementValue}s. */
public
interface ElementValueVisitor extends RvalueVisitor, AnnotationVisitor {
/** Invoked by {@link Java.ElementValueArrayInitializer#accept(Visitor.ElementValueVisitor)} */
void visitElementValueArrayInitializer(Java.ElementValueArrayInitializer evai);
}
/** The visitor for all kinds of {@link Java.TypeArgument}s. */
public
interface TypeArgumentVisitor {
/** Invoked by {@link Java.Wildcard#accept(Visitor.TypeArgumentVisitor)} */
void visitWildcard(Java.Wildcard w);
/** Invoked by {@link Java.ReferenceType#accept(Visitor.TypeArgumentVisitor)} */
void visitReferenceType(Java.ReferenceType rt);
/** Invoked by {@link Java.ArrayType#accept(Visitor.TypeArgumentVisitor)} */
void visitArrayType(Java.ArrayType arrayType);
}
}

View File

@ -0,0 +1,35 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2013, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The classes in this package pose the core of the Janino Java<sup>TM</sup> compiler.
* <p>
* The package comprises a scanner ({@link org.codehaus.janino.Scanner}, a parser ({@link org.codehaus.janino.Parser})
* and a class file library. The parser builds a syntax tree from the "Java.*" classes that represents the parsed code.
* The {@link org.codehaus.janino.UnitCompiler#compileUnit} method compiles this syntax tree into a {@link
* org.codehaus.janino.util.ClassFile} object, which can write Java<sup>TM</sup> bytecode to an "OutputStream".
*/
package org.codehaus.janino;

View File

@ -0,0 +1,101 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.samples;
import java.io.FileReader;
import java.io.IOException;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.janino.Java;
import org.codehaus.janino.Parser;
import org.codehaus.janino.Scanner;
import org.codehaus.janino.util.Traverser;
/**
* An example application for the {@link org.codehaus.janino.util.Traverser}:
* Reads, scans and parses the files named on the command line and counts
* several kinds of declarations.
*/
public
class DeclarationCounter extends Traverser {
public static void // SUPPRESS CHECKSTYLE JavadocMethod
main(String[] args) throws CompileException, IOException {
DeclarationCounter dc = new DeclarationCounter();
for (String fileName : args) {
// Parse each compilation unit.
FileReader r = new FileReader(fileName);
Java.CompilationUnit cu;
try {
cu = new Parser(new Scanner(fileName, r)).parseCompilationUnit();
} finally {
r.close();
}
// Traverse it and count declarations.
dc.traverseCompilationUnit(cu);
}
System.out.println("Class declarations: " + dc.classDeclarationCount);
System.out.println("Interface declarations: " + dc.interfaceDeclarationCount);
System.out.println("Fields: " + dc.fieldCount);
System.out.println("Local variables: " + dc.localVariableCount);
}
// Count class declarations.
@Override public void
traverseClassDeclaration(Java.ClassDeclaration cd) {
++this.classDeclarationCount;
super.traverseClassDeclaration(cd);
}
private int classDeclarationCount;
// Count interface declarations.
@Override public void
traverseInterfaceDeclaration(Java.InterfaceDeclaration id) {
++this.interfaceDeclarationCount;
super.traverseInterfaceDeclaration(id);
}
private int interfaceDeclarationCount;
// Count fields.
@Override public void
traverseFieldDeclaration(Java.FieldDeclaration fd) {
this.fieldCount += fd.variableDeclarators.length;
super.traverseFieldDeclaration(fd);
}
private int fieldCount;
// Count local variables.
@Override public void
traverseLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
this.localVariableCount += lvds.variableDeclarators.length;
super.traverseLocalVariableDeclarationStatement(lvds);
}
private int localVariableCount;
}

View File

@ -0,0 +1,28 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2013, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** Sample applications for the Janino Java<sup>TM</sup> compiler. */
package org.codehaus.janino.samples;

View File

@ -0,0 +1,257 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.tools;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* Example for object allocation statistics:
*
* java -Xrunhprof:heap=sites,monitor=n,cutoff=0,depth=4 MyClass
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public final
class HprofScrubber {
private HprofScrubber() {}
private static
class Site {
public final int allocatedBytes;
public final int allocatedObjects;
public final int traceNumber;
public final String className;
public
Site(int allocatedBytes, int allocatedObjects, int traceNumber, String className) {
this.allocatedBytes = allocatedBytes;
this.allocatedObjects = allocatedObjects;
this.traceNumber = traceNumber;
this.className = className;
}
}
private static
class Sample {
public final int count;
public final int traceNumber;
public
Sample(int count, int traceNumber) {
this.count = count;
this.traceNumber = traceNumber;
}
}
public static void // SUPPRESS CHECKSTYLE JavadocMethod
main(String[] args) throws Exception {
String fileName = args.length == 0 ? "java.hprof.txt" : args[0];
BufferedReader br = new BufferedReader(new FileReader(fileName));
try {
Map<Integer /*number*/, String[] /*stackFrames*/> traces = new HashMap();
List<Site> sites = new ArrayList();
List<Sample> samples = new ArrayList();
String s = br.readLine();
while (s != null) {
if (s.startsWith("SITES BEGIN")) {
br.readLine();
br.readLine();
for (;;) {
s = br.readLine();
if (s.startsWith("SITES END")) break;
StringTokenizer st = new StringTokenizer(s);
st.nextToken(); // rank
st.nextToken(); // percent self
st.nextToken(); // percent accum
st.nextToken(); // live bytes
st.nextToken(); // live objects
sites.add(new Site(
Integer.parseInt(st.nextToken()), // allocatedBytes
Integer.parseInt(st.nextToken()), // allocatedObjects
Integer.parseInt(st.nextToken()), // traceNumber
st.nextToken() // className
));
}
} else
if (s.startsWith("TRACE ") && s.endsWith(":")) {
int traceNumber = Integer.parseInt(s.substring(6, s.length() - 1));
List<String> l = new ArrayList();
for (;;) {
s = br.readLine();
if (!s.startsWith("\t")) break;
l.add(s.substring(1));
}
traces.put(
new Integer(traceNumber),
(String[]) l.toArray(new String[l.size()])
);
} else
if (s.startsWith("CPU SAMPLES BEGIN")) {
br.readLine();
for (;;) {
s = br.readLine();
if (s.startsWith("CPU SAMPLES END")) break;
StringTokenizer st = new StringTokenizer(s);
st.nextToken(); // rank
st.nextToken(); // percent self
st.nextToken(); // percent accum
int count = Integer.parseInt(st.nextToken());
if (count == 0) continue;
int trace = Integer.parseInt(st.nextToken());
samples.add(new Sample(count, trace));
}
} else {
s = br.readLine();
}
}
HprofScrubber.dumpSites((Site[]) sites.toArray(new Site[sites.size()]), traces);
HprofScrubber.dumpSamples((Sample[]) samples.toArray(new Sample[samples.size()]), traces);
} finally {
try { br.close(); } catch (IOException e) {}
}
}
private static void
dumpSites(Site[] ss, Map<Integer, String[]> traces) {
Arrays.sort(ss, new Comparator() {
@Override public int
compare(Object o1, Object o2) { return ((Site) o2).allocatedBytes - ((Site) o1).allocatedBytes; }
});
int totalAllocatedBytes = 0, totalAllocatedObjects = 0;
for (Site site : ss) {
totalAllocatedBytes += site.allocatedBytes;
totalAllocatedObjects += site.allocatedObjects;
}
System.out.println(" percent alloc'ed");
System.out.println("rank self accum bytes objects class name");
System.out.println("Total: " + totalAllocatedBytes + " " + totalAllocatedObjects);
double accumulatedPercentage = 0.0;
MessageFormat mf = new MessageFormat(
"{0,number,00000} {1,number,00.00}% {2,number,00.00}% {3,number,000000000} {4,number,000000000} {5}"
);
for (int i = 0; i < ss.length; ++i) {
Site site = ss[i];
double selfPercentage = 100.0 * ((double) site.allocatedBytes / (double) totalAllocatedBytes);
accumulatedPercentage += selfPercentage;
// System.out.println(
// (i + 1)
// + " "
// + selfPercentage
// + "% "
// + accumulatedPercentage
// + "% "
// + site.allocatedBytes
// + " "
// + site.allocatedObjects
// + " "
// + site.className
// );
System.out.println(mf.format(
new Object[] {
new Integer(i + 1),
new Double(selfPercentage),
new Double(accumulatedPercentage),
new Integer(site.allocatedBytes),
new Integer(site.allocatedObjects),
site.className
},
new StringBuffer(),
new FieldPosition(0)
));
String[] stackFrames = (String[]) traces.get(new Integer(site.traceNumber));
if (stackFrames != null) {
for (String stackFrame : stackFrames) {
System.out.println(" " + stackFrame);
}
}
}
}
private static void
dumpSamples(Sample[] ss, Map<Integer, String[]> traces) {
int totalCount = 0;
for (Sample s : ss) totalCount += s.count;
System.out.println(" percent");
System.out.println("rank self accum count");
System.out.println("Total: " + totalCount);
double accumulatedPercentage = 0.0;
MessageFormat mf = new MessageFormat(
"{0,number,00000} {1,number,00.00}% {2,number,00.00}% {3,number,000000000}"
);
for (int i = 0; i < ss.length; ++i) {
Sample sample = ss[i];
double selfPercentage = 100.0 * ((double) sample.count / (double) totalCount);
accumulatedPercentage += selfPercentage;
// System.out.println(
// (i + 1)
// + " "
// + selfPercentage
// + "% "
// + accumulatedPercentage
// + "% "
// + sample.count
// + " "
// + sample.traceNumber
// );
System.out.println(mf.format(
new Object[] {
new Integer(i + 1),
new Double(selfPercentage),
new Double(accumulatedPercentage),
new Integer(sample.count)
},
new StringBuffer(),
new FieldPosition(0)
));
String[] stackFrames = (String[]) traces.get(new Integer(sample.traceNumber));
if (stackFrames != null) {
for (String stackFrame : stackFrames) System.out.println(" " + stackFrame);
}
}
}
}

View File

@ -0,0 +1,714 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.tools;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.CompilerFactoryFactory;
import org.codehaus.commons.compiler.ICompilerFactory;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.codehaus.commons.compiler.UncheckedCompileException;
import org.codehaus.janino.Descriptor;
import org.codehaus.janino.ExpressionEvaluator;
import org.codehaus.janino.IClass;
import org.codehaus.janino.IClassLoader;
import org.codehaus.janino.Java;
import org.codehaus.janino.Java.CompilationUnit;
import org.codehaus.janino.Parser;
import org.codehaus.janino.Scanner;
import org.codehaus.janino.UnitCompiler;
import org.codehaus.janino.util.Benchmark;
import org.codehaus.janino.util.ClassFile;
import org.codehaus.janino.util.StringPattern;
import org.codehaus.janino.util.Traverser;
import org.codehaus.janino.util.enumerator.Enumerator;
import org.codehaus.janino.util.iterator.DirectoryIterator;
import org.codehaus.janino.util.resource.PathResourceFinder;
/**
* Reads a set of compilation units from the file system and searches it for specific
* Java&trade; constructs, e.g. invocations of a particular method.
*
* Usage:
* <pre>
* java org.codehaus.janino.JGrep \
* [ -dirs <i>directory-name-patterns</i> ] \
* [ -files <i>file-name-patterns</i> ] \
* { <i>directory-path</i> } \
* -method-invocation <i>class.method(arg-types)</i>
* java org.codehaus.janino.JGrep -help
* </pre>
*
* If "-dirs" is not given, then all <i>directory-path</i>es are scanned for files.
* The <i>directory-name-patterns</i> work as described in
* {@link org.codehaus.janino.util.StringPattern#parseCombinedPattern(String)}.
* <p>
* If "-files" is not given, then all files ending in ".java" are read. The
* <i>file-name-patterns</i> work as described in
* {@link org.codehaus.janino.util.StringPattern#parseCombinedPattern(String)}.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public // SUPPRESS CHECKSTYLE HideUtilityClassConstructor
class JGrep {
private static final boolean DEBUG = false;
private final List<UnitCompiler> parsedCompilationUnits = new ArrayList();
/** Command line interface. */
public static void
main(String[] args) {
int idx = 0;
StringPattern[] directoryNamePatterns = StringPattern.PATTERNS_ALL;
StringPattern[] fileNamePatterns = new StringPattern[] { new StringPattern("*.java") };
File[] classPath = new File[] { new File(".") };
File[] optionalExtDirs = null;
File[] optionalBootClassPath = null;
String optionalCharacterEncoding = null;
boolean verbose = false;
for (; idx < args.length; ++idx) {
String arg = args[idx];
if (arg.charAt(0) != '-') break;
if ("-dirs".equals(arg)) {
directoryNamePatterns = StringPattern.parseCombinedPattern(args[++idx]);
} else
if ("-files".equals(arg)) {
fileNamePatterns = StringPattern.parseCombinedPattern(args[++idx]);
} else
if ("-classpath".equals(arg)) {
classPath = PathResourceFinder.parsePath(args[++idx]);
} else
if ("-extdirs".equals(arg)) {
optionalExtDirs = PathResourceFinder.parsePath(args[++idx]);
} else
if ("-bootclasspath".equals(arg)) {
optionalBootClassPath = PathResourceFinder.parsePath(args[++idx]);
} else
if ("-encoding".equals(arg)) {
optionalCharacterEncoding = args[++idx];
} else
if ("-verbose".equals(arg)) {
verbose = true;
} else
if ("-help".equals(arg)) {
for (String s : JGrep.USAGE) System.out.println(s);
System.exit(1);
} else
{
System.err.println("Unexpected command-line argument \"" + arg + "\", try \"-help\".");
System.exit(1);
return; /* NEVER REACHED */
}
}
// { directory-path }
File[] rootDirectories;
{
int first = idx;
for (; idx < args.length && args[idx].charAt(0) != '-'; ++idx);
if (idx == first) {
System.err.println("No <directory-path>es given, try \"-help\".");
System.exit(1);
return; /* NEVER REACHED */
}
rootDirectories = new File[idx - first];
for (int i = first; i < idx; ++i) rootDirectories[i - first] = new File(args[i]);
}
// Create the JGrep object.
final JGrep jGrep = new JGrep(
classPath,
optionalExtDirs,
optionalBootClassPath,
optionalCharacterEncoding,
verbose
);
List<MethodInvocationTarget> mits = new ArrayList();
for (; idx < args.length; ++idx) {
String arg = args[idx];
if ("-method-invocation".equals(arg)) {
MethodInvocationTarget mit;
try {
mit = JGrep.parseMethodInvocationPattern(args[++idx]);
} catch (Exception ex) {
System.err.println("Parsing method invocation pattern \"" + args[idx] + "\": " + ex.getMessage());
System.exit(1);
return; /* NEVER REACHED */
}
while (idx < args.length - 1) {
arg = args[idx + 1];
if (arg.startsWith("predicate:")) {
String predicateExpression = arg.substring(10);
try {
IExpressionEvaluator ee = new ExpressionEvaluator();
ee.setClassName(JGrep.class.getName() + "PE");
mit.predicates.add((MethodInvocationPredicate) ee.createFastEvaluator(
predicateExpression,
MethodInvocationPredicate.class,
new String[] { "uc", "invocation", "method" }
));
} catch (Exception ex) {
System.err.println(
"Compiling predicate expression \""
+ predicateExpression
+ "\": "
+ ex.getMessage()
);
System.exit(1);
return; /* NEVER REACHED */
}
} else
if (arg.startsWith("action:")) {
String action = arg.substring(7);
try {
mit.actions.add(Action.getMethodInvocationAction(action));
} catch (Exception ex) {
System.err.println(
"Compiling method invocation action \""
+ action
+ "\": "
+ ex.getMessage()
);
System.exit(1);
return; /* NEVER REACHED */
}
} else
{
break;
}
++idx;
}
mits.add(mit);
} else
{
System.err.println("Unexpected command-line argument \"" + arg + "\", try \"-help\".");
System.exit(1);
return; /* NEVER REACHED */
}
}
// JGrep the root directories.
try {
jGrep.jGrep(
rootDirectories,
directoryNamePatterns,
fileNamePatterns,
mits // methodInvocationTargets
);
} catch (Exception e) {
System.err.println(e.toString());
System.exit(1);
}
}
private static final
class Action extends Enumerator {
private Action(String name) { super(name); }
static MethodInvocationAction
getMethodInvocationAction(String action) throws CompileException {
if ("print-location-and-match".equals(action)) {
return new MethodInvocationAction() {
@Override public void
execute(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method) {
System.out.println(invocation.getLocation() + ": " + method);
}
};
} else
if ("print-location".equals(action)) {
return new MethodInvocationAction() {
@Override public void
execute(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method) {
System.out.println(invocation.getLocation());
}
};
} else
{
ICompilerFactory cf;
try {
cf = CompilerFactoryFactory.getDefaultCompilerFactory();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage()); // SUPPRESS CHECKSTYLE AvoidHidingCause
}
return (MethodInvocationAction) cf.newScriptEvaluator().createFastEvaluator(
action, // script
MethodInvocationAction.class, // interfaceToImplement
new String[] { "uc", "invocation", "method" } // parameterNames
);
}
}
}
private static MethodInvocationTarget
parseMethodInvocationPattern(String mip) throws CompileException, IOException {
MethodInvocationTarget mit = new MethodInvocationTarget();
Scanner scanner = new Scanner(null, new StringReader(mip));
Parser parser = new Parser(scanner);
for (;;) {
String s = JGrep.readIdentifierPattern(parser);
if (parser.peekRead("(")) {
mit.methodNamePattern = s;
List<String> l = new ArrayList();
if (!parser.peekRead(")")) {
for (;;) {
l.add(JGrep.readIdentifierPattern(parser));
if (parser.peek(")")) break;
parser.read(",");
}
}
mit.optionalArgumentTypeNamePatterns = (String[]) l.toArray(new String[l.size()]);
return mit;
} else
if (parser.peekRead(".")) {
if (mit.optionalClassNamePattern == null) {
mit.optionalClassNamePattern = s;
} else
{
mit.optionalClassNamePattern += '.' + s;
}
} else
if (parser.peekEof()) {
mit.methodNamePattern = s;
return mit;
}
}
}
private static String
readIdentifierPattern(Parser p) throws CompileException, IOException {
StringBuilder sb = new StringBuilder();
if (p.peekRead("*")) {
sb.append('*');
} else
{
sb.append(p.readIdentifier());
}
for (;;) {
if (p.peekRead("*")) {
sb.append('*');
} else
if (p.peekIdentifier() != null) {
sb.append(p.readIdentifier());
} else
{
return sb.toString();
}
}
}
private static
class MethodInvocationTarget {
String optionalClassNamePattern;
String methodNamePattern;
String[] optionalArgumentTypeNamePatterns;
List<MethodInvocationPredicate> predicates = new ArrayList();
List<MethodInvocationAction> actions = new ArrayList();
void
apply(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method) throws CompileException {
// Verify that the class declaring the invoked method matches.
if (this.optionalClassNamePattern != null) {
if (!JGrep.typeMatches(
this.optionalClassNamePattern,
Descriptor.toClassName(method.getDeclaringIClass().getDescriptor())
)) return;
}
// Verify that the name of the invoked method matches.
if (!new StringPattern(this.methodNamePattern).matches(method.getName())) return;
// Verify that the parameter count and types of the invoked method match.
IClass[] fpts = method.getParameterTypes();
if (this.optionalArgumentTypeNamePatterns != null) {
String[] atnps = this.optionalArgumentTypeNamePatterns;
if (atnps.length != fpts.length) return;
for (int i = 0; i < atnps.length; ++i) {
if (!new StringPattern(atnps[i]).matches(Descriptor.toClassName(fpts[i].getDescriptor()))) return;
}
}
// Verify that all predicates (JANINO expressions) return TRUE.
for (MethodInvocationPredicate mip : this.predicates) {
try {
if (!mip.evaluate(uc, invocation, method)) return;
} catch (Exception ex) {
return; // Treat exception as a "false" predicate.
}
}
// Now that all checks were successful, execute all method invocation actions.
for (MethodInvocationAction mia : this.actions) {
try {
mia.execute(uc, invocation, method);
} catch (Exception ex) {
; // Ignore action throwing an exception.
}
}
}
}
/** A predicate that examines a method invocation. */
interface MethodInvocationPredicate {
/** @return Whether the method incovation met some criterion */
boolean evaluate(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method) throws Exception;
}
/** An entity that does something with a method invocation, e.g. report where it occurred. */
interface MethodInvocationAction {
/** Executes some action for a method invocation. */
void execute(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method) throws Exception;
}
/**
* @return Whether the fully qualified {@code typeName} matches the {@code pattern}, or, iff the pattern does not
* contain a period, the simple type name of {@code typeName} matches the {@code pattern}
*/
static boolean
typeMatches(String pattern, String typeName) {
return new StringPattern(pattern).matches(
pattern.indexOf('.') == -1
? typeName.substring(typeName.lastIndexOf('.') + 1)
: typeName
);
}
private static final String[] USAGE = {
"Usage:",
"",
" java org.codehaus.janino.tools.JGrep [ <option> ... ] <root-dir> ... <pattern> ...",
" java org.codehaus.janino.tools.JGrep -help",
"",
"Reads a set of compilation units from the files in the <root-dir>s and their",
"subdirectories and searches them for specific Java[TM] constructs, e.g.",
"invocations of a particular method.",
"",
"Supported <option>s are ('cp' is a 'combined pattern, like '*.java-*Generated*'):",
" -dirs <dir-cp> Ignore subdirectories which don't match",
" -files <file-cp> Include only matching files (default is '*.java')",
" -classpath <classpath>",
" -extdirs <classpath>",
" -bootclasspath <classpath>",
" -encoding <encoding>",
" -verbose",
"",
"Supported <pattern>s are:",
" -method-invocation <method-pattern> [ predicate:<predicate-expression> | action:<action-script> ] ...",
"<method-pattern> is ('<ip>' is an 'identifier pattern' like '*foo*'):",
" -method-invocation <method-ip>",
" -method-invocation <simple-class-ip>.<method-ip>",
" -method-invocation <fully-qualified-class-ip>.<method-ip>",
" -method-invocation <method-ip>([<parameter-ip>[,<parameter-ip>]...])",
"",
"<predicate-expression> is a Java[TM] expression with the following signature:",
" boolean evaluate(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method)",
"",
"<action-script> is either",
" print-location-and-match",
" print-location",
", or a Java[TM] script (method body) with the following signature:",
" void execute(UnitCompiler uc, Java.Invocation invocation, IClass.IMethod method)",
};
private final IClassLoader iClassLoader;
private final String optionalCharacterEncoding;
private final Benchmark benchmark;
public
JGrep(
File[] classPath,
File[] optionalExtDirs,
File[] optionalBootClassPath,
String optionalCharacterEncoding,
boolean verbose
) {
this(
org.codehaus.janino.IClassLoader.createJavacLikePathIClassLoader( // iClassLoader
optionalBootClassPath,
optionalExtDirs,
classPath
),
optionalCharacterEncoding, // optionalCharacterEncoding
verbose // verbose
);
this.benchmark.report("*** JGrep - search Java(TM) source files for specific language constructs");
this.benchmark.report("*** For more information visit http://janino.codehaus.org");
this.benchmark.report("Class path", classPath);
this.benchmark.report("Ext dirs", optionalExtDirs);
this.benchmark.report("Boot class path", optionalBootClassPath);
this.benchmark.report("Character encoding", optionalCharacterEncoding);
}
public
JGrep(IClassLoader iClassLoader, final String optionalCharacterEncoding, boolean verbose) {
this.iClassLoader = new JGrepIClassLoader(iClassLoader);
this.optionalCharacterEncoding = optionalCharacterEncoding;
this.benchmark = new Benchmark(verbose);
}
private void
jGrep(
File[] rootDirectories,
final StringPattern[] directoryNamePatterns,
final StringPattern[] fileNamePatterns,
List<MethodInvocationTarget> methodInvocationTargets
) throws CompileException, IOException {
this.benchmark.report("Root dirs", rootDirectories);
this.benchmark.report("Directory name patterns", directoryNamePatterns);
this.benchmark.report("File name patterns", fileNamePatterns);
this.jGrep(DirectoryIterator.traverseDirectories(
rootDirectories, // rootDirectories
new FilenameFilter() { // directoryNameFilter
@Override public boolean
accept(File dir, String name) { return StringPattern.matches(directoryNamePatterns, name); }
},
new FilenameFilter() { // fileNameFilter
@Override public boolean
accept(File dir, String name) { return StringPattern.matches(fileNamePatterns, name); }
}
), methodInvocationTargets);
}
private void
jGrep(Iterator<File> sourceFilesIterator, final List<MethodInvocationTarget> methodInvocationTargets)
throws CompileException, IOException {
// Parse the given source files.
this.benchmark.beginReporting();
int sourceFileCount = 0;
try {
// Parse all source files.
while (sourceFilesIterator.hasNext()) {
File sourceFile = (File) sourceFilesIterator.next();
UnitCompiler uc = new UnitCompiler(this.parseCompilationUnit(
sourceFile, // sourceFile
this.optionalCharacterEncoding // optionalCharacterEncoding
), this.iClassLoader);
this.parsedCompilationUnits.add(uc);
++sourceFileCount;
}
} finally {
this.benchmark.endReporting("Parsed " + sourceFileCount + " source file(s)");
}
// Traverse the parsed compilation units.
this.benchmark.beginReporting();
try {
for (final UnitCompiler unitCompiler : this.parsedCompilationUnits) {
CompilationUnit compilationUnit = unitCompiler.getCompilationUnit();
this.benchmark.beginReporting("Grepping \"" + compilationUnit.optionalFileName + "\"");
try {
new Traverser() {
// "method(...)", "x.method(...)"
@Override public void
traverseMethodInvocation(Java.MethodInvocation mi) {
try {
this.match(mi, unitCompiler.findIMethod(mi));
} catch (CompileException ex) {
throw new UncheckedCompileException(ex);
}
super.traverseMethodInvocation(mi);
}
// "super.method(...)"
@Override public void
traverseSuperclassMethodInvocation(Java.SuperclassMethodInvocation scmi) {
try {
this.match(scmi, unitCompiler.findIMethod(scmi));
} catch (CompileException ex) {
throw new UncheckedCompileException(ex);
}
super.traverseSuperclassMethodInvocation(scmi);
}
// new Xyz(...)
@Override public void
traverseNewClassInstance(Java.NewClassInstance nci) {
// System.out.println(nci.getLocation() + ": " + nci);
super.traverseNewClassInstance(nci);
}
// new Xyz(...) {}
@Override public void
traverseNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci) {
// System.out.println(naci.getLocation() + ": " + naci);
super.traverseNewAnonymousClassInstance(naci);
}
// Explicit constructor invocation ("this(...)", "super(...)").
@Override public void
traverseConstructorInvocation(Java.ConstructorInvocation ci) {
// System.out.println(ci.getLocation() + ": " + ci);
super.traverseConstructorInvocation(ci);
}
private void
match(Java.Invocation invocation, IClass.IMethod method) throws CompileException {
for (MethodInvocationTarget mit : methodInvocationTargets) {
mit.apply(unitCompiler, invocation, method);
}
}
}.traverseCompilationUnit(compilationUnit);
} catch (UncheckedCompileException uce) {
throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
} finally {
this.benchmark.endReporting();
}
}
} finally {
this.benchmark.endReporting("Traversed " + sourceFileCount + " compilation units");
}
}
/**
* Read one compilation unit from a file and parse it.
* <p>
* The <code>inputStream</code> is closed before the method returns.
* @return the parsed compilation unit
*/
private Java.CompilationUnit
parseCompilationUnit(File sourceFile, String optionalCharacterEncoding) throws CompileException, IOException {
InputStream is = new BufferedInputStream(new FileInputStream(sourceFile));
try {
Parser parser = new Parser(new Scanner(sourceFile.getPath(), is, optionalCharacterEncoding));
this.benchmark.beginReporting("Parsing \"" + sourceFile + "\"");
try {
return parser.parseCompilationUnit();
} finally {
this.benchmark.endReporting();
}
} finally {
try { is.close(); } catch (IOException ex) {}
}
}
/**
* Construct the name of a file that could store the byte code of the class with the given
* name.
* <p>
* If <code>optionalDestinationDirectory</code> is non-null, the returned path is the
* <code>optionalDestinationDirectory</code> plus the package of the class (with dots replaced
* with file separators) plus the class name plus ".class". Example:
* "destdir/pkg1/pkg2/Outer$Inner.class"
* <p>
* If <code>optionalDestinationDirectory</code> is null, the returned path is the
* directory of the <code>sourceFile</code> plus the class name plus ".class". Example:
* "srcdir/Outer$Inner.class"
* @param className E.g. "pkg1.pkg2.Outer$Inner"
* @param sourceFile E.g. "srcdir/Outer.java"
* @param optionalDestinationDirectory E.g. "destdir"
*/
public static File
getClassFile(String className, File sourceFile, File optionalDestinationDirectory) {
if (optionalDestinationDirectory != null) {
return new File(optionalDestinationDirectory, ClassFile.getClassFileResourceName(className));
} else {
int idx = className.lastIndexOf('.');
return new File(
sourceFile.getParentFile(),
ClassFile.getClassFileResourceName(className.substring(idx + 1))
);
}
}
/**
* A specialized {@link IClassLoader} that loads {@link IClass}es from the following
* sources:
* <ol>
* <li>An already-parsed compilation unit
* <li>A class file in the output directory (if existant and younger than source file)
* <li>A source file in any of the source path directories
* <li>The parent class loader
* </ol>
* Notice that the {@link JGrepIClassLoader} is an inner class of {@link JGrep} and
* heavily uses {@link JGrep}'s members.
*/
private
class JGrepIClassLoader extends IClassLoader {
/**
* @param optionalParentIClassLoader The {@link IClassLoader} through which {@link IClass}es are to be loaded
*/
public
JGrepIClassLoader(IClassLoader optionalParentIClassLoader) {
super(optionalParentIClassLoader);
super.postConstruct();
}
/** @param type Field descriptor of the {@IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;" */
@Override protected IClass
findIClass(final String type) {
if (JGrep.DEBUG) System.out.println("type = " + type);
// Class type.
String className = Descriptor.toClassName(type); // E.g. "pkg1.pkg2.Outer$Inner"
if (JGrep.DEBUG) System.out.println("2 className = \"" + className + "\"");
// Do not attempt to load classes from package "java".
if (className.startsWith("java.")) return null;
// Check the already-parsed compilation units.
for (int i = 0; i < JGrep.this.parsedCompilationUnits.size(); ++i) {
UnitCompiler uc = (UnitCompiler) JGrep.this.parsedCompilationUnits.get(i);
IClass res = uc.findClass(className);
if (res != null) {
this.defineIClass(res);
return res;
}
}
return null;
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2013, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** Auxiliary command line tools related to JANINO. */
package org.codehaus.janino.tools;

View File

@ -0,0 +1,251 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* A {@link java.io.FilterWriter} that automatically indents lines by looking at
* trailing opening braces ('{') and leading closing braces ('}').
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class AutoIndentWriter extends FilterWriter {
/** Special character indicating a tabular layout of the following text. */
public static final char TABULATOR = 0xffff;
/** Special character indicating to clear all tabluar layout that was configured through {@link #TABULATOR}. */
public static final char CLEAR_TABULATORS = 0xfffe;
/** Special character that inserts a line break and indents the following text by one position. */
public static final char INDENT = 0xfffd;
/** Special character that inserts a line break and unindents the following text by one position. */
public static final char UNINDENT = 0xfffc;
private final StringBuilder lineBuffer = new StringBuilder();
private int indentation;
private List<StringBuilder> tabulatorBuffer;
private int tabulatorIndentation;
public
AutoIndentWriter(Writer out) { super(out); }
@Override public void
write(char[] cbuf, int off, int len) throws IOException {
for (; len > 0; --len) this.write(cbuf[off++]);
}
@Override public void
write(String str, int off, int len) throws IOException {
for (; len > 0; --len) this.write(str.charAt(off++));
}
@Override public void
write(int c) throws IOException {
if (c == '\n') {
this.lineBuffer.append('\n');
this.line(this.lineBuffer.toString());
this.lineBuffer.setLength(0);
return;
}
if (this.lineBuffer.length() > 0 && this.lineBuffer.charAt(this.lineBuffer.length() - 1) == '\r') {
this.line(this.lineBuffer.toString());
this.lineBuffer.setCharAt(0, (char) c);
this.lineBuffer.setLength(1);
return;
}
this.lineBuffer.append((char) c);
}
private void
line(String line) throws IOException {
if (this.tabulatorBuffer != null) {
this.tabulatorBuffer.add(new StringBuilder(line.length()).append(line));
if (line.charAt(0) == AutoIndentWriter.INDENT) { ++this.indentation; line = line.substring(1); }
if (line.charAt(0) == AutoIndentWriter.UNINDENT && --this.indentation < this.tabulatorIndentation) {
this.flushTabulatorBuffer();
}
} else
if (line.indexOf(AutoIndentWriter.TABULATOR) != -1) {
if (line.charAt(0) == AutoIndentWriter.INDENT) { ++this.indentation; line = line.substring(1); }
if (line.charAt(0) == AutoIndentWriter.UNINDENT) { --this.indentation; line = line.substring(1); }
this.tabulatorBuffer = new ArrayList<StringBuilder>();
this.tabulatorBuffer.add(new StringBuilder(line.length()).append(line));
this.tabulatorIndentation = this.indentation;
} else
{
if (line.charAt(0) == AutoIndentWriter.CLEAR_TABULATORS) line = line.substring(1);
if (line.charAt(0) == AutoIndentWriter.INDENT) { ++this.indentation; line = line.substring(1); }
if (line.charAt(0) == AutoIndentWriter.UNINDENT) { --this.indentation; line = line.substring(1); }
if ("\r\n".indexOf(line.charAt(0)) == -1) {
for (int i = 0; i < this.indentation; ++i) this.out.write(" ");
}
this.out.write(line);
}
}
private void
flushTabulatorBuffer() throws IOException {
List<List<StringBuilder>> lineGroups = new ArrayList();
lineGroups.add(new ArrayList<StringBuilder>());
for (StringBuilder line : this.tabulatorBuffer) {
int idx = 0;
if (line.charAt(0) == AutoIndentWriter.INDENT) {
lineGroups.add(new ArrayList<StringBuilder>());
++idx;
}
if (line.charAt(idx) == AutoIndentWriter.UNINDENT) {
AutoIndentWriter.resolveTabs(lineGroups.remove(lineGroups.size() - 1));
++idx;
}
if (line.charAt(idx) == AutoIndentWriter.CLEAR_TABULATORS) {
List<StringBuilder> lg = lineGroups.get(lineGroups.size() - 1);
AutoIndentWriter.resolveTabs(lg);
lg.clear();
line.deleteCharAt(idx);
}
for (int i = 0; i < line.length(); ++i) {
if (line.charAt(i) == AutoIndentWriter.TABULATOR) {
((List<StringBuilder>) lineGroups.get(lineGroups.size() - 1)).add(line);
}
}
}
for (List<StringBuilder> lg : lineGroups) AutoIndentWriter.resolveTabs(lg);
int ind = this.tabulatorIndentation;
for (StringBuilder sb : this.tabulatorBuffer) {
String line = sb.toString();
if (line.charAt(0) == AutoIndentWriter.INDENT) {
++ind;
line = line.substring(1);
}
if (line.charAt(0) == AutoIndentWriter.UNINDENT) {
--ind;
line = line.substring(1);
}
if ("\r\n".indexOf(line.charAt(0)) == -1) {
for (int i = 0; i < ind; ++i) this.out.write(" ");
}
this.out.write(line.toString());
}
this.tabulatorBuffer = null;
}
/**
* Expands all {@link #TABULATOR}s in the given {@link List} of {@link StringBuilder}s with
* spaces, so that the characters immediately following the {@link #TABULATOR}s are vertically
* aligned, like this:
* <p>
* Input:<pre>
* a @b @c\r\n
* aa @bb @cc\r\n
* aaa @bbb @ccc\r\n</pre>Output:<pre>
* a b c\r\n
* aa bb cc\r\n
* aaa bbb ccc\r\n</pre>
*/
private static void
resolveTabs(List<StringBuilder> lineGroup) {
// Determine the tabulator offsets for this line group.
List<Integer> tabulatorOffsets = new ArrayList<Integer>(); // 4, 4
for (StringBuilder line : lineGroup) {
int previousTab = 0;
if (line.charAt(previousTab) == AutoIndentWriter.INDENT) ++previousTab;
if (line.charAt(previousTab) == AutoIndentWriter.UNINDENT) ++previousTab;
int tabCount = 0;
for (int i = previousTab; i < line.length(); ++i) {
if (line.charAt(i) == AutoIndentWriter.TABULATOR) {
int tabOffset = i - previousTab;
previousTab = i;
if (tabCount >= tabulatorOffsets.size()) {
tabulatorOffsets.add(new Integer(tabOffset));
} else
{
if (tabOffset > ((Integer) tabulatorOffsets.get(tabCount)).intValue()) {
tabulatorOffsets.set(tabCount, new Integer(tabOffset));
}
}
++tabCount;
}
}
}
// Replace tabulators with spaces.
for (Iterator<StringBuilder> it = lineGroup.iterator(); it.hasNext();) {
StringBuilder line = (StringBuilder) it.next();
int tabCount = 0;
int previousTab = 0;
if (line.charAt(previousTab) == AutoIndentWriter.INDENT) ++previousTab;
if (line.charAt(previousTab) == AutoIndentWriter.UNINDENT) ++previousTab;
for (int i = previousTab; i < line.length(); ++i) {
if (line.charAt(i) == AutoIndentWriter.TABULATOR) {
int tabOffset = i - previousTab;
int n = ((Integer) tabulatorOffsets.get(tabCount++)).intValue() - tabOffset;
line.replace(i, i + 1, AutoIndentWriter.spaces(n));
i += n - 1;
previousTab = i;
}
}
}
}
/** @return a {@link String} of <code>n</code> spaces */
private static String
spaces(int n) {
if (n < 30) return " ".substring(0, n);
char[] data = new char[n];
Arrays.fill(data, ' ');
return String.valueOf(data);
}
@Override public void
close() throws IOException {
if (this.tabulatorBuffer != null) this.flushTabulatorBuffer();
if (this.lineBuffer.length() > 0) this.line(this.lineBuffer.toString());
this.out.close();
}
@Override public void
flush() throws IOException {
if (this.tabulatorBuffer != null) this.flushTabulatorBuffer();
if (this.lineBuffer.length() > 0) {
this.line(this.lineBuffer.toString());
this.lineBuffer.setLength(0);
}
this.out.flush();
}
}

View File

@ -0,0 +1,197 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import java.util.Stack;
/**
* Implements a scheme for benchmarking, i.e. for determining and/or reporting the time elapsed
* between the beginning and the end of an activity.
* <p>
* The measurement is done by invoking {@link #begin()} and later calling {@link #end()} whichs
* returns the time elapsed since the call to {@link #begin()}.
* <p>
* Notice that calls to {@link #begin()} and {@link #end()} can be nested, and each call to
* {@link #end()} refers to the matching {@link #begin()} call. To ensure that all calls match,
* the preferred way to write a benchmark is
* <pre>
* ...
* Benchmark b = new Benchmark();
* ...
* b.begin();
* try {
* ....
* } finally {
* long ms = b.end();
* }
* </pre>
* This code layout also makes it visually easy to write correct pairs of {@link #begin()} /
* {@link #end()} pairs.
* <p>
* The pair {@link #beginReporting()} and {@link #endReporting()} do basically the same, but
* report the benchmarking information through an internal {@link Reporter} object. The default
* {@link Reporter} prints its messages by <code>System.out.println()</code>.
* <p>
* Reporting is only enabled if the Benchmark object was created through {@link #Benchmark(boolean)}
* with a <code>true</code> argument.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class Benchmark {
private final Stack beginTimes = new Stack(); // Long
public
Benchmark() {
this.reportingEnabled = false;
this.reporter = null;
}
/** @see Benchmark */
public void
begin() { this.beginTimes.push(new Long(System.currentTimeMillis())); }
/** @see Benchmark */
public long
end() { return System.currentTimeMillis() - ((Long) this.beginTimes.pop()).longValue(); }
// Reporting-related methods and fields.
/** Sets up a {@link Benchmark} with a default {@link Reporter} that reports to {@code System.out}. */
public
Benchmark(boolean reportingEnabled) {
this.reportingEnabled = reportingEnabled;
this.reporter = new Reporter() {
@Override public void report(String message) { System.out.println(message); }
};
}
/** Set up a {@link Benchmark} with a custom {@link Reporter}. */
public
Benchmark(boolean reportingEnabled, Reporter reporter) {
this.reportingEnabled = reportingEnabled;
this.reporter = reporter;
}
private final boolean reportingEnabled;
private final Reporter reporter;
/** Interface used to report messages. */
public
interface Reporter {
/** Reports the given {@code message}. */
void report(String message);
}
/** Begin a benchmark (see {@link #begin()}) and report the fact. */
public void
beginReporting() {
if (!this.reportingEnabled) return;
this.reportIndented("Beginning...");
this.begin();
}
/** Begin a benchmark (see {@link #begin()}) and report the fact. */
public void
beginReporting(String message) {
if (!this.reportingEnabled) return;
this.reportIndented(message + "...");
this.begin();
}
/** End a benchmark (see {@link #end()}) and report the fact. */
public void
endReporting() {
if (!this.reportingEnabled) return;
this.reportIndented("... took " + this.end() + " ms");
}
/** End a benchmark (see {@link #begin()}) and report the fact. */
public void
endReporting(String message) {
if (!this.reportingEnabled) return;
this.reportIndented("... took " + this.end() + " ms: " + message);
}
/** Report the given message. */
public void
report(String message) {
if (!this.reportingEnabled) return;
this.reportIndented(message);
}
/**
* Report the <code>title</code>, a colon, a space, and the pretty-printed
* {@link Object}.
* @param optionalTitle
* @param o
*/
public void
report(String optionalTitle, Object o) {
if (!this.reportingEnabled) return;
String prefix = optionalTitle == null ? "" : (
optionalTitle
+ ": "
+ (optionalTitle.length() < Benchmark.PAD.length() ? Benchmark.PAD.substring(optionalTitle.length()) : "")
);
if (o == null) {
this.reportIndented(prefix + "(undefined)");
} else
if (o.getClass().isArray()) {
Object[] oa = (Object[]) o;
if (oa.length == 0) {
this.reportIndented(prefix + "(empty)");
} else
if (oa.length == 1) {
this.reportIndented(prefix + oa[0].toString());
} else {
this.reportIndented(optionalTitle == null ? "Array:" : optionalTitle + ':');
this.begin();
try {
for (Object o2 : oa) this.report(null, o2);
} finally {
this.end();
}
}
} else
{
this.reportIndented(prefix + o.toString());
}
}
private static final String PAD = " ";
/** Report a message through {@link #reporter}, indent by N spaces where N is the current benchmark stack depth. */
private void
reportIndented(String message) {
StringBuilder sb = new StringBuilder();
for (int i = this.beginTimes.size(); i > 0; --i) sb.append(" ");
sb.append(message);
this.reporter.report(sb.toString());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.codehaus.janino.JaninoRuntimeException;
/**
* An {@link java.util.Iterator} that traverses a {@link java.util.Collection} of {@link java.util.Iterator}s.
*
* @param <T> The element type of the iterator
*/
@SuppressWarnings("unchecked") public
class MultiIterator<T> implements Iterator<T> {
private static final Iterator<?> AT_END = new Iterator<Object>() {
@Override public boolean hasNext() { return false; }
@Override public Object next() { throw new NoSuchElementException(); }
@Override public void remove() { throw new UnsupportedOperationException(); }
};
private final Iterator<?> outer; // Over Iterators, Collections or arrays
private Iterator<T> inner = (Iterator<T>) MultiIterator.AT_END;
/** @param iterators An array of {@link Iterator}s */
public
MultiIterator(Iterator<T>[] iterators) { this.outer = Arrays.asList(iterators).iterator(); }
/** @param collections An array of {@link Collection}s */
public
MultiIterator(Collection<T>[] collections) { this.outer = Arrays.asList(collections).iterator(); }
/** @param arrays An array of arrays */
public
MultiIterator(Object/*T*/[][] arrays) { this.outer = Arrays.asList(arrays).iterator(); }
/** @param collection A {@link Collection} of {@link Collection}s, {@link Iterator}s and/or arrays */
public
MultiIterator(Collection<?> collection) { this.outer = collection.iterator(); }
/** @param iterator An iterator over {@link Collection}s, {@link Iterator}s and/or arrays */
public
MultiIterator(Iterator<?> iterator) { this.outer = iterator; }
/** @param array An array of {@link Collection}s, {@link Iterator}s and/or arrays */
public
MultiIterator(Object[] array) { this.outer = Arrays.asList(array).iterator(); }
/** Iterates over the given {@link Collection}, prepended with the given {@link Object}. */
public
MultiIterator(Object/*T*/ object, Collection<T> collection) {
this.outer = Arrays.asList(new Object[] {
new Object[] { object },
collection
}).iterator();
}
/** Iterates over the given {@link Collection}, appended with the given {@link Object}. */
public
MultiIterator(Collection<T> collection, Object/*T*/ object) {
this.outer = Arrays.asList(new Object[] {
collection,
new Object[] { object }
}).iterator();
}
/** Iterates over the given {@link Iterator}, prepended with the given {@code prefix}. */
public
MultiIterator(Object/*T*/ prefix, Iterator<T> iterator) {
this.outer = Arrays.asList(new Object[] {
new Object[] { prefix },
iterator
}).iterator();
}
/** Iterates over the given {@link Iterator}, appended with the given <code>suffix</code>. */
public
MultiIterator(Iterator<T> iterator, Object/*T*/ suffix) {
this.outer = Arrays.asList(new Object[] {
iterator,
new Object[] { suffix }
}).iterator();
}
@Override public boolean
hasNext() {
for (;;) {
if (this.inner.hasNext()) return true;
if (!this.outer.hasNext()) return false;
Object o = this.outer.next();
if (o instanceof Iterator) {
this.inner = (Iterator<T>) o;
} else
if (o instanceof Collection) {
this.inner = ((Collection<T>) o).iterator();
} else
if (o instanceof Object[]) {
this.inner = Arrays.asList((T[]) o).iterator();
} else
{
throw new JaninoRuntimeException("Unexpected element type \"" + o.getClass().getName() + "\"");
}
}
}
@Override public T
next() {
if (this.hasNext()) return this.inner.next();
throw new NoSuchElementException();
}
@Override public void
remove() {
this.inner.remove();
}
}

View File

@ -0,0 +1,51 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
/**
* An object that produces some {@link java.lang.Object} each time the
* {@link #produce()} method is invoked. This behavior is similar to the
* {@link java.util.Iterator}, but is represented by one single
* {@link #produce()} method as opposed to {@link java.util.Iterator}'s
* two methods {@link java.util.Iterator#hasNext()} and
* {@link java.util.Iterator#next()}. This simplifies the implementation of
* certain complex iterations.
*
* @param <T> The type of the products
* @see org.codehaus.janino.util.iterator.DirectoryIterator
* @see org.codehaus.janino.util.iterator.ProducerIterator
*/
public
interface Producer<T> {
/**
* Produce the next object.
*
* @return the next object or <code>null</code> to indicate that no more objects can be produced
*/
T produce();
}

View File

@ -0,0 +1,107 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.codehaus.janino.JaninoRuntimeException;
import org.codehaus.janino.util.resource.Resource;
import org.codehaus.janino.util.resource.ResourceFinder;
/**
* A {@link ClassLoader} that uses a {@link org.codehaus.janino.util.resource.ResourceFinder} to find ".class" files.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class ResourceFinderClassLoader extends ClassLoader {
private final ResourceFinder resourceFinder;
public
ResourceFinderClassLoader(ResourceFinder resourceFinder, ClassLoader parent) {
super(parent);
this.resourceFinder = resourceFinder;
}
/** @return The underlying {@link ResourceFinder} */
public ResourceFinder
getResourceFinder() { return this.resourceFinder; }
@Override protected Class
findClass(String className) throws ClassNotFoundException {
// Find the resource containing the class bytecode.
Resource classFileResource = this.resourceFinder.findResource(ClassFile.getClassFileResourceName(className));
if (classFileResource == null) throw new ClassNotFoundException(className);
// Open the class file resource.
InputStream is;
try {
is = classFileResource.open();
} catch (IOException ex) {
throw new JaninoRuntimeException((
"Opening class file resource \""
+ classFileResource.getFileName()
+ "\": "
+ ex.getMessage()
), ex);
}
// Read bytecode from the resource into a byte array.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[4096];
for (;;) {
int bytesRead = is.read(buffer);
if (bytesRead == -1) break;
baos.write(buffer, 0, bytesRead);
}
} catch (IOException ex) {
throw new ClassNotFoundException("Reading class file from \"" + classFileResource + "\"", ex);
} finally {
try { is.close(); } catch (IOException ex) {}
}
byte[] ba = baos.toByteArray();
// Define the class in this ClassLoader.
Class clazz = super.defineClass(null, ba, 0, ba.length);
if (!clazz.getName().equals(className)) {
// This is a really complicated case: We may find a class file on
// the class path that seemingly defines the class we are looking
// for, but doesn't. This is possible if the underlying file system
// has case-insensitive file names and/or file names that are
// limited in length (e.g. DOS 8.3).
throw new ClassNotFoundException(className);
}
return clazz;
}
}

View File

@ -0,0 +1,195 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import java.util.ArrayList;
import java.util.List;
/**
* Implementation of a UNIX shell-like string pattern algorithm.
* <p>
* Additionally, the concept of the "combined pattern" is supported (see
* {@link #matches(StringPattern[], String)}.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class StringPattern {
/** @see #matches(StringPattern[], String) */
public static final int INCLUDE = 0;
/** @see #matches(StringPattern[], String) */
public static final int EXCLUDE = 1;
private final int mode;
private final String pattern;
/** @param mode {@link #INCLUDE} or {@link #EXCLUDE} */
public
StringPattern(int mode, String pattern) {
this.mode = mode;
this.pattern = pattern;
}
public
StringPattern(String pattern) {
this.mode = StringPattern.INCLUDE;
this.pattern = pattern;
}
/**
* @return Whether this {@link StringPattern} represents <i>inclusion</i> ({@link #INCLUDE}) or <i>exclusion</i>
* exclusion ({@link #EXCLUDE}) of subjects
*/
public int
getMode() { return this.mode; }
/**
* Match the given <code>text</code> against the pattern represented by the current instance,
* as follows:
* <ul>
* <li>
* A <code>*</code> in the pattern matches any sequence of zero or more characters in the
* <code>text</code>
* </li>
* <li>
* A <code>?</code> in the pattern matches exactly one character in the <code>text</code>
* </li>
* <li>
* Any other character in the pattern must appear exactly as it is in the <code>text</code>
* </ul>
* Notice: The <code>mode</code> flag of the current instance does not take any effect here.
*/
public boolean
matches(String text) { return StringPattern.wildmatch(this.pattern, text); }
/**
* Parse a "combined pattern" into an array of {@link StringPattern}s. A combined pattern
* string is structured as follows:
* <pre>
* combined-pattern :=
* [ '+' | '-' ] pattern
* { ( '+' | '-' ) pattern }
* </pre>
* If a pattern is preceeded with a '-', then the {@link StringPattern} is created with mode
* {@link #EXCLUDE}, otherwise with mode {@link #INCLUDE}.
*/
public static StringPattern[]
parseCombinedPattern(String combinedPattern) {
List<StringPattern> al = new ArrayList();
for (int k = 0, l; k < combinedPattern.length(); k = l) {
int patternMode;
char c = combinedPattern.charAt(k);
if (c == '+') {
patternMode = StringPattern.INCLUDE;
++k;
} else
if (c == '-') {
patternMode = StringPattern.EXCLUDE;
++k;
} else {
patternMode = StringPattern.INCLUDE;
}
for (l = k; l < combinedPattern.length(); ++l) {
c = combinedPattern.charAt(l);
if (c == '+' || c == '-') break;
}
al.add(new StringPattern(patternMode, combinedPattern.substring(k, l)));
}
return (StringPattern[]) al.toArray(new StringPattern[al.size()]);
}
/**
* Match a given <code>text</code> against an array of {@link StringPattern}s (which was
* typically created by {@link #parseCombinedPattern(String)}.
* <p>
* The last matching pattern takes effect; if its mode is {@link #INCLUDE}, then
* <code>true</code> is returned, if its mode is {@link #EXCLUDE}, then <code>false</code> is
* returned.
* <p>
* If <code>patterns</code> is {@link #PATTERNS_NONE}, or empty, or none of its patterns
* matches, then <code>false</code> is returned.
* <p>
* If <code>patterns</code> is {@link #PATTERNS_ALL}, then <code>true</code> is
* returned.
* <p>
* For backwards compatibility, <code>null</code> patterns are treated like
* {@link #PATTERNS_NONE}.
*/
public static boolean
matches(StringPattern[] patterns, String text) {
if (patterns == null) return false; // Backwards compatibility -- previously, "null" was officially documented.
for (int i = patterns.length - 1; i >= 0; --i) {
if (patterns[i].matches(text)) {
return patterns[i].getMode() == StringPattern.INCLUDE;
}
}
return false; // No patterns defined or no pattern matches.
}
/** A {@link StringPattern} that matches any subject. */
public static final StringPattern[] PATTERNS_ALL = new StringPattern[] { new StringPattern("*") };
/** A {@link StringPattern} that matches no subject whatsoever. */
public static final StringPattern[] PATTERNS_NONE = new StringPattern[0];
@Override public String
toString() {
return (
this.mode == StringPattern.INCLUDE ? '+' :
this.mode == StringPattern.EXCLUDE ? '-' :
'?'
) + this.pattern;
}
private static boolean
wildmatch(String pattern, String text) {
int i;
for (i = 0; i < pattern.length(); ++i) {
char c = pattern.charAt(i);
switch (c) {
case '?':
if (i == text.length()) return false;
break;
case '*':
if (pattern.length() == i + 1) return true; // Optimization for trailing '*'.
pattern = pattern.substring(i + 1);
for (; i <= text.length(); ++i) {
if (StringPattern.wildmatch(pattern, text.substring(i))) return true;
}
return false;
default:
if (i == text.length()) return false;
if (text.charAt(i) != c) return false;
break;
}
}
return text.length() == i;
}
}

View File

@ -0,0 +1,85 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
/**
* A {@link java.io.FilterReader} that copies the bytes being passed through
* to a given {@link java.io.Writer}. This is in analogy with the UNIX "tee" command.
*/
public
class TeeReader extends FilterReader {
private final Writer out;
private final boolean closeWriterOnEOF;
public
TeeReader(Reader in, Writer out, boolean closeWriterOnEof) {
super(in);
this.out = out;
this.closeWriterOnEOF = closeWriterOnEof;
}
@Override public void
close() throws IOException {
this.in.close();
this.out.close();
}
@Override public int
read() throws IOException {
int c = this.in.read();
if (c == -1) {
if (this.closeWriterOnEOF) {
this.out.close();
} else {
this.out.flush();
}
} else {
this.out.write(c);
}
return c;
}
@Override public int
read(char[] cbuf, int off, int len) throws IOException {
int bytesRead = this.in.read(cbuf, off, len);
if (bytesRead == -1) {
if (this.closeWriterOnEOF) {
this.out.close();
} else {
this.out.flush();
}
} else {
this.out.write(cbuf, off, bytesRead);
}
return bytesRead;
}
}

View File

@ -0,0 +1,798 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util;
import org.codehaus.janino.JaninoRuntimeException;
import org.codehaus.janino.Java;
import org.codehaus.janino.Java.Rvalue;
import org.codehaus.janino.Visitor;
import org.codehaus.janino.Visitor.ComprehensiveVisitor;
/**
* This class traverses the subnodes of an AST. Derived classes may override
* individual methods to process specific nodes, e.g.:<pre>
* LocalClassDeclaration lcd = ...;
* lcd.accept(new Traverser() {
* int n = 0;
* public void traverseMethodDeclarator(Java.MethodDeclarator md) {
* ++this.n;
* super.traverseMethodDeclarator(md);
* }
* }.comprehensiveVisitor());</pre>
*/
public
class Traverser {
private final Visitor.ComprehensiveVisitor cv = new Visitor.ComprehensiveVisitor() {
// CHECKSTYLE LineLengthCheck:OFF
@Override public void visitSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid) { Traverser.this.traverseSingleTypeImportDeclaration(stid); }
@Override public void visitTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd) { Traverser.this.traverseTypeImportOnDemandDeclaration(tiodd); }
@Override public void visitSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration ssid) { Traverser.this.traverseSingleStaticImportDeclaration(ssid); }
@Override public void visitStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd) { Traverser.this.traverseStaticImportOnDemandDeclaration(siodd); }
@Override public void visitAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) { Traverser.this.traverseAnonymousClassDeclaration(acd); }
@Override public void visitLocalClassDeclaration(Java.LocalClassDeclaration lcd) { Traverser.this.traverseLocalClassDeclaration(lcd); }
@Override public void visitPackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd) { Traverser.this.traversePackageMemberClassDeclaration(pmcd); }
@Override public void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid) { Traverser.this.traverseMemberInterfaceDeclaration(mid); }
@Override public void visitPackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid) { Traverser.this.traversePackageMemberInterfaceDeclaration(pmid); }
@Override public void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd) { Traverser.this.traverseMemberClassDeclaration(mcd); }
@Override public void visitConstructorDeclarator(Java.ConstructorDeclarator cd) { Traverser.this.traverseConstructorDeclarator(cd); }
@Override public void visitInitializer(Java.Initializer i) { Traverser.this.traverseInitializer(i); }
@Override public void visitMethodDeclarator(Java.MethodDeclarator md) { Traverser.this.traverseMethodDeclarator(md); }
@Override public void visitFieldDeclaration(Java.FieldDeclaration fd) { Traverser.this.traverseFieldDeclaration(fd); }
@Override public void visitLabeledStatement(Java.LabeledStatement ls) { Traverser.this.traverseLabeledStatement(ls); }
@Override public void visitBlock(Java.Block b) { Traverser.this.traverseBlock(b); }
@Override public void visitExpressionStatement(Java.ExpressionStatement es) { Traverser.this.traverseExpressionStatement(es); }
@Override public void visitIfStatement(Java.IfStatement is) { Traverser.this.traverseIfStatement(is); }
@Override public void visitForStatement(Java.ForStatement fs) { Traverser.this.traverseForStatement(fs); }
@Override public void visitForEachStatement(Java.ForEachStatement fes) { Traverser.this.traverseForEachStatement(fes); }
@Override public void visitWhileStatement(Java.WhileStatement ws) { Traverser.this.traverseWhileStatement(ws); }
@Override public void visitTryStatement(Java.TryStatement ts) { Traverser.this.traverseTryStatement(ts); }
@Override public void visitSwitchStatement(Java.SwitchStatement ss) { Traverser.this.traverseSwitchStatement(ss); }
@Override public void visitSynchronizedStatement(Java.SynchronizedStatement ss) { Traverser.this.traverseSynchronizedStatement(ss); }
@Override public void visitDoStatement(Java.DoStatement ds) { Traverser.this.traverseDoStatement(ds); }
@Override public void visitLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) { Traverser.this.traverseLocalVariableDeclarationStatement(lvds); }
@Override public void visitReturnStatement(Java.ReturnStatement rs) { Traverser.this.traverseReturnStatement(rs); }
@Override public void visitThrowStatement(Java.ThrowStatement ts) { Traverser.this.traverseThrowStatement(ts); }
@Override public void visitBreakStatement(Java.BreakStatement bs) { Traverser.this.traverseBreakStatement(bs); }
@Override public void visitContinueStatement(Java.ContinueStatement cs) { Traverser.this.traverseContinueStatement(cs); }
@Override public void visitAssertStatement(Java.AssertStatement as) { Traverser.this.traverseAssertStatement(as); }
@Override public void visitEmptyStatement(Java.EmptyStatement es) { Traverser.this.traverseEmptyStatement(es); }
@Override public void visitLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds) { Traverser.this.traverseLocalClassDeclarationStatement(lcds); }
@Override public void visitPackage(Java.Package p) { Traverser.this.traversePackage(p); }
@Override public void visitArrayLength(Java.ArrayLength al) { Traverser.this.traverseArrayLength(al); }
@Override public void visitAssignment(Java.Assignment a) { Traverser.this.traverseAssignment(a); }
@Override public void visitUnaryOperation(Java.UnaryOperation uo) { Traverser.this.traverseUnaryOperation(uo); }
@Override public void visitBinaryOperation(Java.BinaryOperation bo) { Traverser.this.traverseBinaryOperation(bo); }
@Override public void visitCast(Java.Cast c) { Traverser.this.traverseCast(c); }
@Override public void visitClassLiteral(Java.ClassLiteral cl) { Traverser.this.traverseClassLiteral(cl); }
@Override public void visitConditionalExpression(Java.ConditionalExpression ce) { Traverser.this.traverseConditionalExpression(ce); }
@Override public void visitCrement(Java.Crement c) { Traverser.this.traverseCrement(c); }
@Override public void visitInstanceof(Java.Instanceof io) { Traverser.this.traverseInstanceof(io); }
@Override public void visitMethodInvocation(Java.MethodInvocation mi) { Traverser.this.traverseMethodInvocation(mi); }
@Override public void visitSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi) { Traverser.this.traverseSuperclassMethodInvocation(smi); }
@Override public void visitIntegerLiteral(Java.IntegerLiteral il) { Traverser.this.traverseIntegerLiteral(il); }
@Override public void visitFloatingPointLiteral(Java.FloatingPointLiteral fpl) { Traverser.this.traverseFloatingPointLiteral(fpl); }
@Override public void visitBooleanLiteral(Java.BooleanLiteral bl) { Traverser.this.traverseBooleanLiteral(bl); }
@Override public void visitCharacterLiteral(Java.CharacterLiteral cl) { Traverser.this.traverseCharacterLiteral(cl); }
@Override public void visitStringLiteral(Java.StringLiteral sl) { Traverser.this.traverseStringLiteral(sl); }
@Override public void visitNullLiteral(Java.NullLiteral nl) { Traverser.this.traverseNullLiteral(nl); }
@Override public void visitSimpleConstant(Java.SimpleConstant sl) { Traverser.this.traverseSimpleLiteral(sl); }
@Override public void visitNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci) { Traverser.this.traverseNewAnonymousClassInstance(naci); }
@Override public void visitNewArray(Java.NewArray na) { Traverser.this.traverseNewArray(na); }
@Override public void visitNewInitializedArray(Java.NewInitializedArray nia) { Traverser.this.traverseNewInitializedArray(nia); }
@Override public void visitNewClassInstance(Java.NewClassInstance nci) { Traverser.this.traverseNewClassInstance(nci); }
@Override public void visitParameterAccess(Java.ParameterAccess pa) { Traverser.this.traverseParameterAccess(pa); }
@Override public void visitQualifiedThisReference(Java.QualifiedThisReference qtr) { Traverser.this.traverseQualifiedThisReference(qtr); }
@Override public void visitThisReference(Java.ThisReference tr) { Traverser.this.traverseThisReference(tr); }
@Override public void visitArrayType(Java.ArrayType at) { Traverser.this.traverseArrayType(at); }
@Override public void visitBasicType(Java.BasicType bt) { Traverser.this.traverseBasicType(bt); }
@Override public void visitReferenceType(Java.ReferenceType rt) { Traverser.this.traverseReferenceType(rt); }
@Override public void visitRvalueMemberType(Java.RvalueMemberType rmt) { Traverser.this.traverseRvalueMemberType(rmt); }
@Override public void visitSimpleType(Java.SimpleType st) { Traverser.this.traverseSimpleType(st); }
@Override public void visitAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci) { Traverser.this.traverseAlternateConstructorInvocation(aci); }
@Override public void visitSuperConstructorInvocation(Java.SuperConstructorInvocation sci) { Traverser.this.traverseSuperConstructorInvocation(sci); }
@Override public void visitAmbiguousName(Java.AmbiguousName an) { Traverser.this.traverseAmbiguousName(an); }
@Override public void visitArrayAccessExpression(Java.ArrayAccessExpression aae) { Traverser.this.traverseArrayAccessExpression(aae); }
@Override public void visitFieldAccess(Java.FieldAccess fa) { Traverser.this.traverseFieldAccess(fa); }
@Override public void visitFieldAccessExpression(Java.FieldAccessExpression fae) { Traverser.this.traverseFieldAccessExpression(fae); }
@Override public void visitSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae) { Traverser.this.traverseSuperclassFieldAccessExpression(scfae); }
@Override public void visitLocalVariableAccess(Java.LocalVariableAccess lva) { Traverser.this.traverseLocalVariableAccess(lva); }
@Override public void visitParenthesizedExpression(Java.ParenthesizedExpression pe) { Traverser.this.traverseParenthesizedExpression(pe); }
@Override public void visitMarkerAnnotation(Java.MarkerAnnotation ma) { Traverser.this.traverseMarkerAnnotation(ma); }
@Override public void visitNormalAnnotation(Java.NormalAnnotation na) { Traverser.this.traverseNormalAnnotation(na); }
@Override public void visitSingleElementAnnotation(Java.SingleElementAnnotation sea) { Traverser.this.traverseSingleElementAnnotation(sea); }
@Override public void visitElementValueArrayInitializer(Java.ElementValueArrayInitializer evai) { Traverser.this.traverseElementValueArrayInitializer(evai); }
// CHECKSTYLE LineLengthCheck:ON
};
/** @see Traverser */
public ComprehensiveVisitor
comprehensiveVisitor() { return this.cv; }
// These may be overridden by derived classes.
/** @see Traverser */
public void
traverseCompilationUnit(Java.CompilationUnit cu) {
// The optionalPackageDeclaration is considered an integral part of
// the compilation unit and is thus not traversed.
for (Java.CompilationUnit.ImportDeclaration id : cu.importDeclarations) id.accept(this.cv);
for (Java.PackageMemberTypeDeclaration pmtd : cu.packageMemberTypeDeclarations) pmtd.accept(this.cv);
}
/** @see Traverser */
public void
traverseSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid) {
this.traverseImportDeclaration(stid);
}
/** @see Traverser */
public void
traverseTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd) {
this.traverseImportDeclaration(tiodd);
}
/** @see Traverser */
public void
traverseSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration stid) {
this.traverseImportDeclaration(stid);
}
/** @see Traverser */
public void
traverseStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd) {
this.traverseImportDeclaration(siodd);
}
/** @see Traverser */
public void
traverseImportDeclaration(Java.CompilationUnit.ImportDeclaration id) { this.traverseLocated(id); }
/** @see Traverser */
public void
traverseAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) {
acd.baseType.accept((Visitor.TypeVisitor) this.cv);
this.traverseClassDeclaration(acd);
}
/** @see Traverser */
public void
traverseLocalClassDeclaration(Java.LocalClassDeclaration lcd) { this.traverseNamedClassDeclaration(lcd); }
/** @see Traverser */
public void
traversePackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd) {
this.traverseNamedClassDeclaration(pmcd);
}
/** @see Traverser */
public void
traverseMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid) { this.traverseInterfaceDeclaration(mid); }
/** @see Traverser */
public void
traversePackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid) {
this.traverseInterfaceDeclaration(pmid);
}
/** @see Traverser */
public void
traverseMemberClassDeclaration(Java.MemberClassDeclaration mcd) { this.traverseNamedClassDeclaration(mcd); }
/** @see Traverser */
public void
traverseConstructorDeclarator(Java.ConstructorDeclarator cd) {
if (cd.optionalConstructorInvocation != null) {
cd.optionalConstructorInvocation.accept((Visitor.BlockStatementVisitor) this.cv);
}
this.traverseFunctionDeclarator(cd);
}
/** @see Traverser */
public void
traverseInitializer(Java.Initializer i) {
i.block.accept(this.cv);
this.traverseAbstractTypeBodyDeclaration(i);
}
/** @see Traverser */
public void
traverseMethodDeclarator(Java.MethodDeclarator md) { this.traverseFunctionDeclarator(md); }
/** @see Traverser */
public void
traverseFieldDeclaration(Java.FieldDeclaration fd) {
fd.type.accept((Visitor.TypeVisitor) this.cv);
for (Java.VariableDeclarator vd : fd.variableDeclarators) {
Java.ArrayInitializerOrRvalue optionalInitializer = vd.optionalInitializer;
if (optionalInitializer != null) this.traverseArrayInitializerOrRvalue(optionalInitializer);
}
this.traverseStatement(fd);
}
/** @see Traverser */
public void
traverseLabeledStatement(Java.LabeledStatement ls) {
ls.body.accept(this.cv);
this.traverseBreakableStatement(ls);
}
/** @see Traverser */
public void
traverseBlock(Java.Block b) {
for (Java.BlockStatement bs : b.statements) bs.accept(this.cv);
this.traverseStatement(b);
}
/** @see Traverser */
public void
traverseExpressionStatement(Java.ExpressionStatement es) {
es.rvalue.accept((Visitor.RvalueVisitor) this.cv);
this.traverseStatement(es);
}
/** @see Traverser */
public void
traverseIfStatement(Java.IfStatement is) {
is.condition.accept((Visitor.RvalueVisitor) this.cv);
is.thenStatement.accept(this.cv);
if (is.optionalElseStatement != null) is.optionalElseStatement.accept(this.cv);
this.traverseStatement(is);
}
/** @see Traverser */
public void
traverseForStatement(Java.ForStatement fs) {
if (fs.optionalInit != null) fs.optionalInit.accept(this.cv);
if (fs.optionalCondition != null) fs.optionalCondition.accept((Visitor.RvalueVisitor) this.cv);
if (fs.optionalUpdate != null) {
for (Java.Rvalue rv : fs.optionalUpdate) rv.accept((Visitor.RvalueVisitor) this.cv);
}
fs.body.accept(this.cv);
this.traverseContinuableStatement(fs);
}
/** @see Traverser */
public void
traverseForEachStatement(Java.ForEachStatement fes) {
this.traverseFormalParameter(fes.currentElement);
fes.expression.accept((Visitor.RvalueVisitor) this.cv);
fes.body.accept(this.cv);
this.traverseContinuableStatement(fes);
}
/** @see Traverser */
public void
traverseWhileStatement(Java.WhileStatement ws) {
ws.condition.accept((Visitor.RvalueVisitor) this.cv);
ws.body.accept(this.cv);
this.traverseContinuableStatement(ws);
}
/** @see Traverser */
public void
traverseTryStatement(Java.TryStatement ts) {
ts.body.accept(this.cv);
for (Java.CatchClause cc : ts.catchClauses) cc.body.accept(this.cv);
if (ts.optionalFinally != null) ts.optionalFinally.accept(this.cv);
this.traverseStatement(ts);
}
/** @see Traverser */
public void
traverseSwitchStatement(Java.SwitchStatement ss) {
ss.condition.accept((Visitor.RvalueVisitor) this.cv);
for (Java.SwitchStatement.SwitchBlockStatementGroup sbsg : ss.sbsgs) {
for (Java.Rvalue cl : sbsg.caseLabels) cl.accept((Visitor.RvalueVisitor) this.cv);
for (Java.BlockStatement bs : sbsg.blockStatements) bs.accept(this.cv);
this.traverseLocated(sbsg);
}
this.traverseBreakableStatement(ss);
}
/** @see Traverser */
public void
traverseSynchronizedStatement(Java.SynchronizedStatement ss) {
ss.expression.accept((Visitor.RvalueVisitor) this.cv);
ss.body.accept(this.cv);
this.traverseStatement(ss);
}
/** @see Traverser */
public void
traverseDoStatement(Java.DoStatement ds) {
ds.body.accept(this.cv);
ds.condition.accept((Visitor.RvalueVisitor) this.cv);
this.traverseContinuableStatement(ds);
}
/** @see Traverser */
public void
traverseLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
lvds.type.accept((Visitor.TypeVisitor) this.cv);
for (Java.VariableDeclarator vd : lvds.variableDeclarators) {
Java.ArrayInitializerOrRvalue optionalInitializer = vd.optionalInitializer;
if (optionalInitializer != null) this.traverseArrayInitializerOrRvalue(optionalInitializer);
}
this.traverseStatement(lvds);
}
/** @see Traverser */
public void
traverseReturnStatement(Java.ReturnStatement rs) {
if (rs.optionalReturnValue != null) rs.optionalReturnValue.accept((Visitor.RvalueVisitor) this.cv);
this.traverseStatement(rs);
}
/** @see Traverser */
public void
traverseThrowStatement(Java.ThrowStatement ts) {
ts.expression.accept((Visitor.RvalueVisitor) this.cv);
this.traverseStatement(ts);
}
/** @see Traverser */
public void
traverseBreakStatement(Java.BreakStatement bs) { this.traverseStatement(bs); }
/** @see Traverser */
public void
traverseContinueStatement(Java.ContinueStatement cs) { this.traverseStatement(cs); }
/** @see Traverser */
public void
traverseAssertStatement(Java.AssertStatement as) {
as.expression1.accept((Visitor.RvalueVisitor) this.cv);
if (as.optionalExpression2 != null) as.optionalExpression2.accept((Visitor.RvalueVisitor) this.cv);
this.traverseStatement(as);
}
/** @see Traverser */
public void
traverseEmptyStatement(Java.EmptyStatement es) { this.traverseStatement(es); }
/** @see Traverser */
public void
traverseLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds) {
lcds.lcd.accept(this.cv);
this.traverseStatement(lcds);
}
/** @see Traverser */
public void
traversePackage(Java.Package p) { this.traverseAtom(p); }
/** @see Traverser */
public void
traverseArrayLength(Java.ArrayLength al) {
al.lhs.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(al);
}
/** @see Traverser */
public void
traverseAssignment(Java.Assignment a) {
a.lhs.accept((Visitor.LvalueVisitor) this.cv);
a.rhs.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(a);
}
/** @see Traverser */
public void
traverseUnaryOperation(Java.UnaryOperation uo) {
uo.operand.accept((Visitor.RvalueVisitor) this.cv);
this.traverseBooleanRvalue(uo);
}
/** @see Traverser */
public void
traverseBinaryOperation(Java.BinaryOperation bo) {
bo.lhs.accept((Visitor.RvalueVisitor) this.cv);
bo.rhs.accept((Visitor.RvalueVisitor) this.cv);
this.traverseBooleanRvalue(bo);
}
/** @see Traverser */
public void
traverseCast(Java.Cast c) {
c.targetType.accept((Visitor.TypeVisitor) this.cv);
c.value.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(c);
}
/** @see Traverser */
public void
traverseClassLiteral(Java.ClassLiteral cl) {
cl.type.accept((Visitor.TypeVisitor) this.cv);
this.traverseRvalue(cl);
}
/** @see Traverser */
public void
traverseConditionalExpression(Java.ConditionalExpression ce) {
ce.lhs.accept((Visitor.RvalueVisitor) this.cv);
ce.mhs.accept((Visitor.RvalueVisitor) this.cv);
ce.rhs.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(ce);
}
/** @see Traverser */
public void
traverseCrement(Java.Crement c) {
c.operand.accept((Visitor.LvalueVisitor) this.cv);
this.traverseRvalue(c);
}
/** @see Traverser */
public void
traverseInstanceof(Java.Instanceof io) {
io.lhs.accept((Visitor.RvalueVisitor) this.cv);
io.rhs.accept((Visitor.TypeVisitor) this.cv);
this.traverseRvalue(io);
}
/** @see Traverser */
public void
traverseMethodInvocation(Java.MethodInvocation mi) {
if (mi.optionalTarget != null) mi.optionalTarget.accept(this.cv);
this.traverseInvocation(mi);
}
/** @see Traverser */
public void
traverseSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi) { this.traverseInvocation(smi); }
/** @see Traverser */
public void
traverseLiteral(Java.Literal l) { this.traverseRvalue(l); }
/** @see Traverser */
public void
traverseIntegerLiteral(Java.IntegerLiteral il) { this.traverseLiteral(il); }
/** @see Traverser */
public void
traverseFloatingPointLiteral(Java.FloatingPointLiteral fpl) { this.traverseLiteral(fpl); }
/** @see Traverser */
public void
traverseBooleanLiteral(Java.BooleanLiteral bl) { this.traverseLiteral(bl); }
/** @see Traverser */
public void
traverseCharacterLiteral(Java.CharacterLiteral cl) { this.traverseLiteral(cl); }
/** @see Traverser */
public void
traverseStringLiteral(Java.StringLiteral sl) { this.traverseLiteral(sl); }
/** @see Traverser */
public void
traverseNullLiteral(Java.NullLiteral nl) { this.traverseLiteral(nl); }
/** @see Traverser */
public void
traverseSimpleLiteral(Java.SimpleConstant sl) { this.traverseRvalue(sl); }
/** @see Traverser */
public void
traverseNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci) {
if (naci.optionalQualification != null) naci.optionalQualification.accept((Visitor.RvalueVisitor) this.cv);
naci.anonymousClassDeclaration.accept(this.cv);
for (Java.Rvalue argument : naci.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(naci);
}
/** @see Traverser */
public void
traverseNewArray(Java.NewArray na) {
na.type.accept((Visitor.TypeVisitor) this.cv);
for (Rvalue dimExpr : na.dimExprs) dimExpr.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(na);
}
/** @see Traverser */
public void
traverseNewInitializedArray(Java.NewInitializedArray nia) {
nia.arrayType.accept((Visitor.TypeVisitor) this.cv);
this.traverseArrayInitializerOrRvalue(nia.arrayInitializer);
}
/** @see Traverser */
public void
traverseArrayInitializerOrRvalue(Java.ArrayInitializerOrRvalue aiorv) {
if (aiorv instanceof Java.Rvalue) {
((Java.Atom) aiorv).accept(this.cv);
} else
if (aiorv instanceof Java.ArrayInitializer) {
Java.ArrayInitializerOrRvalue[] values = ((Java.ArrayInitializer) aiorv).values;
for (Java.ArrayInitializerOrRvalue value : values) this.traverseArrayInitializerOrRvalue(value);
} else
{
throw new JaninoRuntimeException(
"Unexpected array initializer or rvalue class "
+ aiorv.getClass().getName()
);
}
}
/** @see Traverser */
public void
traverseNewClassInstance(Java.NewClassInstance nci) {
if (nci.optionalQualification != null) nci.optionalQualification.accept((Visitor.RvalueVisitor) this.cv);
if (nci.type != null) nci.type.accept((Visitor.TypeVisitor) this.cv);
for (Java.Rvalue argument : nci.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(nci);
}
/** @see Traverser */
public void
traverseParameterAccess(Java.ParameterAccess pa) { this.traverseRvalue(pa); }
/** @see Traverser */
public void
traverseQualifiedThisReference(Java.QualifiedThisReference qtr) {
qtr.qualification.accept((Visitor.TypeVisitor) this.cv);
this.traverseRvalue(qtr);
}
/** @see Traverser */
public void
traverseThisReference(Java.ThisReference tr) { this.traverseRvalue(tr); }
/** @see Traverser */
public void
traverseArrayType(Java.ArrayType at) {
at.componentType.accept((Visitor.TypeVisitor) this.cv);
this.traverseType(at);
}
/** @see Traverser */
public void
traverseBasicType(Java.BasicType bt) { this.traverseType(bt); }
/** @see Traverser */
public void
traverseReferenceType(Java.ReferenceType rt) { this.traverseType(rt); }
/** @see Traverser */
public void
traverseRvalueMemberType(Java.RvalueMemberType rmt) {
rmt.rvalue.accept((Visitor.RvalueVisitor) this.cv);
this.traverseType(rmt);
}
/** @see Traverser */
public void
traverseSimpleType(Java.SimpleType st) { this.traverseType(st); }
/** @see Traverser */
public void
traverseAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci) {
this.traverseConstructorInvocation(aci);
}
/** @see Traverser */
public void
traverseSuperConstructorInvocation(Java.SuperConstructorInvocation sci) {
if (sci.optionalQualification != null) sci.optionalQualification.accept((Visitor.RvalueVisitor) this.cv);
this.traverseConstructorInvocation(sci);
}
/** @see Traverser */
public void
traverseAmbiguousName(Java.AmbiguousName an) { this.traverseLvalue(an); }
/** @see Traverser */
public void
traverseArrayAccessExpression(Java.ArrayAccessExpression aae) {
aae.lhs.accept((Visitor.RvalueVisitor) this.cv);
((Java.Atom) aae.index).accept(this.cv);
this.traverseLvalue(aae);
}
/** @see Traverser */
public void
traverseFieldAccess(Java.FieldAccess fa) {
fa.lhs.accept(this.cv);
this.traverseLvalue(fa);
}
/** @see Traverser */
public void
traverseFieldAccessExpression(Java.FieldAccessExpression fae) {
fae.lhs.accept(this.cv);
this.traverseLvalue(fae);
}
/** @see Traverser */
public void
traverseSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae) {
if (scfae.optionalQualification != null) scfae.optionalQualification.accept((Visitor.TypeVisitor) this.cv);
this.traverseLvalue(scfae);
}
/** @see Traverser */
public void
traverseLocalVariableAccess(Java.LocalVariableAccess lva) { this.traverseLvalue(lva); }
/** @see Traverser */
public void
traverseParenthesizedExpression(Java.ParenthesizedExpression pe) {
pe.value.accept((Visitor.RvalueVisitor) this.cv);
this.traverseLvalue(pe);
}
/** @see Traverser */
public void
traverseElementValueArrayInitializer(Java.ElementValueArrayInitializer evai) {
for (Java.ElementValue elementValue : evai.elementValues) elementValue.accept(this.cv);
this.traverseElementValue(evai);
}
/** @see Traverser */
public void
traverseElementValue(Java.ElementValue ev) {}
/** @see Traverser */
public void
traverseSingleElementAnnotation(Java.SingleElementAnnotation sea) {
sea.type.accept(this.cv);
sea.elementValue.accept(this.cv);
this.traverseAnnotation(sea);
}
/** @see Traverser */
public void
traverseAnnotation(Java.Annotation a) {}
/** @see Traverser */
public void
traverseNormalAnnotation(Java.NormalAnnotation na) {
na.type.accept(this.cv);
for (Java.ElementValuePair elementValuePair : na.elementValuePairs) {
elementValuePair.elementValue.accept(this.cv);
}
this.traverseAnnotation(na);
}
/** @see Traverser */
public void
traverseMarkerAnnotation(Java.MarkerAnnotation ma) {
ma.type.accept(this.cv);
this.traverseAnnotation(ma);
}
/** @see Traverser */
public void
traverseClassDeclaration(Java.ClassDeclaration cd) {
for (Java.ConstructorDeclarator ctord : cd.constructors) ctord.accept(this.cv);
for (Java.BlockStatement vdoi : cd.variableDeclaratorsAndInitializers) vdoi.accept(this.cv);
this.traverseAbstractTypeDeclaration(cd);
}
/** @see Traverser */
public void
traverseAbstractTypeDeclaration(Java.AbstractTypeDeclaration atd) {
for (Java.NamedTypeDeclaration mtd : atd.getMemberTypeDeclarations()) mtd.accept(this.cv);
for (Java.MethodDeclarator md : atd.getMethodDeclarations()) this.traverseMethodDeclarator(md);
}
/** @see Traverser */
public void
traverseNamedClassDeclaration(Java.NamedClassDeclaration ncd) {
for (Java.Type implementedType : ncd.implementedTypes) implementedType.accept((Visitor.TypeVisitor) this.cv);
if (ncd.optionalExtendedType != null) ncd.optionalExtendedType.accept((Visitor.TypeVisitor) this.cv);
this.traverseClassDeclaration(ncd);
}
/** @see Traverser */
public void
traverseInterfaceDeclaration(Java.InterfaceDeclaration id) {
for (Java.TypeBodyDeclaration cd : id.constantDeclarations) cd.accept(this.cv);
for (Java.Type extendedType : id.extendedTypes) extendedType.accept((Visitor.TypeVisitor) this.cv);
this.traverseAbstractTypeDeclaration(id);
}
/** @see Traverser */
public void
traverseFunctionDeclarator(Java.FunctionDeclarator fd) {
this.traverseFormalParameters(fd.formalParameters);
if (fd.optionalStatements != null) {
for (Java.BlockStatement bs : fd.optionalStatements) bs.accept(this.cv);
}
}
/** @see Traverser */
public void
traverseFormalParameters(Java.FunctionDeclarator.FormalParameters formalParameters) {
for (Java.FunctionDeclarator.FormalParameter formalParameter : formalParameters.parameters) {
this.traverseFormalParameter(formalParameter);
}
}
/** @see Traverser */
public void
traverseFormalParameter(Java.FunctionDeclarator.FormalParameter formalParameter) {
formalParameter.type.accept((Visitor.TypeVisitor) this.cv);
}
/** @see Traverser */
public void
traverseAbstractTypeBodyDeclaration(Java.AbstractTypeBodyDeclaration atbd) { this.traverseLocated(atbd); }
/** @see Traverser */
public void
traverseStatement(Java.Statement s) { this.traverseLocated(s); }
/** @see Traverser */
public void
traverseBreakableStatement(Java.BreakableStatement bs) { this.traverseStatement(bs); }
/** @see Traverser */
public void
traverseContinuableStatement(Java.ContinuableStatement cs) { this.traverseBreakableStatement(cs); }
/** @see Traverser */
public void
traverseRvalue(Java.Rvalue rv) { this.traverseAtom(rv); }
/** @see Traverser */
public void
traverseBooleanRvalue(Java.BooleanRvalue brv) { this.traverseRvalue(brv); }
/** @see Traverser */
public void
traverseInvocation(Java.Invocation i) {
for (Java.Rvalue argument : i.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
this.traverseRvalue(i);
}
/** @see Traverser */
public void
traverseConstructorInvocation(Java.ConstructorInvocation ci) {
for (Java.Rvalue argument : ci.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
this.traverseAtom(ci);
}
/** @see Traverser */
public void
traverseLvalue(Java.Lvalue lv) { this.traverseRvalue(lv); }
/** @see Traverser */
public void
traverseType(Java.Type t) { this.traverseAtom(t); }
/** @see Traverser */
public void
traverseAtom(Java.Atom a) { this.traverseLocated(a); }
/** @see Traverser */
public void
traverseLocated(Java.Located l) {}
}

View File

@ -0,0 +1,126 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.enumerator;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A class that represents an enumerated value. Its main features are its {@link #toString()} and
* {@link #fromString(String, Class)} method, which map names to values and vice versa.
* <p>
* To use this class, derive from it and define one or more
* <code>public static final</code> fields, as follows:
* <pre>
* public final class Suit extends Enumerator {
*
* // Exactly N instances of "Suit" exist to represent the N possible values.
* public static final Suit CLUBS = new Suit("clubs");
* public static final Suit DIAMONDS = new Suit("diamonds");
* public static final Suit HEARTS = new Suit("hearts");
* public static final Suit SPADES = new Suit("spades");
*
* // Optional, if you want to use EumeratorSet arithmetics.
* public static final EnumeratorSet NONE = new EnumeratorSet(Suit.class ).setName("none");
* public static final EnumeratorSet ALL = new EnumeratorSet(Suit.class, true).setName("all");
*
* // These MUST be declared exactly like this:
* private Suit(String name) { super(name); }
* public static Suit fromString(String name) throws EnumeratorFormatException {
* return (Suit) Enumerator.fromString(name, Suit.class);
* }
* }
* </pre>
*
* @see <a href="http://java.sun.com/developer/Books/effectivejava/Chapter5.pdf">Effective Java, Item 21</a>
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public abstract
class Enumerator {
private final String name;
private static final Map<Class /*enumeratorClass*/, Map<String /*name*/, Enumerator>>
INSTANCES = Collections.synchronizedMap(new HashMap());
/** Initialize the enumerator to the given value. */
protected
Enumerator(String name) {
if (name == null) throw new NullPointerException();
this.name = name;
((Map<String /*name*/, Enumerator>) Enumerator.getInstances(this.getClass())).put(name, this);
}
/** Equality is reference identity. */
@Override public final boolean
equals(Object that) { return this == that; }
/** Enforce {@link Object}'s notion of {@link Object#hashCode()}. */
@Override public final int
hashCode() { return super.hashCode(); }
/** Returns a mapping of name to Enumerator for the given enumeratorClass. */
static Map<String /*name*/, Enumerator>
getInstances(Class enumeratorClass) {
Map<String /*name*/, Enumerator> m = (Map) Enumerator.INSTANCES.get(enumeratorClass);
if (m != null) return m;
// The map need not be synchronized because it is modified only during initialization
// of the Enumerator.
m = new HashMap();
Enumerator.INSTANCES.put(enumeratorClass, m);
return m;
}
/**
* Initialize an {@link Enumerator} from a string.
* <p>
* The given string is converted into a value by looking at all instances of the given type
* created so far.
* <p>
* Derived classes should invoke this method as follows:<pre>
* public class Suit extends Enumerator {
* ...
* public static Suit fromString(String name) throws EnumeratorFormatException {
* return (Suit) Enumerator.fromString(name, Suit.class);
* }
* }</pre>
*
* @throws EnumeratorFormatException if the string cannot be identified
*/
protected static final Enumerator
fromString(String name, Class enumeratorClass) throws EnumeratorFormatException {
Enumerator value = (Enumerator) Enumerator.getInstances(enumeratorClass).get(name);
if (value == null) throw new EnumeratorFormatException(name);
return value;
}
/** Returns the <code>name</code> passed to {@link #Enumerator(String)}. */
@Override public String
toString() { return this.name; }
}

View File

@ -0,0 +1,36 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.enumerator;
/** Represents a problem related to parsing {@link Enumerator}s. */
public
class EnumeratorFormatException extends Exception {
private static final long serialVersionUID = -8883639721818527892L;
public EnumeratorFormatException() {}
public EnumeratorFormatException(String message) { super(message); }
}

View File

@ -0,0 +1,28 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2013, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** {@link org.codehaus.janino.util.enumerator.Enumerator}-related utility classes. */
package org.codehaus.janino.util.enumerator;

View File

@ -0,0 +1,133 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.codehaus.janino.JaninoRuntimeException;
import org.codehaus.janino.util.Producer;
/**
* An {@link Iterator} that finds the normal {@link File}s who's names are
* {@link FilenameFilter#accept(java.io.File, java.lang.String) accepted} by the
* <code>fileNameFilter</code> and
* <ul>
* <li>
* that exist in the given <code>rootDirectory</code>,
* </li>
* <li>
* and those that exist in all subdirectories of the
* <code>rootDirectory</code> who's names are
* {@link FilenameFilter#accept(java.io.File, java.lang.String)}ed by the
* <code>directoryNameFilter</code>
* </li>
* </ul>
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class DirectoryIterator extends ProducerIterator<File> {
public
DirectoryIterator(
final File rootDirectory,
final FilenameFilter directoryNameFilter,
final FilenameFilter fileNameFilter
) {
super(new Producer() {
private final List<State> stateStack = DirectoryIterator.newArrayList(new State(rootDirectory));
@Override public Object
produce() {
while (!this.stateStack.isEmpty()) {
State state = (State) this.stateStack.get(this.stateStack.size() - 1);
if (state.directories.hasNext()) {
this.stateStack.add(new State((File) state.directories.next()));
} else
if (state.files.hasNext()) {
File file = (File) state.files.next();
return file;
} else
{
this.stateStack.remove(this.stateStack.size() - 1);
}
}
return null;
}
class State {
State(File dir) {
File[] entries = dir.listFiles();
if (entries == null) {
throw new JaninoRuntimeException("Directory \"" + dir + "\" could not be read");
}
List<File> directoryList = new ArrayList();
List<File> fileList = new ArrayList();
for (File entry : entries) {
if (entry.isDirectory()) {
if (directoryNameFilter.accept(dir, entry.getName())) directoryList.add(entry);
} else
if (entry.isFile()) {
if (fileNameFilter.accept(dir, entry.getName())) fileList.add(entry);
}
}
this.directories = directoryList.iterator();
this.files = fileList.iterator();
}
final Iterator<File> directories;
final Iterator<File> files;
}
});
}
/**
* Create an {@link Iterator} that returns all matching {@link File}s locatable in a <i>set</i> of root
* directories.
*
* @see #DirectoryIterator(File, FilenameFilter, FilenameFilter)
*/
public static Iterator<File>
traverseDirectories(
File[] rootDirectories,
FilenameFilter directoryNameFilter,
FilenameFilter fileNameFilter
) {
List<Iterator<File>> result = new ArrayList();
for (File rootDirectory : rootDirectories) {
result.add(new DirectoryIterator(rootDirectory, directoryNameFilter, fileNameFilter));
}
return new MultiDimensionalIterator(result.iterator(), 2);
}
private static ArrayList
newArrayList(Object initialElement) {
ArrayList result = new ArrayList();
result.add(initialElement);
return result;
}
}

View File

@ -0,0 +1,54 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.Enumeration;
import java.util.Iterator;
/**
* An {@link java.util.Iterator} that iterates over the elements of an {@link java.util.Enumeration}.
*
* @param <T> The element type of the enumeration and the iterator
*/
public
class EnumerationIterator<T> implements Iterator<T> {
private final Enumeration<T> e;
public EnumerationIterator(Enumeration<T> e) { this.e = e; }
@Override public boolean hasNext() { return this.e.hasMoreElements(); }
@Override public T next() { return this.e.nextElement(); }
/**
* Since {@link Enumeration}s don't support element removal, this method always throws
* an {@link UnsupportedOperationException}.
*
* @see Iterator#remove()
*/
@Override public void remove() { throw new UnsupportedOperationException("remove"); }
}

View File

@ -0,0 +1,48 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.Iterator;
/**
* An {@link java.util.Iterator} that retrieves its elements from a delegate {@link java.util.Iterator}. The default
* implementation simply passes all method invocations to the delegate.
*
* @param <T> The element type of the iterator
*/
public abstract
class FilterIterator<T> implements Iterator<T> {
/** @see FilterIterator */
protected final Iterator<T> delegate;
public FilterIterator(Iterator<T> delegate) { this.delegate = delegate; }
@Override public boolean hasNext() { return this.delegate.hasNext(); }
@Override public T next() { return this.delegate.next(); }
@Override public void remove() { this.delegate.remove(); }
}

View File

@ -0,0 +1,83 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.ListIterator;
/**
* An {@link java.util.ListIterator} that retrieves its elements from a delegate {@link java.util.ListIterator}. The
* default implementation simply passes all method invocations to the delegate.
*
* @param <T> The element type of the list iterator
*/
public abstract
class FilterListIterator<T> implements ListIterator<T> {
/** @see FilterListIterator */
protected final ListIterator<T> delegate;
public
FilterListIterator(ListIterator<T> delegate) {
this.delegate = delegate;
}
/** Calls {@link #delegate}.{@link java.util.ListIterator#hasNext()} */
@Override public boolean
hasNext() { return this.delegate.hasNext(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#next()} */
@Override public T
next() { return this.delegate.next(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#hasPrevious()} */
@Override public boolean
hasPrevious() { return this.delegate.hasPrevious(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#previous()} */
@Override public T
previous() { return this.delegate.previous(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#nextIndex()} */
@Override public int
nextIndex() { return this.delegate.nextIndex(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#previousIndex()} */
@Override public int
previousIndex() { return this.delegate.previousIndex(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#remove()} */
@Override public void
remove() { this.delegate.remove(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#set(java.lang.Object)} */
@Override public void
set(T o) { this.delegate.set(o); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#add(java.lang.Object)} */
@Override public void
add(T o) { this.delegate.add(o); }
}

View File

@ -0,0 +1,91 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* A {@link java.util.Collection} that lazily reads its elements from an
* {@link java.util.Iterator}.
* <p>
* In other words, you can call {@link #iterator()} as often as you want, but the
* {@link IteratorCollection} will iterate over its delegate only once.
*
* @param <T> The element type of the iterator and the collection
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class IteratorCollection<T> extends AbstractCollection<T> {
/** The delegate. */
private final Iterator<T> iterator;
/** Lazily-filled collection of the elements delivered by the delegate. */
private final List/*<T>*/ elements = new ArrayList();
public
IteratorCollection(Iterator iterator) { this.iterator = iterator; }
@Override public Iterator<T>
iterator() {
return new Iterator/*<T>*/() {
private Iterator/*<T>*/ elementsIterator = IteratorCollection.this.elements.iterator();
@Override public Object
next() {
if (this.elementsIterator != null) {
if (this.elementsIterator.hasNext()) return this.elementsIterator.next();
this.elementsIterator = null;
}
Object o = IteratorCollection.this.iterator.next();
IteratorCollection.this.elements.add(o);
return o;
}
@Override public boolean
hasNext() {
return (
(this.elementsIterator != null && this.elementsIterator.hasNext())
|| IteratorCollection.this.iterator.hasNext()
);
}
@Override public void
remove() { throw new UnsupportedOperationException(); }
};
}
@Override public int
size() {
int size = 0;
for (@SuppressWarnings("unused") Object o : this) ++size;
return size;
}
}

View File

@ -0,0 +1,105 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An {@link java.util.Iterator} that iterates over a delegate, which produces
* arrays, {@link java.util.Collection}s, {@link java.util.Enumeration}s or
* {@link java.util.Iterator}s. This {@link java.util.Iterator} returns the
* elements of these objects.
* <p>
* The count of dimensions is declared at construction. Count "1" produces an
* {@link java.util.Iterator} that adds no functionality to its delegate, count
* "2" produces an {@link Iterator} that behaves as explained above, and so
* forth.
*/
@SuppressWarnings("rawtypes") public
class MultiDimensionalIterator implements Iterator {
private final Iterator[] nest;
private static final Iterator EMPTY_ITERATOR = new Iterator() {
@Override public boolean hasNext() { return false; }
@Override public Object next() { throw new NoSuchElementException(); }
@Override public void remove() { throw new UnsupportedOperationException("remove"); }
};
public
MultiDimensionalIterator(Iterator delegate, int dimensionCount) {
this.nest = new Iterator[dimensionCount];
this.nest[0] = delegate;
for (int i = 1; i < dimensionCount; ++i) this.nest[i] = MultiDimensionalIterator.EMPTY_ITERATOR;
}
/** @throws UniterableElementException */
@SuppressWarnings("unchecked") @Override public boolean
hasNext() {
// Unroll this check because it is so performance critical:
if (this.nest[this.nest.length - 1].hasNext()) return true;
int i = this.nest.length - 2;
if (i < 0) return false;
for (;;) {
if (!this.nest[i].hasNext()) {
if (i == 0) return false;
--i;
} else {
if (i == this.nest.length - 1) return true;
Object o = this.nest[i].next();
if (o instanceof Iterator) {
this.nest[++i] = (Iterator) o;
} else
if (o instanceof Object[]) {
this.nest[++i] = Arrays.asList((Object[]) o).iterator();
} else
if (o instanceof Collection) {
this.nest[++i] = ((Collection) o).iterator();
} else
if (o instanceof Enumeration) {
this.nest[++i] = new EnumerationIterator<Object>((Enumeration) o);
} else
{
throw new UniterableElementException();
}
}
}
}
@Override public Object
next() {
if (!this.hasNext()) throw new NoSuchElementException();
return this.nest[this.nest.length - 1].next();
}
@Override public void remove() { throw new UnsupportedOperationException("remove"); }
}

View File

@ -0,0 +1,69 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.codehaus.janino.util.Producer;
/**
* An {@link Iterator} that iterates over all the objects produced by a delegate {@link Producer}.
*
* @param <T> The type of the products and the iterator elements
* @see Producer
*/
public
class ProducerIterator<T> implements Iterator<T> {
private final Producer<T> producer;
private static final Object UNKNOWN = new Object();
private static final Object AT_END = null;
private Object nextElement = ProducerIterator.UNKNOWN;
public
ProducerIterator(Producer<T> producer) { this.producer = producer; }
@Override public boolean
hasNext() {
if (this.nextElement == ProducerIterator.UNKNOWN) this.nextElement = this.producer.produce();
return this.nextElement != ProducerIterator.AT_END;
}
@Override public T
next() {
if (this.nextElement == ProducerIterator.UNKNOWN) this.nextElement = this.producer.produce();
if (this.nextElement == ProducerIterator.AT_END) throw new NoSuchElementException();
@SuppressWarnings("unchecked") T result = (T) this.nextElement;
this.nextElement = ProducerIterator.UNKNOWN;
return result;
}
@Override public void
remove() { throw new UnsupportedOperationException("remove"); }
}

View File

@ -0,0 +1,66 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.ListIterator;
/**
* A {@link java.util.ListIterator} that reverses the direction of all operations
* of a delegate {@link java.util.ListIterator}.
*
* @param <T> The element type of the list iterator
*/
public
class ReverseListIterator<T> extends FilterListIterator<T> {
public
ReverseListIterator(ListIterator<T> delegate) { super(delegate); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#hasPrevious()} */
@Override public boolean
hasNext() { return super.hasPrevious(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#hasNext()} */
@Override public boolean
hasPrevious() { return super.hasNext(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#previous()} */
@Override public T
next() { return super.previous(); }
/** Calls {@link #delegate}.{@link java.util.ListIterator#next()} */
@Override public T
previous() { return super.next(); }
/** Throws an {@link UnsupportedOperationException}. */
@Override public int
nextIndex() { throw new UnsupportedOperationException(); }
/** Throws an {@link UnsupportedOperationException}. */
@Override public int
previousIndex() { throw new UnsupportedOperationException(); }
}

View File

@ -0,0 +1,56 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.Iterator;
/**
* An {@link java.util.Iterator} that transforms its elements on-the-fly.
*
* @param <T1> The element type of the delegate iterator
* @param <T2> The element type of this iterator
*/
public abstract
class TransformingIterator<T1, T2> implements Iterator<T2> {
private final Iterator<T1> delegate;
public
TransformingIterator(Iterator<T1> delegate) { this.delegate = delegate; }
@Override public boolean
hasNext() { return this.delegate.hasNext(); }
@Override public final T2
next() { return this.transform(this.delegate.next()); }
@Override public void
remove() { this.delegate.remove(); }
/** Derived classes must implement this method such that it does the desired transformation. */
protected abstract T2 transform(T1 o);
}

View File

@ -0,0 +1,103 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Stack;
/**
* An {@link java.util.Iterator} that iterates over a delegate, and while it encounters an array, a {@link
* java.util.Collection}, an {@link java.util.Enumeration} or a {@link java.util.Iterator} element, it iterates over it
* recursively.
* <p>
* Be aware that {@link #hasNext()} must read ahead one element.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class TraversingIterator implements Iterator {
private final Stack nest = new Stack(); // Iterator
private Object nextElement;
private boolean nextElementRead; // Have we read ahead?
public
TraversingIterator(Iterator delegate) { this.nest.push(delegate); }
@Override public boolean
hasNext() { return this.nextElementRead || this.readNext(); }
@Override public Object
next() {
if (!this.nextElementRead && !this.readNext()) throw new NoSuchElementException();
this.nextElementRead = false;
return this.nextElement;
}
/**
* Reads the next element and stores it in {@link #nextElement}.
* @return <code>false</code> if no more element can be read.
*/
private boolean
readNext() {
while (!this.nest.empty()) {
Iterator it = (Iterator) this.nest.peek();
if (!it.hasNext()) {
this.nest.pop();
continue;
}
Object o = it.next();
if (o instanceof Iterator) {
this.nest.push(o);
} else
if (o instanceof Object[]) {
this.nest.push(Arrays.asList((Object[]) o).iterator());
} else
if (o instanceof Collection) {
this.nest.push(((Collection) o).iterator());
} else
if (o instanceof Enumeration) {
this.nest.push(new EnumerationIterator((Enumeration) o));
} else
{
this.nextElement = o;
this.nextElementRead = true;
return true;
}
}
return false;
}
/**
* @throws UnsupportedOperationException iff the {@link Iterator} currently being
* traversed doesn't support element removal
* @see Iterator#remove()
*/
@Override public void
remove() { ((Iterator) this.nest.peek()).remove(); }
}

View File

@ -0,0 +1,39 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.iterator;
/**
* Thrown by {@link org.codehaus.janino.util.iterator.MultiDimensionalIterator} to indicate that it has encountered an
* element that cannot be iterated.
*/
public
class UniterableElementException extends RuntimeException {
private static final long serialVersionUID = 4822728738007842244L;
public UniterableElementException() {}
}

View File

@ -0,0 +1,28 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2013, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** Some generic {@link java.util.Iterator}-related helper classes. */
package org.codehaus.janino.util.iterator;

View File

@ -0,0 +1,28 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2013, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** Application-independent helper classes. */
package org.codehaus.janino.util;

View File

@ -0,0 +1,46 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
/**
* Creates a resource in a given directory:<pre>
* <i>destinationDirectory</i>/<i>resourceName</i></pre>
*/
public
class DirectoryResourceCreator extends FileResourceCreator {
private final File destinationDirectory;
public
DirectoryResourceCreator(File destinationDirectory) { this.destinationDirectory = destinationDirectory; }
@Override protected final File
getFile(String resourceName) {
return new File(this.destinationDirectory, resourceName.replace('/', File.separatorChar));
}
}

View File

@ -0,0 +1,85 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A {@link org.codehaus.janino.util.resource.FileResourceFinder} that finds file resources in
* a directory. The name of the file is constructed by concatenating a dirctory name
* with the resource name such that slashes in the resource name map to file
* separators.
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class DirectoryResourceFinder extends FileResourceFinder {
private final File directory;
private final Map<String /*directoryName*/, Set<File>> subdirectoryNameToFiles = new HashMap();
/** @param directory the directory to use as the search base */
public
DirectoryResourceFinder(File directory) { this.directory = directory; }
@Override public final String toString() { return "dir:" + this.directory; }
// Implement FileResourceFinder.
@Override protected final File
findResourceAsFile(String resourceName) {
// Determine the subdirectory name (null for no subdirectory).
int idx = resourceName.lastIndexOf('/');
String subdirectoryName = (
idx == -1 ? null :
resourceName.substring(0, idx).replace('/', File.separatorChar)
);
// Determine files existing in this subdirectory.
Set<File> files = (Set) this.subdirectoryNameToFiles.get(subdirectoryName);
if (files == null) {
File subDirectory = (
subdirectoryName == null
? this.directory
: new File(this.directory, subdirectoryName)
);
File[] fa = subDirectory.listFiles();
files = (fa == null) ? Collections.EMPTY_SET : new HashSet(Arrays.asList(fa));
this.subdirectoryNameToFiles.put(subdirectoryName, files);
}
// Notice that "File.equals()" performs all the file-system dependent
// magic like case conversion.
File file = new File(this.directory, resourceName.replace('/', File.separatorChar));
if (!files.contains(file)) return null;
return file;
}
}

View File

@ -0,0 +1,50 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/** Representation of a resource that is a {@link java.io.File}. */
public
class FileResource implements Resource {
public FileResource(File file) { this.file = file; }
// Implement "Resource".
@Override public final String getFileName() { return this.file.toString(); }
@Override public final InputStream open() throws IOException { return new FileInputStream(this.file); }
@Override public final long lastModified() { return this.file.lastModified(); }
/** @return The file containing the contents of this resource */
public final File getFile() { return this.file; }
@Override public final String toString() { return this.getFileName(); }
private final File file;
}

View File

@ -0,0 +1,57 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/** Stores a stream of bytes in a named resource. */
public abstract
class FileResourceCreator implements ResourceCreator {
@Override public final OutputStream
createResource(String resourceName) throws IOException {
File file = this.getFile(resourceName);
// Create directory for class file if it does not exist.
File dir = file.getParentFile();
if (dir != null && !dir.isDirectory()) {
if (!dir.mkdirs()) throw new IOException("Cannot create directory for class file \"" + file + "\"");
}
// Create the file.
return new FileOutputStream(file);
}
@Override public final boolean
deleteResource(String resourceName) { return this.getFile(resourceName).delete(); }
/** @return The file into which the contents is written */
protected abstract File getFile(String resourceName);
}

View File

@ -0,0 +1,50 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
/**
* This class specializes the {@link org.codehaus.janino.util.resource.ResourceFinder}
* for finding resources in {@link java.io.File}s.
* <p>
* It finds {@link FileResource}s instead of simple
* {@link Resource}s.
*/
public abstract
class FileResourceFinder extends ResourceFinder {
@Override public final Resource
findResource(String resourceName) {
File file = this.findResourceAsFile(resourceName);
if (file == null) return null;
return new FileResource(file);
}
/** Converts a given resource resource name into a {@link File}. */
protected abstract File findResourceAsFile(String resourceName);
}

View File

@ -0,0 +1,78 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.zip.ZipFile;
import org.codehaus.janino.util.iterator.MultiDimensionalIterator;
import org.codehaus.janino.util.iterator.TransformingIterator;
/** Finds resources in any of the "*.jar" files that exist in a given set of directories. */
public
class JarDirectoriesResourceFinder extends LazyMultiResourceFinder {
/** @param directories The set of directories to search for JAR files. */
@SuppressWarnings({ "unchecked", "rawtypes" }) public
JarDirectoriesResourceFinder(final File[] directories) {
super(new MultiDimensionalIterator(
// Iterate over directories.
new TransformingIterator(Arrays.asList(directories).iterator()) {
@Override protected Object/*Iterator<ResourceFinder>*/
transform(Object/*File*/ o) {
File directory = (File) o;
if (!directory.exists()) return Collections.EMPTY_LIST.iterator();
// Iterate over the JAR files in the given directory.
File[] jarFiles = directory.listFiles(new FilenameFilter() {
@Override public boolean accept(File dir, String name) { return name.endsWith(".jar"); }
});
return new TransformingIterator(Arrays.asList(jarFiles).iterator()) {
@Override protected Object/*ResourceFinder*/
transform(Object/*File*/ o) {
File jarFile = (File) o;
try {
return new ZipFileResourceFinder(new ZipFile(jarFile));
} catch (IOException e) {
return ResourceFinder.EMPTY_RESOURCE_FINDER;
}
}
};
}
},
2
));
}
}

View File

@ -0,0 +1,48 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.util.Iterator;
import org.codehaus.janino.util.iterator.IteratorCollection;
/**
* A {@link org.codehaus.janino.util.resource.ResourceFinder} that examines a set of {@link
* org.codehaus.janino.util.resource.ResourceFinder}s lazily as it searches for resources.
*
* @see IteratorCollection
*/
@SuppressWarnings("unchecked") public
class LazyMultiResourceFinder extends MultiResourceFinder {
/** @param resourceFinders delegate {@link ResourceFinder}s */
@SuppressWarnings("rawtypes") public
LazyMultiResourceFinder(Iterator<ResourceFinder> resourceFinders) {
super(new IteratorCollection(resourceFinders));
}
}

View File

@ -0,0 +1,65 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/** Creates resources as byte arrays in a delegate {@link java.util.Map}. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class MapResourceCreator implements ResourceCreator {
private final Map<String, byte[]> map;
/** Auto-create the delegate {@link Map}. */
public
MapResourceCreator() { this.map = new HashMap(); }
public
MapResourceCreator(Map<String, byte[]> map) { this.map = map; }
/** @return The {@link String}-to-{@code byte[]} map of the resources created */
public final Map<String, byte[]>
getMap() { return this.map; }
@Override public final OutputStream
createResource(final String resourceName) {
return new ByteArrayOutputStream() {
@Override public void
close() throws IOException {
super.close();
MapResourceCreator.this.map.put(resourceName, this.toByteArray());
}
};
}
@Override public final boolean
deleteResource(String resourceName) { return this.map.remove(resourceName) != null; }
}

View File

@ -0,0 +1,60 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Map;
/**
* A {@link org.codehaus.janino.util.resource.ResourceFinder} that provides access
* to resource stored as byte arrays in a {@link java.util.Map}.
*/
public
class MapResourceFinder extends ResourceFinder {
private final Map<String, byte[]> map;
private long lastModified;
public
MapResourceFinder(Map<String, byte[]> map) { this.map = map; }
/** @param lastModified The return value of {@link Resource#lastModified()} for the next resources found */
public final void
setLastModified(long lastModified) { this.lastModified = lastModified; }
@Override public final Resource
findResource(final String resourceName) {
final byte[] ba = (byte[]) this.map.get(resourceName);
if (ba == null) return null;
return new Resource() {
@Override public InputStream open() { return new ByteArrayInputStream(ba); }
@Override public String getFileName() { return resourceName; }
@Override public long lastModified() { return MapResourceFinder.this.lastModified; }
};
}
}

View File

@ -0,0 +1,55 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.util.Collection;
/**
* A {@link org.codehaus.janino.util.resource.ResourceFinder} that finds its resources through a collection of
* other {@link org.codehaus.janino.util.resource.ResourceFinder}s.
*/
public
class MultiResourceFinder extends ResourceFinder {
private final Collection<ResourceFinder> resourceFinders; // One for each entry
/** @param resourceFinders The entries of the "path" */
public
MultiResourceFinder(Collection<ResourceFinder> resourceFinders) { this.resourceFinders = resourceFinders; }
// Implement ResourceFinder.
@Override public final Resource
findResource(String resourceName) {
for (ResourceFinder rf : this.resourceFinders) {
Resource resource = rf.findResource(resourceName);
//System.err.println("*** " + resourceName + " in " + rf + "? => " + url);
if (resource != null) return resource;
}
return null;
}
}

View File

@ -0,0 +1,136 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipFile;
import org.codehaus.janino.util.iterator.TransformingIterator;
/**
* A {@link org.codehaus.janino.util.resource.ResourceFinder} that finds its resources along a "path"
* consisting of JAR file names, ZIP file names, and directory names.
* @see org.codehaus.janino.util.resource.ZipFileResourceFinder
* @see org.codehaus.janino.util.resource.DirectoryResourceFinder
*/
@SuppressWarnings({ "rawtypes", "unchecked" }) public
class PathResourceFinder extends LazyMultiResourceFinder {
/** @param entries The entries of the "path" */
public
PathResourceFinder(final File[] entries) {
super(PathResourceFinder.createIterator(Arrays.asList(entries).iterator()));
}
/** @param entries The entries of the "path" (type must be {@link File}) */
public
PathResourceFinder(Iterator<ResourceFinder> entries) { super(entries); }
/** @param path A java-like path, i.e. a "path separator"-separated list of entries. */
public
PathResourceFinder(String path) { this(PathResourceFinder.parsePath(path)); }
private static Iterator<ResourceFinder>
createIterator(final Iterator<File> entries) {
return new TransformingIterator/*<File, ResourceFinder>*/(entries) {
@Override protected Object transform(Object o) { return PathResourceFinder.createResourceFinder((File) o); }
};
}
/**
* Break a given string up by the system-dependent path-separator character (on UNIX systems,
* this character is ':'; on Microsoft Windows systems it is ';'). Empty components are
* ignored.
* <p>
* UNIX Examples:
* <dl>
* <dt>A:B:C <dd>A, B, C
* <dt>::B: <dd>B
* <dt>:A <dd>A
* <dt>(Empty string) <dd>(Zero components)
* </dl>
*
* @see File#pathSeparatorChar
*/
public static File[]
parsePath(String s) {
int from = 0;
List<File> l = new ArrayList();
for (;;) {
int to = s.indexOf(File.pathSeparatorChar, from);
if (to == -1) {
if (from != s.length()) l.add(new File(s.substring(from)));
break;
}
if (to != from) l.add(new File(s.substring(from, to)));
from = to + 1;
}
return (File[]) l.toArray(new File[l.size()]);
}
/**
* A factory method that creates a Java classpath-style ResourceFinder as
* follows:
* <table>
* <tr><th><code>entry</code></th><th>Returned {@link ResourceFinder}</th></tr>
* <tr><td>"*.jar" file</td><td>{@link ZipFileResourceFinder}</td></tr>
* <tr><td>"*.zip" file</td><td>{@link ZipFileResourceFinder}</td></tr>
* <tr><td>directory</td><td>{@link DirectoryResourceFinder}</td></tr>
* <tr><td>any other</td><td>A {@link ResourceFinder} that never finds a resource</td></tr>
* </table>
* @return a valid {@link ResourceFinder}
*/
private static ResourceFinder
createResourceFinder(final File entry) {
// ZIP file or JAR file.
if (
(entry.getName().endsWith(".jar") || entry.getName().endsWith(".zip"))
&& entry.isFile()
) {
try {
return new ZipFileResourceFinder(new ZipFile(entry));
} catch (IOException e) {
return ResourceFinder.EMPTY_RESOURCE_FINDER;
}
}
// Directory.
if (entry.isDirectory()) {
return new DirectoryResourceFinder(entry);
}
// Invalid entry.
return ResourceFinder.EMPTY_RESOURCE_FINDER;
}
}

View File

@ -0,0 +1,64 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.IOException;
import java.io.InputStream;
/**
* A {@link Resource} is "something" that is typically found by a
* {@link org.codehaus.janino.util.resource.ResourceFinder}, can be {@link #open()}ed for
* reading, and optionally has a {@link #lastModified()} property.
* <p>
* There also exists a {@link org.codehaus.janino.util.resource.ResourceCreator} concept which
* opens a resource for writing, but that happens directly and not through an intermediate
* {@link Resource} object.
*
* @see org.codehaus.janino.util.resource.ResourceFinder
* @see org.codehaus.janino.util.resource.ResourceCreator
*/
public
interface Resource {
/** Opens the resource. The caller is responsible for closing the {@link java.io.InputStream}. */
InputStream open() throws IOException;
/**
* Returns a decorative "file name" that can be used for reporting
* errors and the like. It does not necessarily map to a file in the
* local file system!
*/
String getFileName();
/**
* Returns the time of the last modification, in milliseconds since
* 1970, or <code>0L</code> if the time of the last modification cannot
* be determined.
*/
long lastModified();
}

View File

@ -0,0 +1,59 @@
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino.util.resource;
import java.io.IOException;
import java.io.OutputStream;
/**
* Opens a resource, characterized by a name, for writing.
* <p>
* There also exists a concept {@link org.codehaus.janino.util.resource.ResourceFinder} that
* finds {@link org.codehaus.janino.util.resource.Resource}s for reading.
*
* @see org.codehaus.janino.util.resource.ResourceFinder
*/
public
interface ResourceCreator {
/**
* Create the designated resource.
*
* @param resourceName Designates the resource; typically structured by slashes ("/") like
* "<code>com/foo/pkg/Bar.class</code>"
* @return Bytes written to this {@link OutputStream} are stored in the resource
* @throws IOException Problems creating the resource
*/
OutputStream createResource(String resourceName) throws IOException;
/**
* Deletes the resource with the given name.
*
* @return <code>false</code> if the resource could not be deleted
*/
boolean deleteResource(String resourceName);
}

Some files were not shown because too many files have changed in this diff Show More