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.
This commit is contained in:
parent
bde746b3b7
commit
0f5ef77944
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
Binary file not shown.
30
README.txt
30
README.txt
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
libs/dx.jar
BIN
libs/dx.jar
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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")
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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™ 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;
|
||||
}
|
|
@ -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™ source for class {@code pkg.Cls} in resource {@code
|
||||
* pkg/Cls.java}
|
||||
* @param optionalCharacterEncoding Encoding of Java™ 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) {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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™ 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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™ 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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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™ 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™ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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); }
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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()]);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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();
|
||||
}
|
|
@ -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
|
@ -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™ 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™ 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™ source files in
|
||||
* the given order
|
||||
* @param optionalCharacterEncoding The encoding of the Java™ 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™ 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™ 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;
|
||||
}
|
|
@ -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™ 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) {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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); }
|
||||
}
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
@ -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
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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™ 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");
|
||||
}
|
||||
}
|
|
@ -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)
|
|
@ -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); }
|
||||
}
|
|
@ -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. "\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
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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™ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {}
|
||||
}
|
|
@ -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; }
|
||||
}
|
|
@ -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); }
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"); }
|
||||
}
|
|
@ -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(); }
|
||||
}
|
|
@ -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); }
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"); }
|
||||
}
|
|
@ -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"); }
|
||||
}
|
|
@ -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(); }
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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(); }
|
||||
}
|
|
@ -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() {}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
));
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
|
@ -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; }
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue