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
BIN
BCV Icon.ico
Normal file
BIN
BCV Icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
BytecodeViewer 2.9.0.jar
Normal file
BIN
BytecodeViewer 2.9.0.jar
Normal file
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.
|
14
_install BCV.bat
Normal file
14
_install BCV.bat
Normal file
|
@ -0,0 +1,14 @@
|
|||
@echo off
|
||||
assoc .class=BCV
|
||||
assoc .apk=BCV
|
||||
assoc .dex=BCV
|
||||
ftype BCV="%CD%\BytecodeViewer.exe" "%%1"
|
||||
echo.
|
||||
echo.
|
||||
echo Installed, .class, .apk and .dex will be associated with BytecodeViwer.exe
|
||||
echo.
|
||||
echo Note, if you move BytecodeViewer.exe
|
||||
echo you'll need to re-run this program in the same directory as it.
|
||||
echo.
|
||||
echo.
|
||||
pause
|
10
_uninstall BCV.bat
Normal file
10
_uninstall BCV.bat
Normal file
|
@ -0,0 +1,10 @@
|
|||
@echo off
|
||||
assoc .class=
|
||||
assoc .apk=
|
||||
assoc .dex=
|
||||
echo.
|
||||
echo.
|
||||
echo Uninstalled, .class, .apk and .dex will no longer be associated.
|
||||
echo.
|
||||
echo.
|
||||
pause
|
1
jar2exe_config.j2e
Normal file
1
jar2exe_config.j2e
Normal file
|
@ -0,0 +1 @@
|
|||
"C:\Program Files\Jar2Exe Wizard\j2ewiz" /jar "C:\Users\null\Documents\GitHub\bytecode-viewer\BytecodeViewer 2.9.0.jar" /o C:\Users\null\Documents\GitHub\bytecode-viewer\BytecodeViewer.exe /m the.bytecode.club.bytecodeviewer.BytecodeViewer /type windows /minjre 1.7 /platform windows /checksum /icon "C:\Users\null\Documents\GitHub\bytecode-viewer\BCV Icon.ico, 0" /pv 1,0,0,1 /fv 1,0,0,1 /ve ProductVersion=1.9.0 /ve "ProductName=The Bytecode Club" /ve "LegalCopyright=Copyright (c) 2014 - 2015 Kalen (Konloch) Kinloch" /ve "SpecialBuild=1, 0, 0, 1" /ve FileVersion=1 /ve "FileDescription=Java Reverse Engineering Suite" /ve "LegalTrademarks=Trade marks" /ve "InternalName=1, 0, 0, 1" /ve "CompanyName=The Bytecode Club"
|
BIN
libs/apktool_2.0.0rc4_obf.jar
Normal file
BIN
libs/apktool_2.0.0rc4_obf.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
libs/asm-all-5.0.3.jar
Normal file
BIN
libs/asm-all-5.0.3.jar
Normal file
Binary file not shown.
BIN
libs/commons-compiler-jdk.jar
Normal file
BIN
libs/commons-compiler-jdk.jar
Normal file
Binary file not shown.
BIN
libs/commons-compiler.jar
Normal file
BIN
libs/commons-compiler.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
libs/dex_obf.jar
Normal file
BIN
libs/dex_obf.jar
Normal file
Binary file not shown.
BIN
libs/dx.jar
BIN
libs/dx.jar
Binary file not shown.
Binary file not shown.
49
plugins/EldevinStringDecrypter.gy
Normal file
49
plugins/EldevinStringDecrypter.gy
Normal file
|
@ -0,0 +1,49 @@
|
|||
import the.bytecode.club.bytecodeviewer.api.*;
|
||||
import java.util.ArrayList;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
import java.lang.reflect.Field;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
|
||||
public class EldevinStringDecrypter extends Plugin {
|
||||
|
||||
@Override
|
||||
public void execute(ArrayList<ClassNode> classNodesList) {
|
||||
PluginConsole gui = new PluginConsole("Eldevin String Decrypter");
|
||||
|
||||
JOptionPane pane = new JOptionPane("WARNING: This method of decryption loads the classes into a classloader and executes the init function, this could lead to malicious code executing.\n\r\n\rAre you sure you want to run this plugin?");
|
||||
String[] options = ["Yes", "No"];
|
||||
pane.setOptions(options);
|
||||
JDialog dialog = pane.createDialog(the.bytecode.club.bytecodeviewer.BytecodeViewer.viewer, "WARNING");
|
||||
dialog.show();
|
||||
Object obj = pane.getValue();
|
||||
int result = -1;
|
||||
for (int k = 0; k < options.length; k++)
|
||||
if (options[k].equals(obj))
|
||||
result = k;
|
||||
|
||||
|
||||
if(result == 0) {
|
||||
for(ClassNode cn : classNodesList) {
|
||||
the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().addClass(cn);
|
||||
|
||||
for(Object o : cn.fields.toArray()) {
|
||||
FieldNode f = (FieldNode) o;
|
||||
if(f.name.equals("z")) {// && f.desc.equals("([Ljava/lang/String;)V")) {
|
||||
try {
|
||||
for(Field f2 : the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().nodeToClass(cn).getFields()) {
|
||||
String s = f2.get(null);
|
||||
if(s != null && !s.empty())
|
||||
gui.appendText(cn+":"+s);
|
||||
}
|
||||
} catch(Exception | StackOverflowError e) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gui.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
15
plugins/Skeleton.rb
Normal file
15
plugins/Skeleton.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
require 'java'
|
||||
|
||||
java_import 'the.bytecode.club.bytecodeviewer.api.Plugin'
|
||||
java_import 'the.bytecode.club.bytecodeviewer.api.PluginConsole'
|
||||
java_import 'java.lang.System'
|
||||
java_import 'java.util.ArrayList'
|
||||
java_import 'org.objectweb.asm.tree.ClassNode'
|
||||
|
||||
class Skeleton < Plugin
|
||||
def execute(classNodeList)
|
||||
gui = PluginConsole.new "Skeleton"
|
||||
gui.setVisible(true)
|
||||
gui.appendText("exceuted skeleton")
|
||||
end
|
||||
end
|
14
plugins/Test.gy
Normal file
14
plugins/Test.gy
Normal file
|
@ -0,0 +1,14 @@
|
|||
import the.bytecode.club.bytecodeviewer.api.*;
|
||||
import java.util.ArrayList;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.*;
|
||||
|
||||
public class Test extends Plugin {
|
||||
|
||||
@Override
|
||||
public void execute(ArrayList<ClassNode> classNodesList) {
|
||||
PluginConsole gui = new PluginConsole("Skeleton");
|
||||
gui.setVisible(true);
|
||||
gui.appendText(Smali.decompileClassNode(the.bytecode.club.bytecodeviewer.BytecodeViewer.viewer.workPane.getCurrentClass().cn));
|
||||
}
|
||||
}
|
13
plugins/skeleton.py
Normal file
13
plugins/skeleton.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from the.bytecode.club.bytecodeviewer.api import Plugin
|
||||
from the.bytecode.club.bytecodeviewer.api import PluginConsole
|
||||
from java.lang import System
|
||||
from java.lang import Boolean
|
||||
from java.util import ArrayList
|
||||
from org.objectweb.asm.tree import ClassNode
|
||||
|
||||
class skeleton(Plugin):
|
||||
|
||||
def execute(classNodeList, poop): #for some reason it requires a second arg
|
||||
gui = PluginConsole("Skeleton")
|
||||
gui.setVisible(Boolean.TRUE)
|
||||
gui.appendText("exceuted skeleton")
|
56
src/org/codehaus/janino/Access.java
Normal file
56
src/org/codehaus/janino/Access.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import org.codehaus.janino.util.enumerator.Enumerator;
|
||||
import org.codehaus.janino.util.enumerator.EnumeratorFormatException;
|
||||
|
||||
/** Return value for {@link IClass.IMember#getAccess}. */
|
||||
public final
|
||||
class Access extends Enumerator {
|
||||
|
||||
/** Representation of PRIVATE accessibility. */
|
||||
public static final Access PRIVATE = new Access("private");
|
||||
|
||||
/** Representation of PROTECTED accessibility. */
|
||||
public static final Access PROTECTED = new Access("protected");
|
||||
|
||||
/** Representation of DEFAULT accessibility. */
|
||||
public static final Access DEFAULT = new Access("/*default*/");
|
||||
|
||||
/** Representation of PUBLIC accessibility. */
|
||||
public static final Access PUBLIC = new Access("public");
|
||||
|
||||
// These MUST be declared exactly like this:
|
||||
private Access(String name) { super(name); }
|
||||
|
||||
/** @return The {@code name} converted to {@link Access} */
|
||||
public static Access
|
||||
fromString(String name) throws EnumeratorFormatException {
|
||||
return (Access) Enumerator.fromString(name, Access.class);
|
||||
}
|
||||
}
|
74
src/org/codehaus/janino/ByteArrayClassLoader.java
Normal file
74
src/org/codehaus/janino/ByteArrayClassLoader.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/** This {@link ClassLoader} allows for the loading of a set of Java™ 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;
|
||||
}
|
218
src/org/codehaus/janino/CachingJavaSourceClassLoader.java
Normal file
218
src/org/codehaus/janino/CachingJavaSourceClassLoader.java
Normal file
|
@ -0,0 +1,218 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.resource.DirectoryResourceCreator;
|
||||
import org.codehaus.janino.util.resource.DirectoryResourceFinder;
|
||||
import org.codehaus.janino.util.resource.PathResourceFinder;
|
||||
import org.codehaus.janino.util.resource.Resource;
|
||||
import org.codehaus.janino.util.resource.ResourceCreator;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
/**
|
||||
* A {@link org.codehaus.janino.JavaSourceClassLoader} that uses a resource storage provided by the application to cache
|
||||
* compiled classes and thus saving unnecessary recompilations.
|
||||
* <p>
|
||||
* The application provides access to the resource storeage through a pair of a {@link
|
||||
* org.codehaus.janino.util.resource.ResourceFinder} and a {@link org.codehaus.janino.util.resource.ResourceCreator}
|
||||
* (see {@link #CachingJavaSourceClassLoader(ClassLoader, ResourceFinder, String, ResourceFinder, ResourceCreator)}.
|
||||
* <p>
|
||||
* See {@link org.codehaus.janino.JavaSourceClassLoader#main(String[])} for an example how to use this class.
|
||||
* <p>
|
||||
* <b>Notice:</b> You must NOT rely on that this class stores some particular data in some particular resources through
|
||||
* the given {@code classFileCacheResourceFinder/Creator}! These serve only as a means for the {@link
|
||||
* CachingJavaSourceClassLoader} to persistently cache some data between invocations. In other words: If you want to
|
||||
* compile {@code .java} files into {@code .class} files, then don't use <i>this</i> class but {@link Compiler}
|
||||
* instead!
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class CachingJavaSourceClassLoader extends JavaSourceClassLoader {
|
||||
private final ResourceFinder classFileCacheResourceFinder;
|
||||
private final ResourceCreator classFileCacheResourceCreator;
|
||||
private final ResourceFinder sourceFinder;
|
||||
|
||||
/**
|
||||
* See {@link #CachingJavaSourceClassLoader(ClassLoader, ResourceFinder, String, ResourceFinder, ResourceCreator)}.
|
||||
*
|
||||
* @param optionalSourcePath Directories to scan for source files
|
||||
* @param cacheDirectory Directory to use for caching generated class files (see class description)
|
||||
*/
|
||||
public
|
||||
CachingJavaSourceClassLoader(
|
||||
ClassLoader parentClassLoader,
|
||||
File[] optionalSourcePath,
|
||||
String optionalCharacterEncoding,
|
||||
File cacheDirectory
|
||||
) {
|
||||
this(
|
||||
parentClassLoader, // parentClassLoader
|
||||
( // sourceFinder
|
||||
optionalSourcePath == null
|
||||
? (ResourceFinder) new DirectoryResourceFinder(new File("."))
|
||||
: (ResourceFinder) new PathResourceFinder(optionalSourcePath)
|
||||
),
|
||||
optionalCharacterEncoding, // optionalCharacterEncoding
|
||||
new DirectoryResourceFinder(cacheDirectory), // classFileCacheResourceFinder
|
||||
new DirectoryResourceCreator(cacheDirectory) // classFileCacheResourceCreator
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice that this class is thread-safe if and only if the {@code classFileCacheResourceCreator} stores its data
|
||||
* atomically, i.e. the {@code classFileCacheResourceFinder} sees the resource written by the {@code
|
||||
* classFileCacheResourceCreator} only after the {@link OutputStream} is closed.
|
||||
* <p>
|
||||
* In order to make the caching scheme work, both the {@code classFileCacheResourceFinder} and the {@code
|
||||
* sourceFinder} must support the {@link org.codehaus.janino.util.resource.Resource#lastModified()} method, so that
|
||||
* the modification time of the source and the class files can be compared.
|
||||
*
|
||||
* @param parentClassLoader Attempt to load classes through this one before looking for source files
|
||||
* @param sourceFinder Finds Java™ 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) {}
|
||||
}
|
||||
}
|
||||
}
|
445
src/org/codehaus/janino/ClassBodyEvaluator.java
Normal file
445
src/org/codehaus/janino/ClassBodyEvaluator.java
Normal file
|
@ -0,0 +1,445 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.CompilerFactoryFactory;
|
||||
import org.codehaus.commons.compiler.Cookable;
|
||||
import org.codehaus.commons.compiler.IClassBodyEvaluator;
|
||||
import org.codehaus.commons.compiler.ICompilerFactory;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
|
||||
/**
|
||||
* The <code>optionalClassLoader</code> serves two purposes:
|
||||
* <ul>
|
||||
* <li>It is used to look for classes referenced by the class body.
|
||||
* <li>It is used to load the generated Java™ 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);
|
||||
}
|
||||
}
|
||||
}
|
438
src/org/codehaus/janino/ClassFileIClass.java
Normal file
438
src/org/codehaus/janino/ClassFileIClass.java
Normal file
|
@ -0,0 +1,438 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.ClassFile.ConstantClassInfo;
|
||||
|
||||
/** A wrapper object that turns a {@link ClassFile} object into an {@link IClass}. */
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class ClassFileIClass extends IClass {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final ClassFile classFile;
|
||||
private final IClassLoader iClassLoader;
|
||||
private final short accessFlags;
|
||||
|
||||
private final Map<ClassFile.FieldInfo, IField> resolvedFields = new HashMap();
|
||||
|
||||
/**
|
||||
* @param classFile Source of data
|
||||
* @param iClassLoader {@link IClassLoader} through which to load other classes
|
||||
*/
|
||||
public
|
||||
ClassFileIClass(ClassFile classFile, IClassLoader iClassLoader) {
|
||||
this.classFile = classFile;
|
||||
this.iClassLoader = iClassLoader;
|
||||
|
||||
// Determine class access flags.
|
||||
this.accessFlags = classFile.accessFlags;
|
||||
}
|
||||
|
||||
// Implement IClass.
|
||||
|
||||
@Override protected IConstructor[]
|
||||
getDeclaredIConstructors2() {
|
||||
List iConstructors = new ArrayList();
|
||||
|
||||
for (ClassFile.MethodInfo mi : this.classFile.methodInfos) {
|
||||
IInvocable ii;
|
||||
try {
|
||||
ii = this.resolveMethod(mi);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new JaninoRuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ii instanceof IConstructor) iConstructors.add(ii);
|
||||
}
|
||||
|
||||
return (IConstructor[]) iConstructors.toArray(new IConstructor[iConstructors.size()]);
|
||||
}
|
||||
|
||||
@Override protected IMethod[]
|
||||
getDeclaredIMethods2() {
|
||||
List<IMethod> iMethods = new ArrayList();
|
||||
|
||||
for (ClassFile.MethodInfo mi : this.classFile.methodInfos) {
|
||||
|
||||
// Skip JDK 1.5 synthetic methods (e.g. those generated for
|
||||
// covariant return values).
|
||||
if (Mod.isSynthetic(mi.getModifierFlags())) continue;
|
||||
|
||||
IInvocable ii;
|
||||
try {
|
||||
ii = this.resolveMethod(mi);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new JaninoRuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ii instanceof IMethod) iMethods.add((IMethod) ii);
|
||||
}
|
||||
|
||||
return (IMethod[]) iMethods.toArray(new IMethod[iMethods.size()]);
|
||||
}
|
||||
|
||||
@Override protected IField[]
|
||||
getDeclaredIFields2() {
|
||||
IField[] ifs = new IClass.IField[this.classFile.fieldInfos.size()];
|
||||
for (int i = 0; i < this.classFile.fieldInfos.size(); ++i) {
|
||||
try {
|
||||
ifs[i] = this.resolveField((ClassFile.FieldInfo) this.classFile.fieldInfos.get(i));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new JaninoRuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
return ifs;
|
||||
}
|
||||
|
||||
@Override protected IClass[]
|
||||
getDeclaredIClasses2() throws CompileException {
|
||||
ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute();
|
||||
if (ica == null) return new IClass[0];
|
||||
|
||||
List<IClass> res = new ArrayList();
|
||||
for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) {
|
||||
if (e.outerClassInfoIndex == this.classFile.thisClass) {
|
||||
try {
|
||||
res.add(this.resolveClass(e.innerClassInfoIndex));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
|
||||
}
|
||||
}
|
||||
}
|
||||
return (IClass[]) res.toArray(new IClass[res.size()]);
|
||||
}
|
||||
|
||||
@Override protected IClass
|
||||
getDeclaringIClass2() throws CompileException {
|
||||
ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute();
|
||||
if (ica == null) return null;
|
||||
|
||||
for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) {
|
||||
if (e.innerClassInfoIndex == this.classFile.thisClass) {
|
||||
// Is this an anonymous class?
|
||||
if (e.outerClassInfoIndex == 0) return null;
|
||||
try {
|
||||
return this.resolveClass(e.outerClassInfoIndex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override protected IClass
|
||||
getOuterIClass2() throws CompileException {
|
||||
ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute();
|
||||
if (ica == null) return null;
|
||||
|
||||
for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) {
|
||||
if (e.innerClassInfoIndex == this.classFile.thisClass) {
|
||||
if (e.outerClassInfoIndex == 0) {
|
||||
|
||||
// Anonymous class or local class.
|
||||
// TODO: Determine enclosing instance of anonymous class or local class
|
||||
return null;
|
||||
} else {
|
||||
|
||||
// Member type.
|
||||
if (Mod.isStatic(e.innerClassAccessFlags)) return null;
|
||||
try {
|
||||
return this.resolveClass(e.outerClassInfoIndex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override protected IClass
|
||||
getSuperclass2() throws CompileException {
|
||||
if (this.classFile.superclass == 0) return null;
|
||||
try {
|
||||
return this.resolveClass(this.classFile.superclass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new CompileException(e.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Access
|
||||
getAccess() { return ClassFileIClass.accessFlags2Access(this.accessFlags); }
|
||||
|
||||
@Override public boolean
|
||||
isFinal() { return Mod.isFinal(this.accessFlags); }
|
||||
|
||||
@Override protected IClass[]
|
||||
getInterfaces2() throws CompileException { return this.resolveClasses(this.classFile.interfaces); }
|
||||
|
||||
@Override public boolean
|
||||
isAbstract() { return Mod.isAbstract(this.accessFlags); }
|
||||
|
||||
@Override protected String
|
||||
getDescriptor2() { return Descriptor.fromClassName(this.classFile.getThisClassName()); }
|
||||
|
||||
@Override public boolean
|
||||
isInterface() { return Mod.isInterface(this.accessFlags); }
|
||||
|
||||
@Override public boolean
|
||||
isArray() { return false; }
|
||||
|
||||
@Override public boolean
|
||||
isPrimitive() { return false; }
|
||||
|
||||
@Override public boolean
|
||||
isPrimitiveNumeric() { return false; }
|
||||
|
||||
@Override protected IClass
|
||||
getComponentType2() { return null; }
|
||||
|
||||
/** Resolves all classes referenced by this class file. */
|
||||
public void
|
||||
resolveAllClasses() throws ClassNotFoundException {
|
||||
for (short i = 0; i < this.classFile.getConstantPoolSize(); ++i) {
|
||||
ClassFile.ConstantPoolInfo cpi = this.classFile.getConstantPoolInfo(i);
|
||||
if (cpi instanceof ClassFile.ConstantClassInfo) {
|
||||
this.resolveClass(i);
|
||||
} else
|
||||
if (cpi instanceof ClassFile.ConstantNameAndTypeInfo) {
|
||||
String descriptor = ((ClassFile.ConstantNameAndTypeInfo) cpi).getDescriptor(this.classFile);
|
||||
if (descriptor.charAt(0) == '(') {
|
||||
MethodDescriptor md = new MethodDescriptor(descriptor);
|
||||
this.resolveClass(md.returnFd);
|
||||
for (String parameterFd : md.parameterFds) this.resolveClass(parameterFd);
|
||||
} else {
|
||||
this.resolveClass(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param index Index of the CONSTANT_Class_info to resolve (JVMS 4.4.1) */
|
||||
private IClass
|
||||
resolveClass(short index) throws ClassNotFoundException {
|
||||
if (ClassFileIClass.DEBUG) System.out.println("index=" + index);
|
||||
ConstantClassInfo cci = (ConstantClassInfo) this.classFile.getConstantPoolInfo(index);
|
||||
return this.resolveClass(Descriptor.fromInternalForm(cci.getName(this.classFile)));
|
||||
}
|
||||
|
||||
private IClass
|
||||
resolveClass(String descriptor) throws ClassNotFoundException {
|
||||
if (ClassFileIClass.DEBUG) System.out.println("descriptor=" + descriptor);
|
||||
|
||||
IClass result = (IClass) this.resolvedClasses.get(descriptor);
|
||||
if (result != null) return result;
|
||||
|
||||
result = this.iClassLoader.loadIClass(descriptor);
|
||||
if (result == null) throw new ClassNotFoundException(descriptor);
|
||||
|
||||
this.resolvedClasses.put(descriptor, result);
|
||||
return result;
|
||||
}
|
||||
private final Map<String /*descriptor*/, IClass> resolvedClasses = new HashMap();
|
||||
|
||||
private IClass[]
|
||||
resolveClasses(short[] ifs) throws CompileException {
|
||||
IClass[] result = new IClass[ifs.length];
|
||||
for (int i = 0; i < result.length; ++i) {
|
||||
try {
|
||||
result[i] = this.resolveClass(ifs[i]);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new CompileException(e.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a {@link ClassFile.MethodInfo} into an {@link IInvocable}. This includes the checking and the
|
||||
* removal of the magic first parameter of an inner class constructor.
|
||||
*
|
||||
* @param methodInfo
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
private IInvocable
|
||||
resolveMethod(final ClassFile.MethodInfo methodInfo) throws ClassNotFoundException {
|
||||
IInvocable result = (IInvocable) this.resolvedMethods.get(methodInfo);
|
||||
if (result != null) return result;
|
||||
|
||||
// Determine method name.
|
||||
final String name = methodInfo.getName();
|
||||
|
||||
// Determine return type.
|
||||
MethodDescriptor md = new MethodDescriptor(methodInfo.getDescriptor());
|
||||
|
||||
final IClass returnType = this.resolveClass(md.returnFd);
|
||||
|
||||
// Determine parameter types.
|
||||
final IClass[] parameterTypes = new IClass[md.parameterFds.length];
|
||||
for (int i = 0; i < parameterTypes.length; ++i) parameterTypes[i] = this.resolveClass(md.parameterFds[i]);
|
||||
|
||||
// Determine thrown exceptions.
|
||||
IClass[] tes = null;
|
||||
ClassFile.AttributeInfo[] ais = methodInfo.getAttributes();
|
||||
for (ClassFile.AttributeInfo ai : ais) {
|
||||
if (ai instanceof ClassFile.ExceptionsAttribute) {
|
||||
ConstantClassInfo[] ccis = ((ClassFile.ExceptionsAttribute) ai).getExceptions(this.classFile);
|
||||
tes = new IClass[ccis.length];
|
||||
for (int i = 0; i < tes.length; ++i) {
|
||||
tes[i] = this.resolveClass(Descriptor.fromInternalForm(ccis[i].getName(this.classFile)));
|
||||
}
|
||||
}
|
||||
}
|
||||
final IClass[] thrownExceptions = tes == null ? new IClass[0] : tes;
|
||||
|
||||
// Determine access.
|
||||
final Access access = ClassFileIClass.accessFlags2Access(methodInfo.getModifierFlags());
|
||||
|
||||
if ("<init>".equals(name)) {
|
||||
result = new IClass.IConstructor() {
|
||||
|
||||
@Override public boolean
|
||||
isVarargs() { return Mod.isVarargs(methodInfo.getModifierFlags()); }
|
||||
|
||||
@Override public IClass[]
|
||||
getParameterTypes2() throws CompileException {
|
||||
|
||||
// Process magic first parameter of inner class constructor.
|
||||
IClass outerIClass = ClassFileIClass.this.getOuterIClass();
|
||||
if (outerIClass != null) {
|
||||
if (parameterTypes.length < 1) {
|
||||
throw new JaninoRuntimeException("Inner class constructor lacks magic first parameter");
|
||||
}
|
||||
if (parameterTypes[0] != outerIClass) {
|
||||
throw new JaninoRuntimeException(
|
||||
"Magic first parameter of inner class constructor has type \""
|
||||
+ parameterTypes[0].toString()
|
||||
+ "\" instead of that of its enclosing instance (\""
|
||||
+ outerIClass.toString()
|
||||
+ "\")"
|
||||
);
|
||||
}
|
||||
IClass[] tmp = new IClass[parameterTypes.length - 1];
|
||||
System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
@Override public IClass[] getThrownExceptions2() { return thrownExceptions; }
|
||||
@Override public Access getAccess() { return access; }
|
||||
@Override public Java.Annotation[] getAnnotations() { return methodInfo.getAnnotations(); }
|
||||
};
|
||||
} else {
|
||||
result = new IClass.IMethod() {
|
||||
|
||||
@Override public String
|
||||
getName() { return name; }
|
||||
|
||||
@Override public IClass
|
||||
getReturnType() { return returnType; }
|
||||
|
||||
@Override public boolean
|
||||
isStatic() { return Mod.isStatic(methodInfo.getModifierFlags()); }
|
||||
|
||||
@Override public boolean
|
||||
isAbstract() { return Mod.isAbstract(methodInfo.getModifierFlags()); }
|
||||
|
||||
@Override public boolean
|
||||
isVarargs() { return Mod.isVarargs(methodInfo.getModifierFlags()); }
|
||||
|
||||
@Override public IClass[]
|
||||
getParameterTypes2() { return parameterTypes; }
|
||||
|
||||
@Override public IClass[]
|
||||
getThrownExceptions2() { return thrownExceptions; }
|
||||
|
||||
@Override public Access
|
||||
getAccess() { return access; }
|
||||
|
||||
@Override public Java.Annotation[]
|
||||
getAnnotations() { return methodInfo.getAnnotations(); }
|
||||
};
|
||||
}
|
||||
this.resolvedMethods.put(methodInfo, result);
|
||||
return result;
|
||||
}
|
||||
private final Map<ClassFile.MethodInfo, IInvocable> resolvedMethods = new HashMap();
|
||||
|
||||
private IField
|
||||
resolveField(final ClassFile.FieldInfo fieldInfo) throws ClassNotFoundException {
|
||||
IField result = (IField) this.resolvedFields.get(fieldInfo);
|
||||
if (result != null) return result;
|
||||
|
||||
// Determine field name.
|
||||
final String name = fieldInfo.getName(this.classFile);
|
||||
|
||||
// Determine field type.
|
||||
final String descriptor = fieldInfo.getDescriptor(this.classFile);
|
||||
final IClass type = this.resolveClass(descriptor);
|
||||
|
||||
// Determine optional "constant value" of the field (JLS7 15.28, bullet 14). If a field has a "ConstantValue"
|
||||
// attribute, we assume that it has a constant value. Notice that this assumption is not always correct,
|
||||
// because typical Java™ 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
|
||||
);
|
||||
}
|
||||
}
|
95
src/org/codehaus/janino/ClassLoaderIClassLoader.java
Normal file
95
src/org/codehaus/janino/ClassLoaderIClassLoader.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
/** An {@link IClassLoader} that loads {@link IClass}es through a reflection {@link ClassLoader}. */
|
||||
@SuppressWarnings("rawtypes") public
|
||||
class ClassLoaderIClassLoader extends IClassLoader {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/** @param classLoader The delegate that loads the classes. */
|
||||
public
|
||||
ClassLoaderIClassLoader(ClassLoader classLoader) {
|
||||
super(
|
||||
null // optionalParentIClassLoader
|
||||
);
|
||||
|
||||
if (classLoader == null) throw new NullPointerException();
|
||||
|
||||
this.classLoader = classLoader;
|
||||
super.postConstruct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to
|
||||
* <pre>
|
||||
* ClassLoaderIClassLoader(Thread.currentThread().getContextClassLoader())
|
||||
* </pre>
|
||||
*/
|
||||
public
|
||||
ClassLoaderIClassLoader() { this(Thread.currentThread().getContextClassLoader()); }
|
||||
|
||||
/** @return The delegate {@link ClassLoader} */
|
||||
public ClassLoader
|
||||
getClassLoader() { return this.classLoader; }
|
||||
|
||||
@Override protected IClass
|
||||
findIClass(String descriptor) throws ClassNotFoundException {
|
||||
|
||||
Class clazz;
|
||||
try {
|
||||
|
||||
//
|
||||
// See also [ 931385 ] Janino 2.0 throwing exception on arrays of java.io.File:
|
||||
//
|
||||
// "ClassLoader.loadClass()" and "Class.forName()" should be identical,
|
||||
// but "ClassLoader.loadClass("[Ljava.lang.Object;")" throws a
|
||||
// ClassNotFoundException under JDK 1.5.0 beta.
|
||||
// Unclear whether this a beta version bug and SUN will fix this in the final
|
||||
// release, but "Class.forName()" seems to work fine in all cases, so we
|
||||
// use that.
|
||||
//
|
||||
|
||||
// clazz = this.classLoader.loadClass(Descriptor.toClassName(descriptor));
|
||||
clazz = Class.forName(Descriptor.toClassName(descriptor), false, this.classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
if (e.getException() == null) {
|
||||
return null;
|
||||
} else
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (ClassLoaderIClassLoader.DEBUG) System.out.println("clazz = " + clazz);
|
||||
|
||||
IClass result = new ReflectionIClass(clazz, this);
|
||||
this.defineIClass(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
}
|
1371
src/org/codehaus/janino/CodeContext.java
Normal file
1371
src/org/codehaus/janino/CodeContext.java
Normal file
File diff suppressed because it is too large
Load Diff
830
src/org/codehaus/janino/Compiler.java
Normal file
830
src/org/codehaus/janino/Compiler.java
Normal file
|
@ -0,0 +1,830 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.ErrorHandler;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
import org.codehaus.commons.compiler.WarningHandler;
|
||||
import org.codehaus.janino.Java.CompilationUnit;
|
||||
import org.codehaus.janino.util.Benchmark;
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.StringPattern;
|
||||
import org.codehaus.janino.util.resource.DirectoryResourceCreator;
|
||||
import org.codehaus.janino.util.resource.DirectoryResourceFinder;
|
||||
import org.codehaus.janino.util.resource.FileResource;
|
||||
import org.codehaus.janino.util.resource.FileResourceCreator;
|
||||
import org.codehaus.janino.util.resource.PathResourceFinder;
|
||||
import org.codehaus.janino.util.resource.Resource;
|
||||
import org.codehaus.janino.util.resource.ResourceCreator;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
|
||||
/**
|
||||
* A simplified substitute for the <tt>javac</tt> tool.
|
||||
*
|
||||
* Usage:
|
||||
* <pre>
|
||||
* java org.codehaus.janino.Compiler \
|
||||
* [ -d <i>destination-dir</i> ] \
|
||||
* [ -sourcepath <i>dirlist</i> ] \
|
||||
* [ -classpath <i>dirlist</i> ] \
|
||||
* [ -extdirs <i>dirlist</i> ] \
|
||||
* [ -bootclasspath <i>dirlist</i> ] \
|
||||
* [ -encoding <i>encoding</i> ] \
|
||||
* [ -verbose ] \
|
||||
* [ -g:none ] \
|
||||
* [ -g:{source,lines,vars} ] \
|
||||
* [ -warn:<i>pattern-list</i> ] \
|
||||
* <i>source-file</i> ...
|
||||
* java org.codehaus.janino.Compiler -help
|
||||
* </pre>
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class Compiler {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/** Command line interface. */
|
||||
public static void BCV(String[] args) throws Exception {
|
||||
File destinationDirectory = Compiler.NO_DESTINATION_DIRECTORY;
|
||||
File[] optionalSourcePath = null;
|
||||
File[] classPath = { new File(".") };
|
||||
File[] optionalExtDirs = null;
|
||||
File[] optionalBootClassPath = null;
|
||||
String optionalCharacterEncoding = null;
|
||||
boolean verbose = false;
|
||||
boolean debugSource = true;
|
||||
boolean debugLines = true;
|
||||
boolean debugVars = false;
|
||||
StringPattern[] warningHandlePatterns = Compiler.DEFAULT_WARNING_HANDLE_PATTERNS;
|
||||
boolean rebuild = false;
|
||||
|
||||
// Process command line options.
|
||||
int i;
|
||||
for (i = 0; i < args.length; ++i) {
|
||||
String arg = args[i];
|
||||
if (arg.charAt(0) != '-') break;
|
||||
if ("-d".equals(arg)) {
|
||||
destinationDirectory = new File(args[++i]);
|
||||
} else
|
||||
if ("-sourcepath".equals(arg)) {
|
||||
optionalSourcePath = PathResourceFinder.parsePath(args[++i]);
|
||||
} else
|
||||
if ("-classpath".equals(arg)) {
|
||||
classPath = PathResourceFinder.parsePath(args[++i]);
|
||||
} else
|
||||
if ("-extdirs".equals(arg)) {
|
||||
optionalExtDirs = PathResourceFinder.parsePath(args[++i]);
|
||||
} else
|
||||
if ("-bootclasspath".equals(arg)) {
|
||||
optionalBootClassPath = PathResourceFinder.parsePath(args[++i]);
|
||||
} else
|
||||
if ("-encoding".equals(arg)) {
|
||||
optionalCharacterEncoding = args[++i];
|
||||
} else
|
||||
if ("-verbose".equals(arg)) {
|
||||
verbose = true;
|
||||
} else
|
||||
if ("-g".equals(arg)) {
|
||||
debugSource = true;
|
||||
debugLines = true;
|
||||
debugVars = true;
|
||||
} else
|
||||
if (arg.startsWith("-g:")) {
|
||||
if (arg.indexOf("none") != -1) debugSource = (debugLines = (debugVars = false));
|
||||
if (arg.indexOf("source") != -1) debugSource = true;
|
||||
if (arg.indexOf("lines") != -1) debugLines = true;
|
||||
if (arg.indexOf("vars") != -1) debugVars = true;
|
||||
} else
|
||||
if (arg.startsWith("-warn:")) {
|
||||
warningHandlePatterns = StringPattern.parseCombinedPattern(arg.substring(6));
|
||||
} else
|
||||
if ("-rebuild".equals(arg)) {
|
||||
rebuild = true;
|
||||
} else
|
||||
if ("-help".equals(arg)) {
|
||||
System.out.printf(Compiler.USAGE, (Object[]) null);
|
||||
} else
|
||||
{
|
||||
System.err.println("Unrecognized command line option \"" + arg + "\"; try \"-help\".");
|
||||
}
|
||||
}
|
||||
|
||||
// Get source file names.
|
||||
if (i == args.length) {
|
||||
System.err.println("No source files given on command line; try \"-help\".");
|
||||
}
|
||||
File[] sourceFiles = new File[args.length - i];
|
||||
for (int j = i; j < args.length; ++j) sourceFiles[j - i] = new File(args[j]);
|
||||
|
||||
// Create the compiler object.
|
||||
final Compiler compiler = new Compiler(
|
||||
optionalSourcePath,
|
||||
classPath,
|
||||
optionalExtDirs,
|
||||
optionalBootClassPath,
|
||||
destinationDirectory,
|
||||
optionalCharacterEncoding,
|
||||
verbose,
|
||||
debugSource,
|
||||
debugLines,
|
||||
debugVars,
|
||||
warningHandlePatterns,
|
||||
rebuild
|
||||
);
|
||||
|
||||
// Compile source files.
|
||||
compiler.compile(sourceFiles);
|
||||
}
|
||||
|
||||
private static final String USAGE = (
|
||||
""
|
||||
+ "Usage:%n"
|
||||
+ "%n"
|
||||
+ " java " + Compiler.class.getName() + " [ <option> ] ... <source-file> ...%n"
|
||||
+ "%n"
|
||||
+ "Supported <option>s are:%n"
|
||||
+ " -d <output-dir> Where to save class files%n"
|
||||
+ " -sourcepath <dirlist> Where to look for other source files%n"
|
||||
+ " -classpath <dirlist> Where to look for other class files%n"
|
||||
+ " -extdirs <dirlist> Where to look for other class files%n"
|
||||
+ " -bootclasspath <dirlist> Where to look for other class files%n"
|
||||
+ " -encoding <encoding> Encoding of source files, e.g. \"UTF-8\" or \"ISO-8859-1\"%n"
|
||||
+ " -verbose%n"
|
||||
+ " -g Generate all debugging info%n"
|
||||
+ " -g:none Generate no debugging info%n"
|
||||
+ " -g:{source,lines,vars} Generate only some debugging info%n"
|
||||
+ " -warn:<pattern-list> Issue certain warnings; examples:%n"
|
||||
+ " -warn:* Enables all warnings%n"
|
||||
+ " -warn:IASF Only warn against implicit access to static fields%n"
|
||||
+ " -warn:*-IASF Enables all warnings, except those against implicit%n"
|
||||
+ " access to static fields%n"
|
||||
+ " -warn:*-IA*+IASF Enables all warnings, except those against implicit%n"
|
||||
+ " accesses, but do warn against implicit access to%n"
|
||||
+ " static fields%n"
|
||||
+ " -rebuild Compile all source files, even if the class files%n"
|
||||
+ " seems up-to-date%n"
|
||||
+ " -help%n"
|
||||
+ "%n"
|
||||
+ "The default encoding in this environment is \"" + Charset.defaultCharset().toString() + "\"."
|
||||
);
|
||||
|
||||
private final ResourceFinder classFileFinder;
|
||||
/** Special value for "classFileResourceFinder". */
|
||||
public static final ResourceFinder FIND_NEXT_TO_SOURCE_FILE = null;
|
||||
private final ResourceCreator classFileCreator;
|
||||
/** Special value for "classFileResourceCreator". */
|
||||
public static final ResourceCreator CREATE_NEXT_TO_SOURCE_FILE = null;
|
||||
private final String optionalCharacterEncoding;
|
||||
private final Benchmark benchmark;
|
||||
private final boolean debugSource;
|
||||
private final boolean debugLines;
|
||||
private final boolean debugVars;
|
||||
private WarningHandler optionalWarningHandler;
|
||||
private ErrorHandler optionalCompileErrorHandler;
|
||||
|
||||
private final IClassLoader iClassLoader;
|
||||
private final List<UnitCompiler> parsedCompilationUnits = new ArrayList();
|
||||
|
||||
/**
|
||||
* Initialize a Java™ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
src/org/codehaus/janino/CompilerFactory.java
Normal file
78
src/org/codehaus/janino/CompilerFactory.java
Normal file
|
@ -0,0 +1,78 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import org.codehaus.commons.compiler.AbstractCompilerFactory;
|
||||
import org.codehaus.commons.compiler.AbstractJavaSourceClassLoader;
|
||||
import org.codehaus.commons.compiler.IClassBodyEvaluator;
|
||||
import org.codehaus.commons.compiler.ICompilerFactory;
|
||||
import org.codehaus.commons.compiler.IExpressionEvaluator;
|
||||
import org.codehaus.commons.compiler.IScriptEvaluator;
|
||||
import org.codehaus.commons.compiler.ISimpleCompiler;
|
||||
|
||||
/** The JANINO implementation of {@link ICompilerFactory}. */
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class CompilerFactory extends AbstractCompilerFactory {
|
||||
|
||||
@Override public String
|
||||
getId() { return "org.codehaus.janino"; }
|
||||
|
||||
@Override public String
|
||||
toString() { return "janino"; }
|
||||
|
||||
@Override public String
|
||||
getImplementationVersion() { return CompilerFactory.class.getPackage().getImplementationVersion(); }
|
||||
|
||||
@Override public IExpressionEvaluator
|
||||
newExpressionEvaluator() { return new ExpressionEvaluator(); }
|
||||
|
||||
@Override public IScriptEvaluator
|
||||
newScriptEvaluator() { return new ScriptEvaluator(); }
|
||||
|
||||
@Override public IClassBodyEvaluator
|
||||
newClassBodyEvaluator() { return new ClassBodyEvaluator(); }
|
||||
|
||||
@Override public ISimpleCompiler
|
||||
newSimpleCompiler() { return new SimpleCompiler(); }
|
||||
|
||||
@Override public AbstractJavaSourceClassLoader
|
||||
newJavaSourceClassLoader() {
|
||||
return (AbstractJavaSourceClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
|
||||
@Override public Object run() { return new JavaSourceClassLoader(); }
|
||||
});
|
||||
}
|
||||
|
||||
@Override public AbstractJavaSourceClassLoader
|
||||
newJavaSourceClassLoader(final ClassLoader parentClassLoader) {
|
||||
return (AbstractJavaSourceClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
|
||||
@Override public Object run() { return new JavaSourceClassLoader(parentClassLoader); }
|
||||
});
|
||||
}
|
||||
}
|
389
src/org/codehaus/janino/Descriptor.java
Normal file
389
src/org/codehaus/janino/Descriptor.java
Normal file
|
@ -0,0 +1,389 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper class that defines useful methods for handling "field descriptors"
|
||||
* (JVMS 4.3.2) and "method descriptors" (JVMS 4.3.3).<p>
|
||||
* Typical descriptors are:
|
||||
* <ul>
|
||||
* <li><code>I</code> Integer
|
||||
* <li><code>[I</code> Array of integer
|
||||
* <li><code>Lpkg1/pkg2/Cls;</code> Class
|
||||
* <li><code>Lpkg1/pkg2/Outer$Inner;</code> Member class
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public final
|
||||
class Descriptor {
|
||||
private Descriptor() {}
|
||||
|
||||
/** @return Whether this {@link Descriptor} describes a reference (i.e. non-primitive) type */
|
||||
public static boolean
|
||||
isReference(String d) { return d.length() > 1; }
|
||||
|
||||
/**
|
||||
* @return Whether this {@link Descriptor} describes a class or an interface (and not an array or a primitive type)
|
||||
*/
|
||||
public static boolean
|
||||
isClassOrInterfaceReference(String d) { return d.charAt(0) == 'L'; }
|
||||
|
||||
/** @return Whether this {@link Descriptor} describes an array type */
|
||||
public static boolean
|
||||
isArrayReference(String d) { return d.charAt(0) == '['; }
|
||||
|
||||
/**
|
||||
* @return The descriptor of the component of the array type {@code d}
|
||||
* @throws JaninoRuntimeException {@code d} does not describe an array type
|
||||
*/
|
||||
public static String
|
||||
getComponentDescriptor(String d) {
|
||||
if (d.charAt(0) != '[') {
|
||||
throw new JaninoRuntimeException(
|
||||
"Cannot determine component descriptor from non-array descriptor \""
|
||||
+ d
|
||||
+ "\""
|
||||
);
|
||||
}
|
||||
return d.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of slots (1 or two) that a value of the type described by {@code d} occupies on the operand
|
||||
* stack or in the local variable array, or 0 iff {@code d} describes the type VOID
|
||||
*/
|
||||
public static short
|
||||
size(String d) {
|
||||
if (d.equals(Descriptor.VOID)) return 0;
|
||||
if (Descriptor.hasSize1(d)) return 1;
|
||||
if (Descriptor.hasSize2(d)) return 2;
|
||||
throw new JaninoRuntimeException("No size defined for type \"" + Descriptor.toString(d) + "\"");
|
||||
}
|
||||
|
||||
/** @return {@code true} iff {@code d} describes a primitive type except LONG and DOUBLE, or a reference type */
|
||||
public static boolean
|
||||
hasSize1(String d) {
|
||||
if (d.length() == 1) return "BCFISZ".indexOf(d) != -1;
|
||||
return Descriptor.isReference(d);
|
||||
}
|
||||
|
||||
/** @return {@code true} iff {@code d} LONG or DOUBLE */
|
||||
public static boolean
|
||||
hasSize2(String d) {
|
||||
return d.equals(Descriptor.LONG) || d.equals(Descriptor.DOUBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty-prints the given descriptor.
|
||||
*
|
||||
* @param d A valid field or method descriptor
|
||||
*/
|
||||
public static String
|
||||
toString(String d) {
|
||||
int idx = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (d.charAt(0) == '(') {
|
||||
++idx;
|
||||
sb.append("(");
|
||||
while (idx < d.length() && d.charAt(idx) != ')') {
|
||||
if (idx != 1) sb.append(", ");
|
||||
idx = Descriptor.toString(d, idx, sb);
|
||||
}
|
||||
if (idx >= d.length()) throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
|
||||
sb.append(") => ");
|
||||
++idx;
|
||||
}
|
||||
Descriptor.toString(d, idx, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
private static int
|
||||
toString(String d, int idx, StringBuilder sb) {
|
||||
int dimensions = 0;
|
||||
while (idx < d.length() && d.charAt(idx) == '[') {
|
||||
++dimensions;
|
||||
++idx;
|
||||
}
|
||||
if (idx >= d.length()) throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
|
||||
switch (d.charAt(idx)) {
|
||||
case 'L':
|
||||
{
|
||||
int idx2 = d.indexOf(';', idx);
|
||||
if (idx2 == -1) throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
|
||||
sb.append(d.substring(idx + 1, idx2).replace('/', '.'));
|
||||
idx = idx2;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
sb.append("void");
|
||||
break;
|
||||
case 'B':
|
||||
sb.append("byte");
|
||||
break;
|
||||
case 'C':
|
||||
sb.append("char");
|
||||
break;
|
||||
case 'D':
|
||||
sb.append("double");
|
||||
break;
|
||||
case 'F':
|
||||
sb.append("float");
|
||||
break;
|
||||
case 'I':
|
||||
sb.append("int");
|
||||
break;
|
||||
case 'J':
|
||||
sb.append("long");
|
||||
break;
|
||||
case 'S':
|
||||
sb.append("short");
|
||||
break;
|
||||
case 'Z':
|
||||
sb.append("boolean");
|
||||
break;
|
||||
default:
|
||||
throw new JaninoRuntimeException("Invalid descriptor \"" + d + "\"");
|
||||
}
|
||||
for (; dimensions > 0; --dimensions) sb.append("[]");
|
||||
return idx + 1;
|
||||
}
|
||||
|
||||
/** Converts a class name as defined by "Class.getName()" into a descriptor. */
|
||||
public static String
|
||||
fromClassName(String className) {
|
||||
String res = (String) Descriptor.CLASS_NAME_TO_DESCRIPTOR.get(className);
|
||||
if (res != null) { return res; }
|
||||
if (className.startsWith("[")) return className.replace('.', '/');
|
||||
return 'L' + className.replace('.', '/') + ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a class name in the "internal form" as described in JVMS 4.2 into a descriptor.
|
||||
* <p>
|
||||
* Also implement the encoding of array types as described in JVMS 4.4.1.
|
||||
*/
|
||||
public static String
|
||||
fromInternalForm(String internalForm) {
|
||||
if (internalForm.charAt(0) == '[') return internalForm;
|
||||
return 'L' + internalForm + ';';
|
||||
}
|
||||
|
||||
/** Converts a field descriptor into a class name as defined by {@link Class#getName()}. */
|
||||
public static String
|
||||
toClassName(String d) {
|
||||
String res = (String) Descriptor.DESCRIPTOR_TO_CLASSNAME.get(d);
|
||||
if (res != null) { return res; }
|
||||
|
||||
char firstChar = d.charAt(0);
|
||||
if (firstChar == 'L' && d.endsWith(";")) {
|
||||
// Class or interface -- convert "Ljava/lang/String;" to "java.lang.String".
|
||||
return d.substring(1, d.length() - 1).replace('/', '.');
|
||||
}
|
||||
if (firstChar == '[') {
|
||||
// Array type -- convert "[Ljava/lang/String;" to "[Ljava.lang.String;".
|
||||
return d.replace('/', '.');
|
||||
}
|
||||
throw new JaninoRuntimeException("(Invalid field descriptor \"" + d + "\")");
|
||||
}
|
||||
|
||||
/** Converts a descriptor into the "internal form" as defined by JVMS 4.2. */
|
||||
public static String
|
||||
toInternalForm(String d) {
|
||||
if (d.charAt(0) != 'L') {
|
||||
throw new JaninoRuntimeException(
|
||||
"Attempt to convert non-class descriptor \""
|
||||
+ d
|
||||
+ "\" into internal form"
|
||||
);
|
||||
}
|
||||
return d.substring(1, d.length() - 1);
|
||||
}
|
||||
|
||||
/** @return Whether {@code d} describes a primitive type or VOID */
|
||||
public static boolean
|
||||
isPrimitive(String d) { return d.length() == 1 && "VBCDFIJSZ".indexOf(d.charAt(0)) != -1; }
|
||||
|
||||
/** @return Whether {@code d} describes a primitive type except BOOLEAN and VOID */
|
||||
public static boolean
|
||||
isPrimitiveNumeric(String d) { return d.length() == 1 && "BDFIJSC".indexOf(d.charAt(0)) != -1; }
|
||||
|
||||
/**
|
||||
* Returns the package name of a class or interface reference descriptor,
|
||||
* or <code>null</code> if the class or interface is declared in the
|
||||
* default package.
|
||||
*/
|
||||
public static String
|
||||
getPackageName(String d) {
|
||||
if (d.charAt(0) != 'L') {
|
||||
throw new JaninoRuntimeException("Attempt to get package name of non-class descriptor \"" + d + "\"");
|
||||
}
|
||||
int idx = d.lastIndexOf('/');
|
||||
return idx == -1 ? null : d.substring(1, idx).replace('/', '.');
|
||||
}
|
||||
|
||||
/** Checks whether two reference types are declared in the same package. */
|
||||
public static boolean
|
||||
areInSamePackage(String d1, String d2) {
|
||||
String packageName1 = Descriptor.getPackageName(d1);
|
||||
String packageName2 = Descriptor.getPackageName(d2);
|
||||
return packageName1 == null ? packageName2 == null : packageName1.equals(packageName2);
|
||||
}
|
||||
|
||||
/** The field descriptor for the type VOID. */
|
||||
public static final String VOID = "V";
|
||||
|
||||
// Primitive types.
|
||||
|
||||
/** The field descriptor for the primitive type BYTE. */
|
||||
public static final String BYTE = "B";
|
||||
/** The field descriptor for the primitive type CHAR. */
|
||||
public static final String CHAR = "C";
|
||||
/** The field descriptor for the primitive type DOUBLE. */
|
||||
public static final String DOUBLE = "D";
|
||||
/** The field descriptor for the primitive type FLOAT. */
|
||||
public static final String FLOAT = "F";
|
||||
/** The field descriptor for the primitive type INT. */
|
||||
public static final String INT = "I";
|
||||
/** The field descriptor for the primitive type LONG. */
|
||||
public static final String LONG = "J";
|
||||
/** The field descriptor for the primitive type SHORT. */
|
||||
public static final String SHORT = "S";
|
||||
/** The field descriptor for the primitive type BOOLEAN. */
|
||||
public static final String BOOLEAN = "Z";
|
||||
|
||||
// Annotations.
|
||||
|
||||
/** The field descriptor for the annotation {@link java.lang.Override}. */
|
||||
public static final String JAVA_LANG_OVERRIDE = "Ljava/lang/Override;";
|
||||
|
||||
// Classes.
|
||||
|
||||
/** The field descriptor for the class {@link java.lang.AssertionError}. */
|
||||
public static final String JAVA_LANG_ASSERTIONERROR = "Ljava/lang/AssertionError;";
|
||||
/** The field descriptor for the class {@link java.lang.Boolean}. */
|
||||
public static final String JAVA_LANG_BOOLEAN = "Ljava/lang/Boolean;";
|
||||
/** The field descriptor for the class {@link java.lang.Byte}. */
|
||||
public static final String JAVA_LANG_BYTE = "Ljava/lang/Byte;";
|
||||
/** The field descriptor for the class {@link java.lang.Character}. */
|
||||
public static final String JAVA_LANG_CHARACTER = "Ljava/lang/Character;";
|
||||
/** The field descriptor for the class {@link java.lang.Class}. */
|
||||
public static final String JAVA_LANG_CLASS = "Ljava/lang/Class;";
|
||||
/** The field descriptor for the class {@link java.lang.Double}. */
|
||||
public static final String JAVA_LANG_DOUBLE = "Ljava/lang/Double;";
|
||||
/** The field descriptor for the class {@link java.lang.Exception}. */
|
||||
public static final String JAVA_LANG_EXCEPTION = "Ljava/lang/Exception;";
|
||||
/** The field descriptor for the class {@link java.lang.Error}. */
|
||||
public static final String JAVA_LANG_ERROR = "Ljava/lang/Error;";
|
||||
/** The field descriptor for the class {@link java.lang.Float}. */
|
||||
public static final String JAVA_LANG_FLOAT = "Ljava/lang/Float;";
|
||||
/** The field descriptor for the class {@link java.lang.Integer}. */
|
||||
public static final String JAVA_LANG_INTEGER = "Ljava/lang/Integer;";
|
||||
/** The field descriptor for the class {@link java.lang.Long}. */
|
||||
public static final String JAVA_LANG_LONG = "Ljava/lang/Long;";
|
||||
/** The field descriptor for the class {@link java.lang.Object}. */
|
||||
public static final String JAVA_LANG_OBJECT = "Ljava/lang/Object;";
|
||||
/** The field descriptor for the class {@link java.lang.RuntimeException}. */
|
||||
public static final String JAVA_LANG_RUNTIMEEXCEPTION = "Ljava/lang/RuntimeException;";
|
||||
/** The field descriptor for the class {@link java.lang.Short}. */
|
||||
public static final String JAVA_LANG_SHORT = "Ljava/lang/Short;";
|
||||
/** The field descriptor for the class {@link java.lang.String}. */
|
||||
public static final String JAVA_LANG_STRING = "Ljava/lang/String;";
|
||||
/** The field descriptor for the class {@link java.lang.StringBuilder}. */
|
||||
public static final String JAVA_LANG_STRINGBUILDER = "Ljava/lang/StringBuilder;"; // Since 1.5!
|
||||
/** The field descriptor for the class {@link java.lang.Throwable}. */
|
||||
public static final String JAVA_LANG_THROWABLE = "Ljava/lang/Throwable;";
|
||||
|
||||
// Interfaces.
|
||||
|
||||
/** The field descriptor for the interface {@link java.io.Serializable}. */
|
||||
public static final String JAVA_IO_SERIALIZABLE = "Ljava/io/Serializable;";
|
||||
/** The field descriptor for the interface {@link java.lang.Cloneable}. */
|
||||
public static final String JAVA_LANG_CLONEABLE = "Ljava/lang/Cloneable;";
|
||||
/** The field descriptor for the interface {@link java.lang.Iterable}. */
|
||||
public static final String JAVA_LANG_ITERABLE = "Ljava/lang/Iterable;";
|
||||
/** The field descriptor for the interface {@link java.util.Iterator}. */
|
||||
public static final String JAVA_UTIL_ITERATOR = "Ljava/util/Iterator;";
|
||||
|
||||
private static final Map<String, String> DESCRIPTOR_TO_CLASSNAME;
|
||||
static {
|
||||
Map<String, String> m = new HashMap();
|
||||
|
||||
m.put(Descriptor.VOID, "void");
|
||||
|
||||
// Primitive types.
|
||||
m.put(Descriptor.BYTE, "byte");
|
||||
m.put(Descriptor.CHAR, "char");
|
||||
m.put(Descriptor.DOUBLE, "double");
|
||||
m.put(Descriptor.FLOAT, "float");
|
||||
m.put(Descriptor.INT, "int");
|
||||
m.put(Descriptor.LONG, "long");
|
||||
m.put(Descriptor.SHORT, "short");
|
||||
m.put(Descriptor.BOOLEAN, "boolean");
|
||||
|
||||
// Annotations.
|
||||
m.put(Descriptor.JAVA_LANG_OVERRIDE, "java.lang.Override");
|
||||
|
||||
// Classes.
|
||||
m.put(Descriptor.JAVA_LANG_ASSERTIONERROR, "java.lang.AssertionError");
|
||||
m.put(Descriptor.JAVA_LANG_BOOLEAN, "java.lang.Boolean");
|
||||
m.put(Descriptor.JAVA_LANG_BYTE, "java.lang.Byte");
|
||||
m.put(Descriptor.JAVA_LANG_CHARACTER, "java.lang.Character");
|
||||
m.put(Descriptor.JAVA_LANG_CLASS, "java.lang.Class");
|
||||
m.put(Descriptor.JAVA_LANG_DOUBLE, "java.lang.Double");
|
||||
m.put(Descriptor.JAVA_LANG_EXCEPTION, "java.lang.Exception");
|
||||
m.put(Descriptor.JAVA_LANG_ERROR, "java.lang.Error");
|
||||
m.put(Descriptor.JAVA_LANG_FLOAT, "java.lang.Float");
|
||||
m.put(Descriptor.JAVA_LANG_INTEGER, "java.lang.Integer");
|
||||
m.put(Descriptor.JAVA_LANG_LONG, "java.lang.Long");
|
||||
m.put(Descriptor.JAVA_LANG_OBJECT, "java.lang.Object");
|
||||
m.put(Descriptor.JAVA_LANG_RUNTIMEEXCEPTION, "java.lang.RuntimeException");
|
||||
m.put(Descriptor.JAVA_LANG_SHORT, "java.lang.Short");
|
||||
m.put(Descriptor.JAVA_LANG_STRING, "java.lang.String");
|
||||
m.put(Descriptor.JAVA_LANG_STRINGBUILDER, "java.lang.StringBuilder");
|
||||
m.put(Descriptor.JAVA_LANG_THROWABLE, "java.lang.Throwable");
|
||||
|
||||
// Interfaces.
|
||||
m.put(Descriptor.JAVA_IO_SERIALIZABLE, "java.io.Serializable");
|
||||
m.put(Descriptor.JAVA_LANG_CLONEABLE, "java.lang.Cloneable");
|
||||
m.put(Descriptor.JAVA_LANG_ITERABLE, "java.lang.Iterable");
|
||||
m.put(Descriptor.JAVA_UTIL_ITERATOR, "java.util.Iterator");
|
||||
|
||||
DESCRIPTOR_TO_CLASSNAME = Collections.unmodifiableMap(m);
|
||||
}
|
||||
|
||||
private static final Map<String, String> CLASS_NAME_TO_DESCRIPTOR;
|
||||
|
||||
static {
|
||||
Map<String, String> m = new HashMap();
|
||||
for (Map.Entry<String, String> e : Descriptor.DESCRIPTOR_TO_CLASSNAME.entrySet()) {
|
||||
m.put(e.getValue(), e.getKey());
|
||||
}
|
||||
CLASS_NAME_TO_DESCRIPTOR = Collections.unmodifiableMap(m);
|
||||
}
|
||||
}
|
445
src/org/codehaus/janino/ExpressionEvaluator.java
Normal file
445
src/org/codehaus/janino/ExpressionEvaluator.java
Normal file
|
@ -0,0 +1,445 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.CompilerFactoryFactory;
|
||||
import org.codehaus.commons.compiler.Cookable;
|
||||
import org.codehaus.commons.compiler.IClassBodyEvaluator;
|
||||
import org.codehaus.commons.compiler.ICompilerFactory;
|
||||
import org.codehaus.commons.compiler.ICookable;
|
||||
import org.codehaus.commons.compiler.IExpressionEvaluator;
|
||||
import org.codehaus.commons.compiler.IScriptEvaluator;
|
||||
import org.codehaus.commons.compiler.ISimpleCompiler;
|
||||
import org.codehaus.commons.compiler.PrimitiveWrapper;
|
||||
import org.codehaus.janino.Java.AmbiguousName;
|
||||
import org.codehaus.janino.Java.BlockStatement;
|
||||
import org.codehaus.janino.Java.Rvalue;
|
||||
import org.codehaus.janino.Visitor.RvalueVisitor;
|
||||
import org.codehaus.janino.util.Traverser;
|
||||
|
||||
/**
|
||||
* This {@link IExpressionEvaluator} is implemented by creating and compiling a temporary
|
||||
* compilation unit defining one class with one static method with one RETURN statement.
|
||||
* <p>
|
||||
* A number of "convenience constructors" exist that execute the set-up steps described for {@link
|
||||
* IExpressionEvaluator} instantly.
|
||||
* <p>
|
||||
* If the parameter and return types of the expression are known at compile time, then a "fast"
|
||||
* expression evaluator can be instantiated through
|
||||
* {@link #createFastExpressionEvaluator(String, Class, String[], ClassLoader)}. Expression
|
||||
* evaluation is faster than through {@link #evaluate(Object[])}, because it is not done through
|
||||
* reflection but through direct method invocation.
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre>
|
||||
* public interface Foo {
|
||||
* int bar(int a, int b);
|
||||
* }
|
||||
* ...
|
||||
* Foo f = (Foo) ExpressionEvaluator.createFastExpressionEvaluator(
|
||||
* "a + b", // expression to evaluate
|
||||
* Foo.class, // interface that describes the expression's signature
|
||||
* new String[] { "a", "b" }, // the parameters' names
|
||||
* (ClassLoader) null // Use current thread's context class loader
|
||||
* );
|
||||
* System.out.println("1 + 2 = " + f.bar(1, 2)); // Evaluate the expression
|
||||
* </pre>
|
||||
* Notice: The <code>interfaceToImplement</code> must either be declared <code>public</code>,
|
||||
* or with package scope in the root package (i.e. "no" package).
|
||||
* <p>
|
||||
* On my system (Intel P4, 2 GHz, MS Windows XP, JDK 1.4.1), expression "x + 1"
|
||||
* evaluates as follows:
|
||||
* <table>
|
||||
* <tr><td></td><th>Server JVM</th><th>Client JVM</th></td></tr>
|
||||
* <tr><td>Normal EE</td><td>23.7 ns</td><td>64.0 ns</td></tr>
|
||||
* <tr><td>Fast EE</td><td>31.2 ns</td><td>42.2 ns</td></tr>
|
||||
* </table>
|
||||
* (How can it be that interface method invocation is slower than reflection for
|
||||
* the server JVM?)
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class ExpressionEvaluator extends ScriptEvaluator implements IExpressionEvaluator {
|
||||
|
||||
private Class[] optionalExpressionTypes;
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
* ee.setExpressionType(expressionType);
|
||||
* ee.setParameters(parameterNames, parameterTypes);
|
||||
* ee.cook(expression);</pre>
|
||||
*
|
||||
* @see #ExpressionEvaluator()
|
||||
* @see ExpressionEvaluator#setExpressionType(Class)
|
||||
* @see ScriptEvaluator#setParameters(String[], Class[])
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ExpressionEvaluator(
|
||||
String expression,
|
||||
Class expressionType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes
|
||||
) throws CompileException {
|
||||
this.setExpressionType(expressionType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.cook(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
* ee.setExpressionType(expressionType);
|
||||
* ee.setParameters(parameterNames, parameterTypes);
|
||||
* ee.setThrownExceptions(thrownExceptions);
|
||||
* ee.setParentClassLoader(optionalParentClassLoader);
|
||||
* ee.cook(expression);</pre>
|
||||
*
|
||||
* @see #ExpressionEvaluator()
|
||||
* @see ExpressionEvaluator#setExpressionType(Class)
|
||||
* @see ScriptEvaluator#setParameters(String[], Class[])
|
||||
* @see ScriptEvaluator#setThrownExceptions(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ExpressionEvaluator(
|
||||
String expression,
|
||||
Class expressionType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException {
|
||||
this.setExpressionType(expressionType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
* ee.setExpressionType(expressionType);
|
||||
* ee.setParameters(parameterNames, parameterTypes);
|
||||
* ee.setThrownExceptions(thrownExceptions);
|
||||
* ee.setExtendedType(optionalExtendedType);
|
||||
* ee.setImplementedTypes(implementedTypes);
|
||||
* ee.setParentClassLoader(optionalParentClassLoader);
|
||||
* ee.cook(expression);</pre>
|
||||
*
|
||||
* @see #ExpressionEvaluator()
|
||||
* @see ExpressionEvaluator#setExpressionType(Class)
|
||||
* @see ScriptEvaluator#setParameters(String[], Class[])
|
||||
* @see ScriptEvaluator#setThrownExceptions(Class[])
|
||||
* @see ClassBodyEvaluator#setExtendedClass(Class)
|
||||
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ExpressionEvaluator(
|
||||
String expression,
|
||||
Class expressionType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
Class optionalExtendedType,
|
||||
Class[] implementedTypes,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException {
|
||||
this.setExpressionType(expressionType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setExtendedClass(optionalExtendedType);
|
||||
this.setImplementedInterfaces(implementedTypes);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
* ee.setClassName(className);
|
||||
* ee.setExtendedType(optionalExtendedType);
|
||||
* ee.setImplementedTypes(implementedTypes);
|
||||
* ee.setStaticMethod(staticMethod);
|
||||
* ee.setExpressionType(expressionType);
|
||||
* ee.setMethodName(methodName);
|
||||
* ee.setParameters(parameterNames, parameterTypes);
|
||||
* ee.setThrownExceptions(thrownExceptions);
|
||||
* ee.setParentClassLoader(optionalParentClassLoader);
|
||||
* ee.cook(scanner);
|
||||
*
|
||||
* @see IExpressionEvaluator
|
||||
* @see IClassBodyEvaluator#setClassName(String)
|
||||
* @see IClassBodyEvaluator#setExtendedClass(Class)
|
||||
* @see IClassBodyEvaluator#setImplementedInterfaces(Class[])
|
||||
* @see IScriptEvaluator#setStaticMethod(boolean)
|
||||
* @see IExpressionEvaluator#setExpressionType(Class)
|
||||
* @see IScriptEvaluator#setMethodName(String)
|
||||
* @see IScriptEvaluator#setParameters(String[], Class[])
|
||||
* @see IScriptEvaluator#setThrownExceptions(Class[])
|
||||
* @see ISimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see ICookable#cook(Reader)
|
||||
*/
|
||||
public
|
||||
ExpressionEvaluator(
|
||||
Scanner scanner,
|
||||
String className,
|
||||
Class optionalExtendedType,
|
||||
Class[] implementedTypes,
|
||||
boolean staticMethod,
|
||||
Class expressionType,
|
||||
String methodName,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException, IOException {
|
||||
this.setClassName(className);
|
||||
this.setExtendedClass(optionalExtendedType);
|
||||
this.setImplementedInterfaces(implementedTypes);
|
||||
this.setStaticMethod(staticMethod);
|
||||
this.setExpressionType(expressionType);
|
||||
this.setMethodName(methodName);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(scanner);
|
||||
}
|
||||
|
||||
public ExpressionEvaluator() {}
|
||||
|
||||
@Override public void
|
||||
setExpressionType(Class expressionType) { this.setExpressionTypes(new Class[] { expressionType }); }
|
||||
|
||||
@Override public void
|
||||
setExpressionTypes(Class[] expressionTypes) {
|
||||
this.assertNotCooked();
|
||||
this.optionalExpressionTypes = expressionTypes;
|
||||
|
||||
Class[] returnTypes = new Class[expressionTypes.length];
|
||||
for (int i = 0; i < returnTypes.length; ++i) {
|
||||
Class et = expressionTypes[i];
|
||||
returnTypes[i] = et == IExpressionEvaluator.ANY_TYPE ? Object.class : et;
|
||||
}
|
||||
super.setReturnTypes(returnTypes);
|
||||
}
|
||||
|
||||
/** @deprecated {@link #setExpressionType(Class)} should be called instead. */
|
||||
@Override @Deprecated public final void
|
||||
setReturnType(Class returnType) {
|
||||
throw new AssertionError("Must not be used on an ExpressionEvaluator; use 'setExpressionType()' instead");
|
||||
}
|
||||
|
||||
/** @deprecated {@link #setExpressionTypes(Class[])} should be called instead. */
|
||||
@Override @Deprecated public final void
|
||||
setReturnTypes(Class[] returnTypes) {
|
||||
throw new AssertionError("Must not be used on an ExpressionEvaluator; use 'setExpressionTypes()' instead");
|
||||
}
|
||||
|
||||
@Override protected Class
|
||||
getDefaultReturnType() { return Object.class; }
|
||||
|
||||
@Override protected List<BlockStatement>
|
||||
makeStatements(int idx, Parser parser) throws CompileException, IOException {
|
||||
List<BlockStatement> statements = new ArrayList();
|
||||
|
||||
// Parse the expression.
|
||||
Rvalue value = parser.parseExpression().toRvalueOrCompileException();
|
||||
|
||||
Class et = (
|
||||
this.optionalExpressionTypes == null
|
||||
? IExpressionEvaluator.ANY_TYPE
|
||||
: this.optionalExpressionTypes[idx]
|
||||
);
|
||||
if (et == void.class) {
|
||||
|
||||
// ExpressionEvaluator with an expression type "void" is a simple expression statement.
|
||||
statements.add(new Java.ExpressionStatement(value));
|
||||
} else {
|
||||
|
||||
// Special case: Expression type "ANY_TYPE" means return type "Object" and automatic
|
||||
// wrapping of primitive types.
|
||||
if (et == IExpressionEvaluator.ANY_TYPE) {
|
||||
value = new Java.MethodInvocation(
|
||||
parser.location(), // location
|
||||
new Java.ReferenceType( // optionalTarget
|
||||
parser.location(), // location
|
||||
new String[] { // identifiers
|
||||
"org", "codehaus", "commons", "compiler", "PrimitiveWrapper"
|
||||
},
|
||||
null // optionalTypeArguments
|
||||
),
|
||||
"wrap", // methodName
|
||||
new Java.Rvalue[] { value } // arguments
|
||||
);
|
||||
|
||||
// Make sure "PrimitiveWrapper" is compiled.
|
||||
PrimitiveWrapper.wrap(99);
|
||||
|
||||
// Verify that "PrimitiveWrapper" is loadable.
|
||||
this.classToType(null, PrimitiveWrapper.class);
|
||||
}
|
||||
|
||||
// Add a return statement.
|
||||
statements.add(new Java.ReturnStatement(parser.location(), value));
|
||||
}
|
||||
if (!parser.peekEof()) {
|
||||
throw new CompileException("Unexpected token \"" + parser.peek() + "\"", parser.location());
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* {@link IExpressionEvaluator} ee = {@link CompilerFactoryFactory}.{@link
|
||||
* CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
|
||||
* ICompilerFactory#newExpressionEvaluator() newExpressionEvaluator}();
|
||||
* ee.setParentClassLoader(optionalParentClassLoader);
|
||||
* return ee.{@link #createFastEvaluator createFastEvaluator}(expression, interfaceToImplement, parameterNames);
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated Use {@link #createFastEvaluator(String, Class, String[])} instead:
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastExpressionEvaluator(
|
||||
String expression,
|
||||
Class interfaceToImplement,
|
||||
String[] parameterNames,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException {
|
||||
IExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
ee.setParentClassLoader(optionalParentClassLoader);
|
||||
return ee.createFastEvaluator(expression, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice: This method is not declared in {@link IExpressionEvaluator}, and is hence only available in <i>this</i>
|
||||
* implementation of <code>org.codehaus.commons.compiler</code>. To be independent from this particular
|
||||
* implementation, try to switch to {@link #createFastEvaluator(Reader, Class, String[])}.
|
||||
*
|
||||
* @deprecated Use {@link #createFastEvaluator(Reader, Class, String[])} instead
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastExpressionEvaluator(
|
||||
Scanner scanner,
|
||||
String className,
|
||||
Class optionalExtendedType,
|
||||
Class interfaceToImplement,
|
||||
String[] parameterNames,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException, IOException {
|
||||
ExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
ee.setClassName(className);
|
||||
ee.setExtendedClass(optionalExtendedType);
|
||||
ee.setParentClassLoader(optionalParentClassLoader);
|
||||
return ee.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice: This method is not declared in {@link IExpressionEvaluator}, and is hence only available in <i>this</i>
|
||||
* implementation of <code>org.codehaus.commons.compiler</code>. To be independent from this particular
|
||||
* implementation, try to switch to {@link #createFastEvaluator(Reader, Class, String[])}.
|
||||
*
|
||||
* @deprecated Use {@link #createFastEvaluator(Reader, Class, String[])} instead
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastExpressionEvaluator(
|
||||
Scanner scanner,
|
||||
String[] optionalDefaultImports,
|
||||
String className,
|
||||
Class optionalExtendedType,
|
||||
Class interfaceToImplement,
|
||||
String[] parameterNames,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException, IOException {
|
||||
ExpressionEvaluator ee = new ExpressionEvaluator();
|
||||
ee.setClassName(className);
|
||||
ee.setExtendedClass(optionalExtendedType);
|
||||
ee.setDefaultImports(optionalDefaultImports);
|
||||
ee.setParentClassLoader(optionalParentClassLoader);
|
||||
return ee.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess the names of the parameters used in the given expression. The strategy is to look
|
||||
* at all "ambiguous names" in the expression (e.g. in "a.b.c.d()", the ambiguous name
|
||||
* is "a.b.c"), and then at the first components of the ambiguous name.
|
||||
* <ul>
|
||||
* <li>If any component starts with an upper-case letter, then ambiguous name is assumed to
|
||||
* be a type name.
|
||||
* <li>Otherwise, it is assumed to be a parameter name.
|
||||
* </ul>
|
||||
*
|
||||
* @see Scanner#Scanner(String, Reader)
|
||||
*/
|
||||
public static String[]
|
||||
guessParameterNames(Scanner scanner) throws CompileException, IOException {
|
||||
Parser parser = new Parser(scanner);
|
||||
|
||||
// Eat optional leading import declarations.
|
||||
while (parser.peek("import")) parser.parseImportDeclaration();
|
||||
|
||||
// Parse the expression.
|
||||
Rvalue rvalue = parser.parseExpression().toRvalueOrCompileException();
|
||||
if (!parser.peekEof()) {
|
||||
throw new CompileException("Unexpected token \"" + parser.peek() + "\"", scanner.location());
|
||||
}
|
||||
|
||||
// Traverse the expression for ambiguous names and guess which of them are parameter names.
|
||||
final Set<String> parameterNames = new HashSet();
|
||||
rvalue.accept((RvalueVisitor) new Traverser() {
|
||||
|
||||
@Override public void
|
||||
traverseAmbiguousName(AmbiguousName an) {
|
||||
|
||||
// If any of the components starts with an upper-case letter, then the ambiguous
|
||||
// name is most probably a type name, e.g. "System.out" or "java.lang.System.out".
|
||||
for (String identifier : an.identifiers) {
|
||||
if (Character.isUpperCase(identifier.charAt(0))) return;
|
||||
}
|
||||
|
||||
// It's most probably a parameter name (although it could be a field name as well).
|
||||
parameterNames.add(an.identifiers[0]);
|
||||
}
|
||||
}.comprehensiveVisitor());
|
||||
|
||||
return (String[]) parameterNames.toArray(new String[parameterNames.size()]);
|
||||
}
|
||||
}
|
56
src/org/codehaus/janino/FilterWarningHandler.java
Normal file
56
src/org/codehaus/janino/FilterWarningHandler.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
import org.codehaus.commons.compiler.WarningHandler;
|
||||
import org.codehaus.janino.util.StringPattern;
|
||||
|
||||
/** Invokes a delegate iff the handle of the warning matches one or more of a set of {@link StringPattern}s. */
|
||||
public
|
||||
class FilterWarningHandler implements WarningHandler {
|
||||
private final StringPattern[] handlePatterns;
|
||||
private final WarningHandler delegate;
|
||||
|
||||
/**
|
||||
* Popular values for the <code>handlePatterns</code> parameter are
|
||||
* {@link StringPattern#PATTERNS_ALL} and {@link StringPattern#PATTERNS_NONE}.
|
||||
*/
|
||||
public
|
||||
FilterWarningHandler(StringPattern[] handlePatterns, WarningHandler delegate) {
|
||||
this.handlePatterns = handlePatterns;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override public void
|
||||
handleWarning(String handle, String message, Location optionalLocation) throws CompileException {
|
||||
if (StringPattern.matches(this.handlePatterns, handle)) {
|
||||
this.delegate.handleWarning(handle, message, optionalLocation);
|
||||
}
|
||||
}
|
||||
}
|
1146
src/org/codehaus/janino/IClass.java
Normal file
1146
src/org/codehaus/janino/IClass.java
Normal file
File diff suppressed because it is too large
Load Diff
384
src/org/codehaus/janino/IClassLoader.java
Normal file
384
src/org/codehaus/janino/IClassLoader.java
Normal file
|
@ -0,0 +1,384 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codehaus.janino.IClass.IConstructor;
|
||||
import org.codehaus.janino.IClass.IMethod;
|
||||
import org.codehaus.janino.util.resource.JarDirectoriesResourceFinder;
|
||||
import org.codehaus.janino.util.resource.PathResourceFinder;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
/** Loads an {@link IClass} by type name. */
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public abstract
|
||||
class IClassLoader {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
// The following are constants, but cannot be declared FINAL, because they are only initialized by
|
||||
// "postConstruct()".
|
||||
|
||||
// CHECKSTYLE MemberName:OFF
|
||||
// CHECKSTYLE AbbreviationAsWordInName:OFF
|
||||
/** Representation of the {@link java.lang.Override} annotation. */
|
||||
public IClass ANNO_java_lang_Override;
|
||||
|
||||
/** Representation of the {@link java.lang.AssertionError} type. */
|
||||
public IClass TYPE_java_lang_AssertionError;
|
||||
/** Representation of the {@link java.lang.Boolean} type. */
|
||||
public IClass TYPE_java_lang_Boolean;
|
||||
/** Representation of the {@link java.lang.Byte} type. */
|
||||
public IClass TYPE_java_lang_Byte;
|
||||
/** Representation of the {@link java.lang.Character} type. */
|
||||
public IClass TYPE_java_lang_Character;
|
||||
/** Representation of the {@link java.lang.Class} type. */
|
||||
public IClass TYPE_java_lang_Class;
|
||||
/** Representation of the {@link java.lang.Cloneable} type. */
|
||||
public IClass TYPE_java_lang_Cloneable;
|
||||
/** Representation of the {@link java.lang.Double} type. */
|
||||
public IClass TYPE_java_lang_Double;
|
||||
/** Representation of the {@link java.lang.Exception} type. */
|
||||
public IClass TYPE_java_lang_Exception;
|
||||
/** Representation of the {@link java.lang.Error} type. */
|
||||
public IClass TYPE_java_lang_Error;
|
||||
/** Representation of the {@link java.lang.Float} type. */
|
||||
public IClass TYPE_java_lang_Float;
|
||||
/** Representation of the {@link java.lang.Integer} type. */
|
||||
public IClass TYPE_java_lang_Integer;
|
||||
/** Representation of the {@link java.lang.Iterable} type. */
|
||||
public IClass TYPE_java_lang_Iterable;
|
||||
/** Representation of the {@link java.lang.Long} type. */
|
||||
public IClass TYPE_java_lang_Long;
|
||||
/** Representation of the {@link java.lang.Object} type. */
|
||||
public IClass TYPE_java_lang_Object;
|
||||
/** Representation of the {@link java.lang.RuntimeException} type. */
|
||||
public IClass TYPE_java_lang_RuntimeException;
|
||||
/** Representation of the {@link java.lang.Short} type. */
|
||||
public IClass TYPE_java_lang_Short;
|
||||
/** Representation of the {@link java.lang.String} type. */
|
||||
public IClass TYPE_java_lang_String;
|
||||
/** Representation of the {@link java.lang.StringBuilder} type. */
|
||||
public IClass TYPE_java_lang_StringBuilder;
|
||||
/** Representation of the {@link java.lang.Throwable} type. */
|
||||
public IClass TYPE_java_lang_Throwable;
|
||||
/** Representation of the {@link java.io.Serializable} type. */
|
||||
public IClass TYPE_java_io_Serializable;
|
||||
/** Representation of the {@link java.util.Iterator} type. */
|
||||
public IClass TYPE_java_util_Iterator;
|
||||
|
||||
/** Representation of the {@link Iterable#iterator()} method. */
|
||||
public IMethod METH_java_lang_Iterable__iterator;
|
||||
/** Representation of the {@link String#concat(String)} method. */
|
||||
public IMethod METH_java_lang_String__concat__java_lang_String;
|
||||
/** Representation of the {@link String#valueOf(int)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__int;
|
||||
/** Representation of the {@link String#valueOf(long)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__long;
|
||||
/** Representation of the {@link String#valueOf(float)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__float;
|
||||
/** Representation of the {@link String#valueOf(double)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__double;
|
||||
/** Representation of the {@link String#valueOf(char)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__char;
|
||||
/** Representation of the {@link String#valueOf(boolean)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__boolean;
|
||||
/** Representation of the {@link String#valueOf(Object)} method. */
|
||||
public IMethod METH_java_lang_String__valueOf__java_lang_Object;
|
||||
/** Representation of the {@link StringBuilder#append(String)} method. */
|
||||
public IMethod METH_java_lang_StringBuilder__append__java_lang_String;
|
||||
/** Representation of the {@link StringBuilder#toString()} method. */
|
||||
public IMethod METH_java_lang_StringBuilder__toString;
|
||||
/** Representation of the {@link java.util.Iterator#hasNext()} method. */
|
||||
public IMethod METH_java_util_Iterator__hasNext;
|
||||
/** Representation of the {@link java.util.Iterator#next()} method. */
|
||||
public IMethod METH_java_util_Iterator__next;
|
||||
|
||||
/** Representation of the {@link StringBuilder#StringBuilder(String)} constructor. */
|
||||
public IConstructor CTOR_java_lang_StringBuilder__java_lang_String;
|
||||
// CHECKSTYLE AbbreviationAsWordInName:ON
|
||||
// CHECKSTYLE MemberName:ON
|
||||
|
||||
public
|
||||
IClassLoader(IClassLoader optionalParentIClassLoader) {
|
||||
this.optionalParentIClassLoader = optionalParentIClassLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must be called by the constructor of the directly derived
|
||||
* class. (The reason being is that this method invokes abstract
|
||||
* {@link #loadIClass(String)} which will not work until the implementing
|
||||
* class is constructed.)
|
||||
*/
|
||||
protected final void
|
||||
postConstruct() {
|
||||
try {
|
||||
this.ANNO_java_lang_Override = this.loadIClass(Descriptor.JAVA_LANG_OVERRIDE);
|
||||
|
||||
this.TYPE_java_lang_AssertionError = this.loadIClass(Descriptor.JAVA_LANG_ASSERTIONERROR);
|
||||
this.TYPE_java_lang_Boolean = this.loadIClass(Descriptor.JAVA_LANG_BOOLEAN);
|
||||
this.TYPE_java_lang_Byte = this.loadIClass(Descriptor.JAVA_LANG_BYTE);
|
||||
this.TYPE_java_lang_Character = this.loadIClass(Descriptor.JAVA_LANG_CHARACTER);
|
||||
this.TYPE_java_lang_Class = this.loadIClass(Descriptor.JAVA_LANG_CLASS);
|
||||
this.TYPE_java_lang_Cloneable = this.loadIClass(Descriptor.JAVA_LANG_CLONEABLE);
|
||||
this.TYPE_java_lang_Double = this.loadIClass(Descriptor.JAVA_LANG_DOUBLE);
|
||||
this.TYPE_java_lang_Exception = this.loadIClass(Descriptor.JAVA_LANG_EXCEPTION);
|
||||
this.TYPE_java_lang_Error = this.loadIClass(Descriptor.JAVA_LANG_ERROR);
|
||||
this.TYPE_java_lang_Float = this.loadIClass(Descriptor.JAVA_LANG_FLOAT);
|
||||
this.TYPE_java_lang_Integer = this.loadIClass(Descriptor.JAVA_LANG_INTEGER);
|
||||
this.TYPE_java_lang_Iterable = this.loadIClass(Descriptor.JAVA_LANG_ITERABLE);
|
||||
this.TYPE_java_lang_Long = this.loadIClass(Descriptor.JAVA_LANG_LONG);
|
||||
this.TYPE_java_lang_Object = this.loadIClass(Descriptor.JAVA_LANG_OBJECT);
|
||||
this.TYPE_java_lang_RuntimeException = this.loadIClass(Descriptor.JAVA_LANG_RUNTIMEEXCEPTION);
|
||||
this.TYPE_java_lang_Short = this.loadIClass(Descriptor.JAVA_LANG_SHORT);
|
||||
this.TYPE_java_lang_String = this.loadIClass(Descriptor.JAVA_LANG_STRING);
|
||||
this.TYPE_java_lang_StringBuilder = this.loadIClass(Descriptor.JAVA_LANG_STRINGBUILDER);
|
||||
this.TYPE_java_lang_Throwable = this.loadIClass(Descriptor.JAVA_LANG_THROWABLE);
|
||||
this.TYPE_java_io_Serializable = this.loadIClass(Descriptor.JAVA_IO_SERIALIZABLE);
|
||||
this.TYPE_java_util_Iterator = this.loadIClass(Descriptor.JAVA_UTIL_ITERATOR);
|
||||
|
||||
// CHECKSTYLE LineLength:OFF
|
||||
// CHECKSTYLE Whitespace:OFF
|
||||
this.METH_java_lang_Iterable__iterator = this.TYPE_java_lang_Iterable .findIMethod("iterator", new IClass[0]);
|
||||
this.METH_java_lang_String__concat__java_lang_String = this.TYPE_java_lang_String .findIMethod("concat", new IClass[] { this.TYPE_java_lang_String });
|
||||
this.METH_java_lang_String__valueOf__int = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.INT });
|
||||
this.METH_java_lang_String__valueOf__long = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.LONG });
|
||||
this.METH_java_lang_String__valueOf__float = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.FLOAT });
|
||||
this.METH_java_lang_String__valueOf__double = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.DOUBLE });
|
||||
this.METH_java_lang_String__valueOf__char = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.CHAR });
|
||||
this.METH_java_lang_String__valueOf__boolean = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { IClass.BOOLEAN });
|
||||
this.METH_java_lang_String__valueOf__java_lang_Object = this.TYPE_java_lang_String .findIMethod("valueOf", new IClass[] { this.TYPE_java_lang_Object });
|
||||
this.METH_java_lang_StringBuilder__append__java_lang_String = this.TYPE_java_lang_StringBuilder.findIMethod("append", new IClass[] { this.TYPE_java_lang_String });
|
||||
this.METH_java_lang_StringBuilder__toString = this.TYPE_java_lang_StringBuilder.findIMethod("toString", new IClass[0]);
|
||||
this.METH_java_util_Iterator__hasNext = this.TYPE_java_util_Iterator .findIMethod("hasNext", new IClass[0]);
|
||||
this.METH_java_util_Iterator__next = this.TYPE_java_util_Iterator .findIMethod("next", new IClass[0]);
|
||||
|
||||
this.CTOR_java_lang_StringBuilder__java_lang_String = this.TYPE_java_lang_StringBuilder.findIConstructor(new IClass[] { this.TYPE_java_lang_String });
|
||||
// CHECKSTYLE Whitespace:ON
|
||||
// CHECKSTYLE LineLength:ON
|
||||
} catch (Exception e) {
|
||||
throw new JaninoRuntimeException("Cannot load simple types", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an {@link IClass} by field descriptor.
|
||||
*
|
||||
* @param fieldDescriptor E.g. 'Lpkg1/pkg2/Outer$Inner;'
|
||||
* @return {@code null} if an {@link IClass} could not be loaded
|
||||
* @throws ClassNotFoundException An exception was raised while loading the {@link IClass}
|
||||
*/
|
||||
public final IClass
|
||||
loadIClass(String fieldDescriptor) throws ClassNotFoundException {
|
||||
if (IClassLoader.DEBUG) System.out.println(this + ": Load type \"" + fieldDescriptor + "\"");
|
||||
|
||||
if (Descriptor.isPrimitive(fieldDescriptor)) {
|
||||
return (
|
||||
fieldDescriptor.equals(Descriptor.VOID) ? IClass.VOID :
|
||||
fieldDescriptor.equals(Descriptor.BYTE) ? IClass.BYTE :
|
||||
fieldDescriptor.equals(Descriptor.CHAR) ? IClass.CHAR :
|
||||
fieldDescriptor.equals(Descriptor.DOUBLE) ? IClass.DOUBLE :
|
||||
fieldDescriptor.equals(Descriptor.FLOAT) ? IClass.FLOAT :
|
||||
fieldDescriptor.equals(Descriptor.INT) ? IClass.INT :
|
||||
fieldDescriptor.equals(Descriptor.LONG) ? IClass.LONG :
|
||||
fieldDescriptor.equals(Descriptor.SHORT) ? IClass.SHORT :
|
||||
fieldDescriptor.equals(Descriptor.BOOLEAN) ? IClass.BOOLEAN :
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// Ask parent IClassLoader first.
|
||||
if (this.optionalParentIClassLoader != null) {
|
||||
IClass res = this.optionalParentIClassLoader.loadIClass(fieldDescriptor);
|
||||
if (res != null) return res;
|
||||
}
|
||||
|
||||
// We need to synchronize here because "unloadableIClasses" and
|
||||
// "loadedIClasses" are unsynchronized containers.
|
||||
IClass result;
|
||||
synchronized (this) {
|
||||
|
||||
// Class could not be loaded before?
|
||||
if (this.unloadableIClasses.contains(fieldDescriptor)) return null;
|
||||
|
||||
// Class already loaded?
|
||||
result = (IClass) this.loadedIClasses.get(fieldDescriptor);
|
||||
if (result != null) return result;
|
||||
|
||||
// Special handling for array types.
|
||||
if (Descriptor.isArrayReference(fieldDescriptor)) {
|
||||
|
||||
// Load the component type.
|
||||
IClass componentIClass = this.loadIClass(
|
||||
Descriptor.getComponentDescriptor(fieldDescriptor)
|
||||
);
|
||||
if (componentIClass == null) return null;
|
||||
|
||||
// Now get and define the array type.
|
||||
IClass arrayIClass = componentIClass.getArrayIClass(this.TYPE_java_lang_Object);
|
||||
this.loadedIClasses.put(fieldDescriptor, arrayIClass);
|
||||
return arrayIClass;
|
||||
}
|
||||
|
||||
if (IClassLoader.DEBUG) System.out.println("call IClassLoader.findIClass(\"" + fieldDescriptor + "\")");
|
||||
|
||||
// Load the class through the {@link #findIClass(String)} method implemented by the
|
||||
// derived class.
|
||||
result = this.findIClass(fieldDescriptor);
|
||||
if (result == null) {
|
||||
this.unloadableIClasses.add(fieldDescriptor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.getDescriptor().equalsIgnoreCase(fieldDescriptor)) {
|
||||
throw new JaninoRuntimeException(
|
||||
"\"findIClass()\" returned \""
|
||||
+ result.getDescriptor()
|
||||
+ "\" instead of \""
|
||||
+ fieldDescriptor
|
||||
+ "\""
|
||||
);
|
||||
}
|
||||
|
||||
if (IClassLoader.DEBUG) System.out.println(this + ": Loaded type \"" + fieldDescriptor + "\" as " + result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a new {@link IClass} by descriptor; return <code>null</code> if a class
|
||||
* for that <code>descriptor</code> could not be found.
|
||||
* <p>
|
||||
* Similar {@link java.lang.ClassLoader#findClass(java.lang.String)}, this method
|
||||
* must
|
||||
* <ul>
|
||||
* <li>Get an {@link IClass} object from somewhere for the given type
|
||||
* <li>Call {@link #defineIClass(IClass)} with that {@link IClass} object as
|
||||
* the argument
|
||||
* <li>Return the {@link IClass} object
|
||||
* </ul>
|
||||
* <p>
|
||||
* The format of a <code>descriptor</code> is defined in JVMS 4.3.2. Typical
|
||||
* descriptors are:
|
||||
* <ul>
|
||||
* <li><code>I</code> (Integer)
|
||||
* <li><code>Lpkg1/pkg2/Cls;</code> (Class declared in package)
|
||||
* <li><code>Lpkg1/pkg2/Outer$Inner;</code> Member class
|
||||
* </ul>
|
||||
* Notice that this method is never called for array types.
|
||||
* <p>
|
||||
* Notice that this method is never called from more than one thread at a time.
|
||||
* In other words, implementations of this method need not be synchronized.
|
||||
*
|
||||
* @return <code>null</code> if a class with that descriptor could not be found
|
||||
* @throws ClassNotFoundException if an exception was raised while loading the class
|
||||
*/
|
||||
protected abstract IClass findIClass(String descriptor) throws ClassNotFoundException;
|
||||
|
||||
/**
|
||||
* Define an {@link IClass} in the context of this {@link IClassLoader}.
|
||||
* If an {@link IClass} with that descriptor already exists, a
|
||||
* {@link RuntimeException} is thrown.
|
||||
* <p>
|
||||
* This method should only be called from an implementation of
|
||||
* {@link #findIClass(String)}.
|
||||
*
|
||||
* @throws RuntimeException A different {@link IClass} object is already defined for this type
|
||||
*/
|
||||
protected final void
|
||||
defineIClass(IClass iClass) {
|
||||
String descriptor = iClass.getDescriptor();
|
||||
|
||||
// Already defined?
|
||||
IClass loadedIClass = (IClass) this.loadedIClasses.get(descriptor);
|
||||
if (loadedIClass != null) {
|
||||
if (loadedIClass == iClass) return;
|
||||
throw new JaninoRuntimeException("Non-identical definition of IClass \"" + descriptor + "\"");
|
||||
}
|
||||
|
||||
// Define.
|
||||
this.loadedIClasses.put(descriptor, iClass);
|
||||
if (IClassLoader.DEBUG) System.out.println(this + ": Defined type \"" + descriptor + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link IClassLoader} that looks for classes in the given "boot class
|
||||
* path", then in the given "extension directories", and then in the given
|
||||
* "class path".
|
||||
* <p>
|
||||
* The default for the <code>optionalBootClassPath</code> is the path defined in
|
||||
* the system property "sun.boot.class.path", and the default for the
|
||||
* <code>optionalExtensionDirs</code> is the path defined in the "java.ext.dirs"
|
||||
* system property.
|
||||
*/
|
||||
public static IClassLoader
|
||||
createJavacLikePathIClassLoader(
|
||||
final File[] optionalBootClassPath,
|
||||
final File[] optionalExtDirs,
|
||||
final File[] classPath
|
||||
) {
|
||||
ResourceFinder bootClassPathResourceFinder = new PathResourceFinder(
|
||||
optionalBootClassPath == null
|
||||
? PathResourceFinder.parsePath(System.getProperty("sun.boot.class.path"))
|
||||
: optionalBootClassPath
|
||||
);
|
||||
ResourceFinder extensionDirectoriesResourceFinder = new JarDirectoriesResourceFinder(
|
||||
optionalExtDirs == null
|
||||
? PathResourceFinder.parsePath(System.getProperty("java.ext.dirs"))
|
||||
: optionalExtDirs
|
||||
);
|
||||
final ResourceFinder classPathResourceFinder = new PathResourceFinder(classPath);
|
||||
|
||||
// We can load classes through "ResourceFinderIClassLoader"s, which means
|
||||
// they are read into "ClassFile" objects, or we can load classes through
|
||||
// "ClassLoaderIClassLoader"s, which means they are loaded into the JVM.
|
||||
//
|
||||
// In my environment, the latter is slightly faster. No figures about
|
||||
// resource usage yet.
|
||||
//
|
||||
// In applications where the generated classes are not loaded into the
|
||||
// same JVM instance, we should avoid to use the
|
||||
// ClassLoaderIClassLoader, because that assumes that final fields have
|
||||
// a constant value, even if not compile-time-constant but only
|
||||
// initialization-time constant. The classical example is
|
||||
// "File.separator", which is non-blank final, but not compile-time-
|
||||
// constant.
|
||||
IClassLoader icl;
|
||||
icl = new ResourceFinderIClassLoader(bootClassPathResourceFinder, null);
|
||||
icl = new ResourceFinderIClassLoader(extensionDirectoriesResourceFinder, icl);
|
||||
icl = new ResourceFinderIClassLoader(classPathResourceFinder, icl);
|
||||
return icl;
|
||||
}
|
||||
|
||||
private final IClassLoader optionalParentIClassLoader;
|
||||
private final Map<String /*descriptor*/, IClass> loadedIClasses = new HashMap();
|
||||
private final Set<String /*descriptor*/> unloadableIClasses = new HashSet();
|
||||
}
|
40
src/org/codehaus/janino/JaninoRuntimeException.java
Normal file
40
src/org/codehaus/janino/JaninoRuntimeException.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
/**
|
||||
* All Janino components that throw {@link RuntimeException} throw this subclass
|
||||
* to allow for client libraries to intercept them more easily.
|
||||
*/
|
||||
public
|
||||
class JaninoRuntimeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 7155453370536273589L;
|
||||
public JaninoRuntimeException() {}
|
||||
public JaninoRuntimeException(String message) { super(message); }
|
||||
public JaninoRuntimeException(String message, Throwable t) { super(message, t); }
|
||||
}
|
4655
src/org/codehaus/janino/Java.java
Normal file
4655
src/org/codehaus/janino/Java.java
Normal file
File diff suppressed because it is too large
Load Diff
256
src/org/codehaus/janino/JavaSourceClassLoader.java
Normal file
256
src/org/codehaus/janino/JavaSourceClassLoader.java
Normal file
|
@ -0,0 +1,256 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codehaus.commons.compiler.AbstractJavaSourceClassLoader;
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.ErrorHandler;
|
||||
import org.codehaus.commons.compiler.ICookable;
|
||||
import org.codehaus.commons.compiler.WarningHandler;
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.resource.DirectoryResourceFinder;
|
||||
import org.codehaus.janino.util.resource.PathResourceFinder;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
/**
|
||||
* A {@link ClassLoader} that, unlike usual {@link ClassLoader}s,
|
||||
* does not load byte code, but reads Java™ 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;
|
||||
}
|
208
src/org/codehaus/janino/JavaSourceIClassLoader.java
Normal file
208
src/org/codehaus/janino/JavaSourceIClassLoader.java
Normal file
|
@ -0,0 +1,208 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.ErrorHandler;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
import org.codehaus.commons.compiler.WarningHandler;
|
||||
import org.codehaus.janino.Java.CompilationUnit;
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.resource.Resource;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
|
||||
/**
|
||||
* This {@link org.codehaus.janino.IClassLoader} finds, scans and parses compilation units.
|
||||
* <p>
|
||||
* Notice that it does not compile them!
|
||||
*/
|
||||
public
|
||||
class JavaSourceIClassLoader extends IClassLoader {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private ResourceFinder sourceFinder;
|
||||
private String optionalCharacterEncoding;
|
||||
/** Collection of parsed compilation units. */
|
||||
private final Set<UnitCompiler> unitCompilers = new HashSet<UnitCompiler>();
|
||||
|
||||
private ErrorHandler optionalCompileErrorHandler;
|
||||
private WarningHandler optionalWarningHandler;
|
||||
|
||||
public
|
||||
JavaSourceIClassLoader(
|
||||
ResourceFinder sourceFinder,
|
||||
String optionalCharacterEncoding,
|
||||
IClassLoader optionalParentIClassLoader
|
||||
) {
|
||||
super(optionalParentIClassLoader);
|
||||
|
||||
this.sourceFinder = sourceFinder;
|
||||
this.optionalCharacterEncoding = optionalCharacterEncoding;
|
||||
super.postConstruct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of {@link UnitCompiler}s that were created so far.
|
||||
*/
|
||||
public Set<UnitCompiler>
|
||||
getUnitCompilers() { return this.unitCompilers; }
|
||||
|
||||
/** @param pathResourceFinder The source path */
|
||||
public void
|
||||
setSourceFinder(ResourceFinder pathResourceFinder) {
|
||||
this.sourceFinder = pathResourceFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param optionalCharacterEncoding The name of the charset that is used to read source files, or {@code null} to
|
||||
* use the platform's 'default charset'
|
||||
*/
|
||||
public void
|
||||
setCharacterEncoding(String optionalCharacterEncoding) {
|
||||
this.optionalCharacterEncoding = optionalCharacterEncoding;
|
||||
}
|
||||
|
||||
/** @see UnitCompiler#setCompileErrorHandler(ErrorHandler) */
|
||||
public void
|
||||
setCompileErrorHandler(ErrorHandler optionalCompileErrorHandler) {
|
||||
this.optionalCompileErrorHandler = optionalCompileErrorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Parser#setWarningHandler(WarningHandler)
|
||||
* @see UnitCompiler#setCompileErrorHandler(ErrorHandler)
|
||||
*/
|
||||
public void
|
||||
setWarningHandler(WarningHandler optionalWarningHandler) {
|
||||
this.optionalWarningHandler = optionalWarningHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldDescriptor Field descriptor of the {@link IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;"
|
||||
* @throws ClassNotFoundException An exception was raised while loading the {@link IClass}
|
||||
*/
|
||||
@Override public IClass
|
||||
findIClass(final String fieldDescriptor) throws ClassNotFoundException {
|
||||
if (JavaSourceIClassLoader.DEBUG) System.out.println("type = " + fieldDescriptor);
|
||||
|
||||
// Class type.
|
||||
String className = Descriptor.toClassName(fieldDescriptor); // E.g. "pkg1.pkg2.Outer$Inner"
|
||||
if (JavaSourceIClassLoader.DEBUG) System.out.println("2 className = \"" + className + "\"");
|
||||
|
||||
// Do not attempt to load classes from package "java".
|
||||
if (className.startsWith("java.")) return null;
|
||||
|
||||
// Determine the name of the top-level class.
|
||||
String topLevelClassName;
|
||||
{
|
||||
int idx = className.indexOf('$');
|
||||
topLevelClassName = idx == -1 ? className : className.substring(0, idx);
|
||||
}
|
||||
|
||||
// Check the already-parsed compilation units.
|
||||
for (UnitCompiler uc : this.unitCompilers) {
|
||||
IClass res = uc.findClass(topLevelClassName);
|
||||
if (res != null) {
|
||||
if (!className.equals(topLevelClassName)) {
|
||||
res = uc.findClass(className);
|
||||
if (res == null) return null;
|
||||
}
|
||||
this.defineIClass(res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Java.CompilationUnit cu = this.findCompilationUnit(className);
|
||||
if (cu == null) return null;
|
||||
|
||||
UnitCompiler uc = new UnitCompiler(cu, this);
|
||||
uc.setCompileErrorHandler(this.optionalCompileErrorHandler);
|
||||
uc.setWarningHandler(this.optionalWarningHandler);
|
||||
|
||||
// Remember compilation unit for later compilation.
|
||||
this.unitCompilers.add(uc);
|
||||
|
||||
// Find the class/interface declaration in the compiled unit.
|
||||
IClass res = uc.findClass(className);
|
||||
if (res == null) {
|
||||
if (className.equals(topLevelClassName)) {
|
||||
throw new CompileException(
|
||||
"Compilation unit '" + className + "' does not declare a class with the same name",
|
||||
(Location) null
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
this.defineIClass(res);
|
||||
return res;
|
||||
} catch (IOException e) {
|
||||
throw new ClassNotFoundException("Parsing compilation unit '" + className + "'", e);
|
||||
} catch (CompileException e) {
|
||||
throw new ClassNotFoundException("Parsing compilation unit '" + className + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the Java™ 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) {}
|
||||
}
|
||||
}
|
||||
}
|
86
src/org/codehaus/janino/MethodDescriptor.java
Normal file
86
src/org/codehaus/janino/MethodDescriptor.java
Normal file
|
@ -0,0 +1,86 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Representation of a "method descriptor" (JVMS 4.3.3). */
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class MethodDescriptor {
|
||||
|
||||
/** The field descriptors of the method parameters. */
|
||||
public final String[] parameterFds;
|
||||
|
||||
/** The field descriptor of the method return value. */
|
||||
public final String returnFd;
|
||||
|
||||
/** */
|
||||
public
|
||||
MethodDescriptor(String[] parameterFds, String returnFd) {
|
||||
this.parameterFds = parameterFds;
|
||||
this.returnFd = returnFd;
|
||||
}
|
||||
|
||||
/** Parse a method descriptor into parameter FDs and return FDs. */
|
||||
public
|
||||
MethodDescriptor(String s) {
|
||||
if (s.charAt(0) != '(') throw new JaninoRuntimeException();
|
||||
|
||||
int from = 1;
|
||||
List<String> parameterFDs = new ArrayList();
|
||||
while (s.charAt(from) != ')') {
|
||||
int to = from;
|
||||
while (s.charAt(to) == '[') ++to;
|
||||
if ("BCDFIJSZ".indexOf(s.charAt(to)) != -1) {
|
||||
++to;
|
||||
} else
|
||||
if (s.charAt(to) == 'L') {
|
||||
for (++to; s.charAt(to) != ';'; ++to);
|
||||
++to;
|
||||
} else {
|
||||
throw new JaninoRuntimeException();
|
||||
}
|
||||
parameterFDs.add(s.substring(from, to));
|
||||
from = to;
|
||||
}
|
||||
this.parameterFds = (String[]) parameterFDs.toArray(new String[parameterFDs.size()]);
|
||||
this.returnFd = s.substring(++from);
|
||||
}
|
||||
|
||||
/** @return The "method descriptor" (JVMS 4.3.3) */
|
||||
@Override public String
|
||||
toString() {
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
for (String parameterFd : this.parameterFds) sb.append(parameterFd);
|
||||
return sb.append(')').append(this.returnFd).toString();
|
||||
}
|
||||
|
||||
/** Patches an additional parameter into a given method descriptor. */
|
||||
public static String
|
||||
prependParameter(String md, String parameterFd) { return '(' + parameterFd + md.substring(1); }
|
||||
}
|
270
src/org/codehaus/janino/Mod.java
Normal file
270
src/org/codehaus/janino/Mod.java
Normal file
|
@ -0,0 +1,270 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
/**
|
||||
* This class defines constants and convenience methods for the handling of modifiers as defined by the JVM.
|
||||
* <p>
|
||||
* Notice: This class should be named <code>IClass.IModifier</code>, but changing the name would break existing client
|
||||
* code. Thus it won't be renamed until there's a really good reason to do it (maybe with a major design change).
|
||||
*/
|
||||
public final
|
||||
class Mod {
|
||||
private Mod() {} // Don't instantiate me!
|
||||
|
||||
/** An alias for '0' -- <i>no</i> modifiers. */
|
||||
public static final short NONE = 0x0000;
|
||||
|
||||
/**
|
||||
* The flag indicating 'public accessibility' of the modified element. Methods of interfaces are always {@link
|
||||
* #PUBLIC}.
|
||||
*
|
||||
* @see #PPP
|
||||
* @see #isPublicAccess(short)
|
||||
*/
|
||||
public static final short PUBLIC = 0x0001;
|
||||
|
||||
/** @return Whether the given modifier symbolizes {@link #PUBLIC} accessibility */
|
||||
public static boolean isPublicAccess(short sh) { return (sh & Mod.PPP) == Mod.PUBLIC; }
|
||||
|
||||
/**
|
||||
* The flag indicating 'private accessibility' of the modified element.
|
||||
*
|
||||
* @see #PPP
|
||||
* @see #isPrivateAccess(short)
|
||||
*/
|
||||
public static final short PRIVATE = 0x0002;
|
||||
|
||||
/** @return Whether the given modifier symbolizes {@link #PRIVATE} accessibility */
|
||||
public static boolean isPrivateAccess(short sh) { return (sh & Mod.PPP) == Mod.PRIVATE; }
|
||||
|
||||
/**
|
||||
* The flag indicating 'protected accessibility' of the modified element.
|
||||
*
|
||||
* @see #PPP
|
||||
* @see #isProtectedAccess(short)
|
||||
*/
|
||||
public static final short PROTECTED = 0x0004;
|
||||
|
||||
/** @return Whether the given modifier symbolizes {@link #PROTECTED} accessibility */
|
||||
public static boolean isProtectedAccess(short sh) { return (sh & Mod.PPP) == Mod.PROTECTED; }
|
||||
|
||||
/**
|
||||
* The flag indicating 'default accessibility' a.k.a. 'package accessibility' of the modified element.
|
||||
*
|
||||
* @see #PPP
|
||||
* @see #isPackageAccess(short)
|
||||
*/
|
||||
public static final short PACKAGE = 0x0000;
|
||||
|
||||
/** @return Whether the given modifier symbolizes {@link #PACKAGE} (a.k.a. 'default') accessibility */
|
||||
public static boolean isPackageAccess(short sh) { return (sh & Mod.PPP) == Mod.PACKAGE; }
|
||||
|
||||
/** The mask to select the accessibility flags from modifiers. */
|
||||
public static final short PPP = 0x0007;
|
||||
|
||||
/** @return The given {@code modifiers}, but with the accessibility part changed to {@code newAccess} */
|
||||
public static short
|
||||
changeAccess(short modifiers, short newAccess) { return (short) ((modifiers & ~Mod.PPP) | newAccess); }
|
||||
|
||||
/**
|
||||
* This flag is set on class or interface initialization methods, STATIC class fields, all interface fields, STATIC
|
||||
* methods, and STATIC nested classes.
|
||||
*/
|
||||
public static final short STATIC = 0x0008;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #STATIC} */
|
||||
public static boolean isStatic(short sh) { return (sh & Mod.STATIC) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on FINAL classes, FINAL fields and FINAL methods, and is mutually exclusive with {@link
|
||||
* #VOLATILE} and {@link #ABSTRACT}.
|
||||
*/
|
||||
public static final short FINAL = 0x0010;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #INTERFACE} */
|
||||
public static boolean isFinal(short sh) { return (sh & Mod.FINAL) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is always set on classes, and never set on any other element. Notice that it has the same value as
|
||||
* {@link #SYNCHRONIZED}, which is OK because {@link #SYNCHRONIZED} is for methods and {@link #SUPER} for classes.
|
||||
*/
|
||||
public static final short SUPER = 0x0020;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #SUPER} */
|
||||
public static boolean isSuper(short sh) { return (sh & Mod.SUPER) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on SYNCHRONIZED methods. Notice that it has the same value as {@link #SUPER}, which is OK
|
||||
* because {@link #SYNCHRONIZED} is for methods and {@link #SUPER} for classes.
|
||||
*/
|
||||
public static final short SYNCHRONIZED = 0x0020;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #SYNCHRONIZED} */
|
||||
public static boolean isSynchronized(short sh) { return (sh & Mod.SYNCHRONIZED) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on VOLATILE fields and is mutually exclusive with {@link #FINAL}. Notice that it has the same
|
||||
* value as {@link #BRIDGE}, which is OK because {@link #BRIDGE} is for methods and {@link #VOLATILE} for fields.
|
||||
*/
|
||||
public static final short VOLATILE = 0x0040;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #VOLATILE} */
|
||||
public static boolean isVolatile(short sh) { return (sh & Mod.VOLATILE) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on 'bridge methods' generated by the compiler. Notice that it has the same value as {@link
|
||||
* #VOLATILE}, which is OK because {@link #BRIDGE} is for methods and {@link #VOLATILE} for fields.
|
||||
*/
|
||||
public static final short BRIDGE = 0x0040;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #BRIDGE} */
|
||||
public static boolean isBridge(short sh) { return (sh & Mod.BRIDGE) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on TRANSIENT fields. Notice that it has the same value as {@link #VARARGS}, which is OK because
|
||||
* {@link #VARARGS} is for methods and {@link #TRANSIENT} for fields.
|
||||
*/
|
||||
public static final short TRANSIENT = 0x0080;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #TRANSIENT} */
|
||||
public static boolean isTransient(short sh) { return (sh & Mod.TRANSIENT) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on 'variable arity' (a.k.a. 'varargs') methods and constructors. Notice that it has the same
|
||||
* value as {@link #TRANSIENT}, which is OK because {@link #VARARGS} is for methods and {@link #TRANSIENT} for
|
||||
* fields.
|
||||
*/
|
||||
public static final short VARARGS = 0x0080;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #VARARGS} */
|
||||
public static boolean isVarargs(short sh) { return (sh & Mod.VARARGS) != 0; }
|
||||
|
||||
/** This flag is set on NATIVE methods, and is mutually exclusive with {@link #ABSTRACT}. */
|
||||
public static final short NATIVE = 0x0100;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #NATIVE} */
|
||||
public static boolean isNative(short sh) { return (sh & Mod.NATIVE) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on interfaces (including nested interfaces), and requires that {@link #ABSTRACT} must also be
|
||||
* set. {@link #INTERFACE} is mutually exclusive with {@link #FINAL}, {@link #SUPER} and {@link #ENUM}.
|
||||
*/
|
||||
public static final short INTERFACE = 0x0200;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #INTERFACE} */
|
||||
public static boolean isInterface(short sh) { return (sh & Mod.INTERFACE) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on all interfaces, ABSTRACT classes and ABSTRACT methods, and is mutually exclusive with
|
||||
* {@link #FINAL}, {@link #NATIVE}, {@link #PRIVATE}, {@link #STATIC} and {@link #SYNCHRONIZED}.
|
||||
*/
|
||||
public static final short ABSTRACT = 0x0400;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #ABSTRACT} */
|
||||
public static boolean isAbstract(short sh) { return (sh & Mod.ABSTRACT) != 0; }
|
||||
|
||||
/** This flag is set on STRICTFP methods, and is mutually exclusive with {@link #ABSTRACT}. */
|
||||
public static final short STRICTFP = 0x0800;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #STRICTFP} */
|
||||
public static boolean isStrictfp(short sh) { return (sh & Mod.STRICTFP) != 0; }
|
||||
|
||||
// Poorly documented JDK 1.5 modifiers:
|
||||
|
||||
/**
|
||||
* This flag is set on classes, methods and fields that were generated by the compiler and do not appear in the
|
||||
* source code.
|
||||
*/
|
||||
public static final short SYNTHETIC = 0x1000;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #SYNTHETIC} */
|
||||
public static boolean isSynthetic(short sh) { return (sh & Mod.SYNTHETIC) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on annotation types (including nested annotation types), and requires that {@link #INTERFACE}
|
||||
* is also set.
|
||||
*/
|
||||
public static final short ANNOTATION = 0x2000;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #ANNOTATION} */
|
||||
public static boolean isAnnotation(short sh) { return (sh & Mod.ANNOTATION) != 0; }
|
||||
|
||||
/**
|
||||
* This flag is set on enumerated types (including nested enumerated types) and enumerated types' elements, and is
|
||||
* mutually exclusive with {@link #INTERFACE}.
|
||||
*/
|
||||
public static final short ENUM = 0x4000;
|
||||
|
||||
/** @return Whether the given modifier includes {@link #ENUM} */
|
||||
public static boolean isEnum(short sh) { return (sh & Mod.ENUM) != 0; }
|
||||
|
||||
/**
|
||||
* Composes and returns a string that maps the given modifier as follows:
|
||||
* <ul>
|
||||
* <li>Value zero is mapped to "".
|
||||
* <li>Non-zero values are mapped to a sequence of words, separated with blanks.
|
||||
* <li>{@link #VARARGS} is mapped to "transient", because the two flags have the same value
|
||||
* <li>{@link #SUPER} is mapped to "synchronized", because the two flags have the same value
|
||||
* <li>{@link #BRIDGE} is mapped to "volatile", because the two flags have the same value
|
||||
* </ul>
|
||||
*/
|
||||
public static String
|
||||
shortToString(short sh) {
|
||||
if (sh == 0) return "";
|
||||
StringBuilder res = new StringBuilder();
|
||||
for (int i = 0; i < Mod.MAPPINGS.length; i += 2) {
|
||||
if ((sh & ((Short) Mod.MAPPINGS[i + 1]).shortValue()) == 0) continue;
|
||||
if (res.length() > 0) res.append(' ');
|
||||
res.append((String) Mod.MAPPINGS[i]);
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
private static final Object[] MAPPINGS = {
|
||||
"public", new Short(Mod.PUBLIC),
|
||||
"private", new Short(Mod.PRIVATE),
|
||||
"protected", new Short(Mod.PROTECTED),
|
||||
// "???", new Short(Mod.PACKAGE),
|
||||
"static", new Short(Mod.STATIC),
|
||||
"final", new Short(Mod.FINAL),
|
||||
"synchronized", new Short(Mod.SYNCHRONIZED), // Has the same value as SUPER
|
||||
// "super", new Short(Mod.SUPER), // Has the same value as SYNCHRONIZED
|
||||
"volatile", new Short(Mod.VOLATILE), // Has the same value as BRIDGE
|
||||
// "bridge", new Short(Mod.BRIDGE), // Has the same value as VOLATILE
|
||||
"transient", new Short(Mod.TRANSIENT), // Has the same value as VARARGS
|
||||
// "varargs", new Short(Mod.VARARGS), // Has the same value as TRANSIENT
|
||||
"native", new Short(Mod.NATIVE),
|
||||
"interface", new Short(Mod.INTERFACE),
|
||||
"abstract", new Short(Mod.ABSTRACT),
|
||||
"strictfp", new Short(Mod.STRICTFP),
|
||||
"enum", new Short(Mod.ENUM),
|
||||
"synthetic", new Short(Mod.SYNTHETIC),
|
||||
"@", new Short(Mod.ANNOTATION),
|
||||
};
|
||||
}
|
||||
|
614
src/org/codehaus/janino/Opcode.java
Normal file
614
src/org/codehaus/janino/Opcode.java
Normal file
|
@ -0,0 +1,614 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
/** Definitions of Java bytecode opcodes. */
|
||||
final
|
||||
class Opcode {
|
||||
private Opcode() {}
|
||||
|
||||
// Symbolic JVM opcodes, in alphabetical order.
|
||||
|
||||
// CHECKSTYLE JavadocVariable:OFF
|
||||
public static final byte AALOAD = 50;
|
||||
public static final byte AASTORE = 83;
|
||||
public static final byte ACONST_NULL = 1;
|
||||
public static final byte ALOAD = 25;
|
||||
public static final byte ALOAD_0 = 42;
|
||||
public static final byte ALOAD_1 = 43;
|
||||
public static final byte ALOAD_2 = 44;
|
||||
public static final byte ALOAD_3 = 45;
|
||||
public static final byte ANEWARRAY = (byte) 189;
|
||||
public static final byte ARETURN = (byte) 176;
|
||||
public static final byte ARRAYLENGTH = (byte) 190;
|
||||
public static final byte ASTORE = 58;
|
||||
public static final byte ASTORE_0 = 75;
|
||||
public static final byte ASTORE_1 = 76;
|
||||
public static final byte ASTORE_2 = 77;
|
||||
public static final byte ASTORE_3 = 78;
|
||||
public static final byte ATHROW = (byte) 191;
|
||||
public static final byte BALOAD = 51;
|
||||
public static final byte BASTORE = 84;
|
||||
public static final byte BIPUSH = 16;
|
||||
public static final byte CALOAD = 52;
|
||||
public static final byte CASTORE = 85;
|
||||
public static final byte CHECKCAST = (byte) 192;
|
||||
public static final byte D2F = (byte) 144;
|
||||
public static final byte D2I = (byte) 142;
|
||||
public static final byte D2L = (byte) 143;
|
||||
public static final byte DADD = 99;
|
||||
public static final byte DALOAD = 49;
|
||||
public static final byte DASTORE = 82;
|
||||
public static final byte DCMPG = (byte) 152;
|
||||
public static final byte DCMPL = (byte) 151;
|
||||
public static final byte DCONST_0 = 14;
|
||||
public static final byte DCONST_1 = 15;
|
||||
public static final byte DDIV = 111;
|
||||
public static final byte DLOAD = 24;
|
||||
public static final byte DLOAD_0 = 38;
|
||||
public static final byte DLOAD_1 = 39;
|
||||
public static final byte DLOAD_2 = 40;
|
||||
public static final byte DLOAD_3 = 41;
|
||||
public static final byte DMUL = 107;
|
||||
public static final byte DNEG = 119;
|
||||
public static final byte DREM = 115;
|
||||
public static final byte DRETURN = (byte) 175;
|
||||
public static final byte DSTORE = 57;
|
||||
public static final byte DSTORE_0 = 71;
|
||||
public static final byte DSTORE_1 = 72;
|
||||
public static final byte DSTORE_2 = 73;
|
||||
public static final byte DSTORE_3 = 74;
|
||||
public static final byte DSUB = 103;
|
||||
public static final byte DUP = 89;
|
||||
public static final byte DUP_X1 = 90;
|
||||
public static final byte DUP_X2 = 91;
|
||||
public static final byte DUP2 = 92;
|
||||
public static final byte DUP2_X1 = 93;
|
||||
public static final byte DUP2_X2 = 94;
|
||||
public static final byte F2D = (byte) 141;
|
||||
public static final byte F2I = (byte) 139;
|
||||
public static final byte F2L = (byte) 140;
|
||||
public static final byte FADD = 98;
|
||||
public static final byte FALOAD = 48;
|
||||
public static final byte FASTORE = 81;
|
||||
public static final byte FCMPG = (byte) 150;
|
||||
public static final byte FCMPL = (byte) 149;
|
||||
public static final byte FCONST_0 = 11;
|
||||
public static final byte FCONST_1 = 12;
|
||||
public static final byte FCONST_2 = 13;
|
||||
public static final byte FDIV = 110;
|
||||
public static final byte FLOAD = 23;
|
||||
public static final byte FLOAD_0 = 34;
|
||||
public static final byte FLOAD_1 = 35;
|
||||
public static final byte FLOAD_2 = 36;
|
||||
public static final byte FLOAD_3 = 37;
|
||||
public static final byte FMUL = 106;
|
||||
public static final byte FNEG = 118;
|
||||
public static final byte FREM = 114;
|
||||
public static final byte FRETURN = (byte) 174;
|
||||
public static final byte FSTORE = 56;
|
||||
public static final byte FSTORE_0 = 67;
|
||||
public static final byte FSTORE_1 = 68;
|
||||
public static final byte FSTORE_2 = 69;
|
||||
public static final byte FSTORE_3 = 70;
|
||||
public static final byte FSUB = 102;
|
||||
public static final byte GETFIELD = (byte) 180;
|
||||
public static final byte GETSTATIC = (byte) 178;
|
||||
public static final byte GOTO = (byte) 167;
|
||||
public static final byte GOTO_W = (byte) 200;
|
||||
public static final byte I2B = (byte) 145;
|
||||
public static final byte I2C = (byte) 146;
|
||||
public static final byte I2D = (byte) 135;
|
||||
public static final byte I2F = (byte) 134;
|
||||
public static final byte I2L = (byte) 133;
|
||||
public static final byte I2S = (byte) 147;
|
||||
public static final byte IADD = 96;
|
||||
public static final byte IALOAD = 46;
|
||||
public static final byte IAND = 126;
|
||||
public static final byte IASTORE = 79;
|
||||
public static final byte ICONST_M1 = 2;
|
||||
public static final byte ICONST_0 = 3;
|
||||
public static final byte ICONST_1 = 4;
|
||||
public static final byte ICONST_2 = 5;
|
||||
public static final byte ICONST_3 = 6;
|
||||
public static final byte ICONST_4 = 7;
|
||||
public static final byte ICONST_5 = 8;
|
||||
public static final byte IDIV = 108;
|
||||
public static final byte IF_ACMPEQ = (byte) 165;
|
||||
public static final byte IF_ACMPNE = (byte) 166;
|
||||
public static final byte IF_ICMPEQ = (byte) 159;
|
||||
public static final byte IF_ICMPNE = (byte) 160;
|
||||
public static final byte IF_ICMPLT = (byte) 161;
|
||||
public static final byte IF_ICMPGE = (byte) 162;
|
||||
public static final byte IF_ICMPGT = (byte) 163;
|
||||
public static final byte IF_ICMPLE = (byte) 164;
|
||||
public static final byte IFEQ = (byte) 153;
|
||||
public static final byte IFNE = (byte) 154;
|
||||
public static final byte IFLT = (byte) 155;
|
||||
public static final byte IFGE = (byte) 156;
|
||||
public static final byte IFGT = (byte) 157;
|
||||
public static final byte IFLE = (byte) 158;
|
||||
public static final byte IFNONNULL = (byte) 199;
|
||||
public static final byte IFNULL = (byte) 198;
|
||||
public static final byte IINC = (byte) 132;
|
||||
public static final byte ILOAD = 21;
|
||||
public static final byte ILOAD_0 = 26;
|
||||
public static final byte ILOAD_1 = 27;
|
||||
public static final byte ILOAD_2 = 28;
|
||||
public static final byte ILOAD_3 = 29;
|
||||
public static final byte IMUL = 104;
|
||||
public static final byte INEG = 116;
|
||||
public static final byte INSTANCEOF = (byte) 193;
|
||||
public static final byte INVOKEINTERFACE = (byte) 185;
|
||||
public static final byte INVOKESPECIAL = (byte) 183;
|
||||
public static final byte INVOKESTATIC = (byte) 184;
|
||||
public static final byte INVOKEVIRTUAL = (byte) 182;
|
||||
public static final byte IOR = (byte) 128;
|
||||
public static final byte IREM = 112;
|
||||
public static final byte IRETURN = (byte) 172;
|
||||
public static final byte ISHL = 120;
|
||||
public static final byte ISHR = 122;
|
||||
public static final byte ISTORE = 54;
|
||||
public static final byte ISTORE_0 = 59;
|
||||
public static final byte ISTORE_1 = 60;
|
||||
public static final byte ISTORE_2 = 61;
|
||||
public static final byte ISTORE_3 = 62;
|
||||
public static final byte ISUB = 100;
|
||||
public static final byte IUSHR = 124;
|
||||
public static final byte IXOR = (byte) 130;
|
||||
public static final byte JSR = (byte) 168;
|
||||
public static final byte JSR_W = (byte) 201;
|
||||
public static final byte L2D = (byte) 138;
|
||||
public static final byte L2F = (byte) 137;
|
||||
public static final byte L2I = (byte) 136;
|
||||
public static final byte LADD = 97;
|
||||
public static final byte LALOAD = 47;
|
||||
public static final byte LAND = 127;
|
||||
public static final byte LASTORE = 80;
|
||||
public static final byte LCMP = (byte) 148;
|
||||
public static final byte LCONST_0 = 9;
|
||||
public static final byte LCONST_1 = 10;
|
||||
public static final byte LDC = 18;
|
||||
public static final byte LDC_W = 19;
|
||||
public static final byte LDC2_W = 20;
|
||||
public static final byte LDIV = 109;
|
||||
public static final byte LLOAD = 22;
|
||||
public static final byte LLOAD_0 = 30;
|
||||
public static final byte LLOAD_1 = 31;
|
||||
public static final byte LLOAD_2 = 32;
|
||||
public static final byte LLOAD_3 = 33;
|
||||
public static final byte LMUL = 105;
|
||||
public static final byte LNEG = 117;
|
||||
public static final byte LOOKUPSWITCH = (byte) 171;
|
||||
public static final byte LOR = (byte) 129;
|
||||
public static final byte LREM = 113;
|
||||
public static final byte LRETURN = (byte) 173;
|
||||
public static final byte LSHL = 121;
|
||||
public static final byte LSHR = 123;
|
||||
public static final byte LSTORE = 55;
|
||||
public static final byte LSTORE_0 = 63;
|
||||
public static final byte LSTORE_1 = 64;
|
||||
public static final byte LSTORE_2 = 65;
|
||||
public static final byte LSTORE_3 = 66;
|
||||
public static final byte LSUB = 101;
|
||||
public static final byte LUSHR = 125;
|
||||
public static final byte LXOR = (byte) 131;
|
||||
public static final byte MONITORENTER = (byte) 194;
|
||||
public static final byte MONITOREXIT = (byte) 195;
|
||||
public static final byte MULTIANEWARRAY = (byte) 197;
|
||||
public static final byte NEW = (byte) 187;
|
||||
public static final byte NEWARRAY = (byte) 188;
|
||||
public static final byte NOP = 0;
|
||||
public static final byte POP = 87;
|
||||
public static final byte POP2 = 88;
|
||||
public static final byte PUTFIELD = (byte) 181;
|
||||
public static final byte PUTSTATIC = (byte) 179;
|
||||
public static final byte RET = (byte) 169;
|
||||
public static final byte RETURN = (byte) 177;
|
||||
public static final byte SALOAD = 53;
|
||||
public static final byte SASTORE = 86;
|
||||
public static final byte SIPUSH = 17;
|
||||
public static final byte SWAP = 95;
|
||||
public static final byte TABLESWITCH = (byte) 170;
|
||||
public static final byte WIDE = (byte) 196;
|
||||
// CHECKSTYLE JavadocVariable:ON
|
||||
|
||||
// Constants for the "OPCODE_PROPERTIES" array.
|
||||
|
||||
/** Special value for {@link #OPCODE_PROPERTIES} indicating that this element represents an invalid opcode. */
|
||||
public static final short INVALID_OPCODE = -1;
|
||||
|
||||
/** Masks the 'stack delta' portion of {@link #OPCODE_PROPERTIES}. */
|
||||
public static final short SD_MASK = 31;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
|
||||
* size by 4 elements.
|
||||
*/
|
||||
public static final short SD_M4 = 0;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
|
||||
* size by 3 elements.
|
||||
*/
|
||||
public static final short SD_M3 = 1;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
|
||||
* size by 2 elements.
|
||||
*/
|
||||
public static final short SD_M2 = 2;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} reduces the operand stack
|
||||
* size by 1 element.
|
||||
*/
|
||||
public static final short SD_M1 = 3;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} results in the same operand
|
||||
* stack size.
|
||||
*/
|
||||
public static final short SD_P0 = 4;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} increases the operand stack
|
||||
* size by 1 element.
|
||||
*/
|
||||
public static final short SD_P1 = 5;
|
||||
/**
|
||||
* Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} increases the operand stack
|
||||
* size by 2 elements.
|
||||
*/
|
||||
public static final short SD_P2 = 6;
|
||||
/** Indicates that the opcode represented by this element of {@link #OPCODE_PROPERTIES} clears the operand stack. */
|
||||
public static final short SD_0 = 7;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the GETFIELD opcode. */
|
||||
public static final short SD_GETFIELD = 9;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the GETSTATIC opcode. */
|
||||
public static final short SD_GETSTATIC = 10;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the PUTFIELD opcode. */
|
||||
public static final short SD_PUTFIELD = 11;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the PUTSTATIC opcode. */
|
||||
public static final short SD_PUTSTATIC = 12;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKEVIRTUAL opcode. */
|
||||
public static final short SD_INVOKEVIRTUAL = 13;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKESPECIAL opcode. */
|
||||
public static final short SD_INVOKESPECIAL = 14;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKESTATIC opcode. */
|
||||
public static final short SD_INVOKESTATIC = 15;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the INVOKEINTERFACE opcode. */
|
||||
public static final short SD_INVOKEINTERFACE = 16;
|
||||
/** This element of {@link #OPCODE_PROPERTIES} represents the MULTIANEWARRAY opcode. */
|
||||
public static final short SD_MULTIANEWARRAY = 18;
|
||||
|
||||
// Properties of the opcode's first operand.
|
||||
|
||||
/** Masks the 'first operand' portion of {@link #OPCODE_PROPERTIES}. */
|
||||
public static final short OP1_MASK = 15 * 32;
|
||||
/** The first operand of this opcode is a signed byte. */
|
||||
public static final short OP1_SB = 1 * 32;
|
||||
/** The first operand of this opcode is an unsigned byte. */
|
||||
public static final short OP1_UB = 2 * 32;
|
||||
/** The first operand of this opcode is a signed short. */
|
||||
public static final short OP1_SS = 3 * 32;
|
||||
/** The first operand of this opcode is a one-byte constant pool index. */
|
||||
public static final short OP1_CP1 = 4 * 32;
|
||||
/** The first operand of this opcode is a two-byte constant pool index. */
|
||||
public static final short OP1_CP2 = 5 * 32;
|
||||
/** The first operand of this opcode is a one-byte local variable array index. */
|
||||
public static final short OP1_LV1 = 6 * 32;
|
||||
/** The first operand of this opcode is a two-byte local variable array index. */
|
||||
public static final short OP1_LV2 = 7 * 32;
|
||||
/** The first operand of this opcode is a two-byte branch offset. */
|
||||
public static final short OP1_BO2 = 8 * 32;
|
||||
/** The first operand of this opcode is a four-byte branch offset. */
|
||||
public static final short OP1_BO4 = 9 * 32;
|
||||
/** The first operand of this opcode is a signed byte. */
|
||||
public static final short OP1_LOOKUPSWITCH = 10 * 32;
|
||||
/** The first operand of this opcode is a signed byte. */
|
||||
public static final short OP1_TABLESWITCH = 11 * 32;
|
||||
/** The first operand of this opcode is a signed byte. */
|
||||
public static final short OP1_JSR = 12 * 32;
|
||||
|
||||
// Properties of the opcode's second operand.
|
||||
|
||||
/** Masks the 'second operand' portion of {@link #OPCODE_PROPERTIES}. */
|
||||
public static final short OP2_MASK = 3 * 512;
|
||||
/** The second operand of this opcode is a signed byte. */
|
||||
public static final short OP2_SB = 1 * 512;
|
||||
/** The second operand of this opcode is a signed short. */
|
||||
public static final short OP2_SS = 2 * 512;
|
||||
|
||||
// Properties of the opcode's third operand.
|
||||
|
||||
/** Masks the 'third operand' portion of {@link #OPCODE_PROPERTIES}. */
|
||||
public static final short OP3_MASK = 1 * 2048;
|
||||
/** The third operand of this opcode is a signed byte. */
|
||||
public static final short OP3_SB = 1 * 2048;
|
||||
|
||||
// Properties of the opcode's 'implicit' operand.
|
||||
|
||||
/** Masks the 'implicit operand' portion of {@link #OPCODE_PROPERTIES}. */
|
||||
public static final short IO_MASK = 7 * 4096;
|
||||
/** The local variable wiht index 0 is the opcode's implicit operand. */
|
||||
public static final short IO_LV_0 = 1 * 4096;
|
||||
/** The local variable wiht index 1 is the opcode's implicit operand. */
|
||||
public static final short IO_LV_1 = 2 * 4096;
|
||||
/** The local variable wiht index 2 is the opcode's implicit operand. */
|
||||
public static final short IO_LV_2 = 3 * 4096;
|
||||
/** The local variable wiht index 3 is the opcode's implicit operand. */
|
||||
public static final short IO_LV_3 = 4 * 4096;
|
||||
|
||||
/**
|
||||
* This opcode never 'completes normally', i.e. it never passes the control flow to the immediately following
|
||||
* opcode.
|
||||
*/
|
||||
public static final short NO_FALLTHROUGH = (short) 32768;
|
||||
|
||||
/** The {@code n}th element of this array describes the properties of the JVM opcode {@code n}. */
|
||||
public static final short[] OPCODE_PROPERTIES = {
|
||||
// CHECKSTYLE WrapAndIndent:OFF
|
||||
/* 0*/ /*NOP*/ Opcode.SD_P0,
|
||||
/*ACONST_NULL*/ Opcode.SD_P1,
|
||||
/*ICONST_M1*/ Opcode.SD_P1,
|
||||
/*ICONST_0*/ Opcode.SD_P1,
|
||||
/*ICONST_1*/ Opcode.SD_P1,
|
||||
/*ICONST_2*/ Opcode.SD_P1,
|
||||
/*ICONST_3*/ Opcode.SD_P1,
|
||||
/*ICONST_4*/ Opcode.SD_P1,
|
||||
/*ICONST_5*/ Opcode.SD_P1,
|
||||
/*LCONST_0*/ Opcode.SD_P2,
|
||||
/* 10*/ /*LCONST_1*/ Opcode.SD_P2,
|
||||
/*FCONST_0*/ Opcode.SD_P1,
|
||||
/*FCONST_1*/ Opcode.SD_P1,
|
||||
/*FCONST_2*/ Opcode.SD_P1,
|
||||
/*DCONST_0*/ Opcode.SD_P2,
|
||||
/*DCONST_1*/ Opcode.SD_P2,
|
||||
/*BIPUSH*/ Opcode.SD_P1 | Opcode.OP1_SB,
|
||||
/*SIPUSH*/ Opcode.SD_P1 | Opcode.OP1_SS,
|
||||
/*LDC*/ Opcode.SD_P1 | Opcode.OP1_CP1,
|
||||
/*LDC_W*/ Opcode.SD_P1 | Opcode.OP1_CP2,
|
||||
/* 20*/ /*LDC2_W*/ Opcode.SD_P2 | Opcode.OP1_CP2,
|
||||
/*ILOAD*/ Opcode.SD_P1 | Opcode.OP1_LV1,
|
||||
/*LLOAD*/ Opcode.SD_P2 | Opcode.OP1_LV1,
|
||||
/*FLOAD*/ Opcode.SD_P1 | Opcode.OP1_LV1,
|
||||
/*DLOAD*/ Opcode.SD_P2 | Opcode.OP1_LV1,
|
||||
/*ALOAD*/ Opcode.SD_P1 | Opcode.OP1_LV1,
|
||||
/*ILOAD_0*/ Opcode.SD_P1 | Opcode.IO_LV_0,
|
||||
/*ILOAD_1*/ Opcode.SD_P1 | Opcode.IO_LV_1,
|
||||
/*ILOAD_2*/ Opcode.SD_P1 | Opcode.IO_LV_2,
|
||||
/*ILOAD_3*/ Opcode.SD_P1 | Opcode.IO_LV_3,
|
||||
/* 30*/ /*LLOAD_0*/ Opcode.SD_P2 | Opcode.IO_LV_0,
|
||||
/*LLOAD_1*/ Opcode.SD_P2 | Opcode.IO_LV_1,
|
||||
/*LLOAD_2*/ Opcode.SD_P2 | Opcode.IO_LV_2,
|
||||
/*LLOAD_3*/ Opcode.SD_P2 | Opcode.IO_LV_3,
|
||||
/*FLOAD_0*/ Opcode.SD_P1 | Opcode.IO_LV_0,
|
||||
/*FLOAD_1*/ Opcode.SD_P1 | Opcode.IO_LV_1,
|
||||
/*FLOAD_2*/ Opcode.SD_P1 | Opcode.IO_LV_2,
|
||||
/*FLOAD_3*/ Opcode.SD_P1 | Opcode.IO_LV_3,
|
||||
/*DLOAD_0*/ Opcode.SD_P2 | Opcode.IO_LV_0,
|
||||
/*DLOAD_1*/ Opcode.SD_P2 | Opcode.IO_LV_1,
|
||||
/* 40*/ /*DLOAD_2*/ Opcode.SD_P2 | Opcode.IO_LV_2,
|
||||
/*DLOAD_3*/ Opcode.SD_P2 | Opcode.IO_LV_3,
|
||||
/*ALOAD_0*/ Opcode.SD_P1 | Opcode.IO_LV_0,
|
||||
/*ALOAD_1*/ Opcode.SD_P1 | Opcode.IO_LV_1,
|
||||
/*ALOAD_2*/ Opcode.SD_P1 | Opcode.IO_LV_2,
|
||||
/*ALOAD_3*/ Opcode.SD_P1 | Opcode.IO_LV_3,
|
||||
/*IALOAD*/ Opcode.SD_M1,
|
||||
/*LALOAD*/ Opcode.SD_P0,
|
||||
/*FALOAD*/ Opcode.SD_M1,
|
||||
/*DALOAD*/ Opcode.SD_P0,
|
||||
/* 50*/ /*AALOAD*/ Opcode.SD_M1,
|
||||
/*BALOAD*/ Opcode.SD_M1,
|
||||
/*CALOAD*/ Opcode.SD_M1,
|
||||
/*SALOAD*/ Opcode.SD_M1,
|
||||
/*ISTORE*/ Opcode.SD_M1 | Opcode.OP1_LV1,
|
||||
/*LSTORE*/ Opcode.SD_M2 | Opcode.OP1_LV1,
|
||||
/*FSTORE*/ Opcode.SD_M1 | Opcode.OP1_LV1,
|
||||
/*DSTORE*/ Opcode.SD_M2 | Opcode.OP1_LV1,
|
||||
/*ASTORE*/ Opcode.SD_M1 | Opcode.OP1_LV1,
|
||||
/*ISTORE_0*/ Opcode.SD_M1 | Opcode.IO_LV_0,
|
||||
/* 60*/ /*ISTORE_1*/ Opcode.SD_M1 | Opcode.IO_LV_1,
|
||||
/*ISTORE_2*/ Opcode.SD_M1 | Opcode.IO_LV_2,
|
||||
/*ISTORE_3*/ Opcode.SD_M1 | Opcode.IO_LV_3,
|
||||
/*LSTORE_0*/ Opcode.SD_M2 | Opcode.IO_LV_0,
|
||||
/*LSTORE_1*/ Opcode.SD_M2 | Opcode.IO_LV_1,
|
||||
/*LSTORE_2*/ Opcode.SD_M2 | Opcode.IO_LV_2,
|
||||
/*LSTORE_3*/ Opcode.SD_M2 | Opcode.IO_LV_3,
|
||||
/*FSTORE_0*/ Opcode.SD_M1 | Opcode.IO_LV_0,
|
||||
/*FSTORE_1*/ Opcode.SD_M1 | Opcode.IO_LV_1,
|
||||
/*FSTORE_2*/ Opcode.SD_M1 | Opcode.IO_LV_2,
|
||||
/* 70*/ /*FSTORE_3*/ Opcode.SD_M1 | Opcode.IO_LV_3,
|
||||
/*DSTORE_0*/ Opcode.SD_M2 | Opcode.IO_LV_0,
|
||||
/*DSTORE_1*/ Opcode.SD_M2 | Opcode.IO_LV_1,
|
||||
/*DSTORE_2*/ Opcode.SD_M2 | Opcode.IO_LV_2,
|
||||
/*DSTORE_3*/ Opcode.SD_M2 | Opcode.IO_LV_3,
|
||||
/*ASTORE_0*/ Opcode.SD_M1 | Opcode.IO_LV_0,
|
||||
/*ASTORE_1*/ Opcode.SD_M1 | Opcode.IO_LV_1,
|
||||
/*ASTORE_2*/ Opcode.SD_M1 | Opcode.IO_LV_2,
|
||||
/*ASTORE_3*/ Opcode.SD_M1 | Opcode.IO_LV_3,
|
||||
/*IASTORE*/ Opcode.SD_M3,
|
||||
/* 80*/ /*LASTORE*/ Opcode.SD_M4,
|
||||
/*FASTORE*/ Opcode.SD_M3,
|
||||
/*DASTORE*/ Opcode.SD_M4,
|
||||
/*AASTORE*/ Opcode.SD_M3,
|
||||
/*BASTORE*/ Opcode.SD_M3,
|
||||
/*CASTORE*/ Opcode.SD_M3,
|
||||
/*SASTORE*/ Opcode.SD_M3,
|
||||
/*POP*/ Opcode.SD_M1,
|
||||
/*POP2*/ Opcode.SD_M2,
|
||||
/*DUP*/ Opcode.SD_P1,
|
||||
/* 90*/ /*DUP_X1*/ Opcode.SD_P1,
|
||||
/*DUP_X2*/ Opcode.SD_P1,
|
||||
/*DUP2*/ Opcode.SD_P2,
|
||||
/*DUP2_X1*/ Opcode.SD_P2,
|
||||
/*DUP2_X2*/ Opcode.SD_P2,
|
||||
/*SWAP*/ Opcode.SD_P0,
|
||||
/*IADD*/ Opcode.SD_M1,
|
||||
/*LADD*/ Opcode.SD_M2,
|
||||
/*FADD*/ Opcode.SD_M1,
|
||||
/*DADD*/ Opcode.SD_M2,
|
||||
/*100*/ /*ISUB*/ Opcode.SD_M1,
|
||||
/*LSUB*/ Opcode.SD_M2,
|
||||
/*FSUB*/ Opcode.SD_M1,
|
||||
/*DSUB*/ Opcode.SD_M2,
|
||||
/*IMUL*/ Opcode.SD_M1,
|
||||
/*LMUL*/ Opcode.SD_M2,
|
||||
/*FMUL*/ Opcode.SD_M1,
|
||||
/*DMUL*/ Opcode.SD_M2,
|
||||
/*IDIV*/ Opcode.SD_M1,
|
||||
/*LDIV*/ Opcode.SD_M2,
|
||||
/*110*/ /*FDIV*/ Opcode.SD_M1,
|
||||
/*DDIV*/ Opcode.SD_M2,
|
||||
/*IREM*/ Opcode.SD_M1,
|
||||
/*LREM*/ Opcode.SD_M2,
|
||||
/*FREM*/ Opcode.SD_M1,
|
||||
/*DREM*/ Opcode.SD_M2,
|
||||
/*INEG*/ Opcode.SD_P0,
|
||||
/*LNEG*/ Opcode.SD_P0,
|
||||
/*FNEG*/ Opcode.SD_P0,
|
||||
/*DNEG*/ Opcode.SD_P0,
|
||||
/*120*/ /*ISHL*/ Opcode.SD_M1,
|
||||
/*LSHL*/ Opcode.SD_M1,
|
||||
/*ISHR*/ Opcode.SD_M1,
|
||||
/*LSHR*/ Opcode.SD_M1,
|
||||
/*IUSHR*/ Opcode.SD_M1,
|
||||
/*LUSHR*/ Opcode.SD_M1,
|
||||
/*IAND*/ Opcode.SD_M1,
|
||||
/*LAND*/ Opcode.SD_M2,
|
||||
/*IOR*/ Opcode.SD_M1,
|
||||
/*LOR*/ Opcode.SD_M2,
|
||||
/*130*/ /*IXOR*/ Opcode.SD_M1,
|
||||
/*LXOR*/ Opcode.SD_M2,
|
||||
/*IINC*/ Opcode.SD_P0 | Opcode.OP1_LV1 | Opcode.OP2_SB,
|
||||
/*I2L*/ Opcode.SD_P1,
|
||||
/*I2F*/ Opcode.SD_P0,
|
||||
/*I2D*/ Opcode.SD_P1,
|
||||
/*L2I*/ Opcode.SD_M1,
|
||||
/*L2F*/ Opcode.SD_M1,
|
||||
/*L2D*/ Opcode.SD_P0,
|
||||
/*F2I*/ Opcode.SD_P0,
|
||||
/*140*/ /*F2L*/ Opcode.SD_P1,
|
||||
/*F2D*/ Opcode.SD_P1,
|
||||
/*D2I*/ Opcode.SD_M1,
|
||||
/*D2L*/ Opcode.SD_P0,
|
||||
/*D2F*/ Opcode.SD_M1,
|
||||
/*I2B*/ Opcode.SD_P0,
|
||||
/*I2C*/ Opcode.SD_P0,
|
||||
/*I2S*/ Opcode.SD_P0,
|
||||
/*LCMP*/ Opcode.SD_M3,
|
||||
/*FCMPL*/ Opcode.SD_M1,
|
||||
/*150*/ /*FCMPG*/ Opcode.SD_M1,
|
||||
/*DCMPL*/ Opcode.SD_M3,
|
||||
/*DCMPG*/ Opcode.SD_M3,
|
||||
/*IFEQ*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IFNE*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IFLT*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IFGE*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IFGT*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IFLE*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IF_ICMPEQ*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*160*/ /*IF_ICMPNE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*IF_ICMPLT*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*IF_ICMPGE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*IF_ICMPGT*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*IF_ICMPLE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*IF_ACMPEQ*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*IF_ACMPNE*/ Opcode.SD_M2 | Opcode.OP1_BO2,
|
||||
/*GOTO*/ Opcode.SD_P0 | Opcode.OP1_BO2 | Opcode.NO_FALLTHROUGH,
|
||||
/*JSR*/ Opcode.SD_P0 | Opcode.OP1_JSR,
|
||||
/*RET*/ Opcode.SD_P0 | Opcode.OP1_LV1 | Opcode.NO_FALLTHROUGH,
|
||||
/*170*/ /*TABLESWITCH*/ Opcode.SD_M1 | Opcode.OP1_TABLESWITCH,
|
||||
/*LOOKUPSWITCH*/ Opcode.SD_M1 | Opcode.OP1_LOOKUPSWITCH,
|
||||
/*IRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
|
||||
/*LRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
|
||||
/*FRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
|
||||
/*DRETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
|
||||
/*ARETURN*/ Opcode.SD_M1 | Opcode.NO_FALLTHROUGH,
|
||||
/*RETURN*/ Opcode.SD_0 | Opcode.NO_FALLTHROUGH,
|
||||
/*GETSTATIC*/ Opcode.SD_GETSTATIC | Opcode.OP1_CP2,
|
||||
/*PUTSTATIC*/ Opcode.SD_PUTSTATIC | Opcode.OP1_CP2,
|
||||
/*180*/ /*GETFIELD*/ Opcode.SD_GETFIELD | Opcode.OP1_CP2,
|
||||
/*PUTFIELD*/ Opcode.SD_PUTFIELD | Opcode.OP1_CP2,
|
||||
/*INVOKEVIRTUAL*/ Opcode.SD_INVOKEVIRTUAL | Opcode.OP1_CP2,
|
||||
/*INVOKESPECIAL*/ Opcode.SD_INVOKESPECIAL | Opcode.OP1_CP2,
|
||||
/*INVOKESTATIC*/ Opcode.SD_INVOKESTATIC | Opcode.OP1_CP2,
|
||||
/*INVOKEINTERFACE*/ Opcode.SD_INVOKEINTERFACE | Opcode.OP1_CP2 | Opcode.OP2_SB | Opcode.OP3_SB,
|
||||
/*UNUSED*/ Opcode.INVALID_OPCODE,
|
||||
/*NEW*/ Opcode.SD_P1 | Opcode.OP1_CP2,
|
||||
/*NEWARRAY*/ Opcode.SD_P0 | Opcode.OP1_UB,
|
||||
/*ANEWARRAY*/ Opcode.SD_P0 | Opcode.OP1_CP2,
|
||||
/*190*/ /*ARRAYLENGTH*/ Opcode.SD_P0,
|
||||
/*ATHROW*/ Opcode.SD_M1 | Opcode.NO_FALLTHROUGH,
|
||||
/*CHECKCAST*/ Opcode.SD_P0 | Opcode.OP1_CP2,
|
||||
/*INSTANCEOF*/ Opcode.SD_P0 | Opcode.OP1_CP2,
|
||||
/*MONITORENTER*/ Opcode.SD_M1,
|
||||
/*MONITOREXIT*/ Opcode.SD_M1,
|
||||
/*WIDE*/ Opcode.INVALID_OPCODE,
|
||||
/*MULTIANEWARRAY*/ Opcode.SD_MULTIANEWARRAY | Opcode.OP1_CP2 | Opcode.OP2_SB,
|
||||
/*IFNULL*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*IFNONNULL*/ Opcode.SD_M1 | Opcode.OP1_BO2,
|
||||
/*200*/ /*GOTO_W*/ Opcode.SD_P0 | Opcode.OP1_BO4 | Opcode.NO_FALLTHROUGH,
|
||||
/*JSR_W*/ Opcode.SD_P1 | Opcode.OP1_BO4,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
/*210*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
/*220*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
/*230*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
/*240*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
/*250*/ Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
Opcode.INVALID_OPCODE, Opcode.INVALID_OPCODE,
|
||||
// CHECKSTYLE WrapAndIndent:ON
|
||||
};
|
||||
|
||||
/** The {@code n}th element of this array describes the properties of the JVM opcode {@code WIDE n}. */
|
||||
public static final short[] WIDE_OPCODE_PROPERTIES = new short[256];
|
||||
static {
|
||||
for (int i = 0; i < Opcode.WIDE_OPCODE_PROPERTIES.length; ++i) {
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[i] = Opcode.INVALID_OPCODE;
|
||||
}
|
||||
// load instructions
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ILOAD] = Opcode.SD_P1 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.FLOAD] = Opcode.SD_P1 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ALOAD] = Opcode.SD_P1 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.LLOAD] = Opcode.SD_P2 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.DLOAD] = Opcode.SD_P2 | Opcode.OP1_LV2;
|
||||
|
||||
// store instructions
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ISTORE] = Opcode.SD_M1 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.FSTORE] = Opcode.SD_M1 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.ASTORE] = Opcode.SD_M1 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.LSTORE] = Opcode.SD_M2 | Opcode.OP1_LV2;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.DSTORE] = Opcode.SD_M2 | Opcode.OP1_LV2;
|
||||
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.IINC] = Opcode.SD_P0 | Opcode.OP1_LV2 | Opcode.OP2_SS;
|
||||
Opcode.WIDE_OPCODE_PROPERTIES[0xff & Opcode.RET] = Opcode.SD_P0 | Opcode.OP1_LV2;
|
||||
}
|
||||
}
|
3138
src/org/codehaus/janino/Parser.java
Normal file
3138
src/org/codehaus/janino/Parser.java
Normal file
File diff suppressed because it is too large
Load Diff
384
src/org/codehaus/janino/ReflectionIClass.java
Normal file
384
src/org/codehaus/janino/ReflectionIClass.java
Normal file
|
@ -0,0 +1,384 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
|
||||
/** Wraps a {@link java.lang.Class} in an {@link org.codehaus.janino.IClass}. */
|
||||
@SuppressWarnings("rawtypes")
|
||||
class ReflectionIClass extends IClass {
|
||||
private final Class clazz;
|
||||
private final IClassLoader iClassLoader;
|
||||
|
||||
/** @param iClassLoader Required to load other {@link IClass}es on {@code get...()} */
|
||||
public
|
||||
ReflectionIClass(Class clazz, IClassLoader iClassLoader) {
|
||||
this.clazz = clazz;
|
||||
this.iClassLoader = iClassLoader;
|
||||
}
|
||||
|
||||
@Override protected IConstructor[]
|
||||
getDeclaredIConstructors2() {
|
||||
Constructor[] constructors = this.clazz.getDeclaredConstructors();
|
||||
IConstructor[] result = new IConstructor[constructors.length];
|
||||
for (int i = 0; i < constructors.length; ++i) {
|
||||
result[i] = new ReflectionIConstructor(constructors[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override protected IMethod[]
|
||||
getDeclaredIMethods2() {
|
||||
Method[] methods = this.clazz.getDeclaredMethods();
|
||||
|
||||
if (methods.length == 0 && this.clazz.isArray()) {
|
||||
return new IMethod[] { new IMethod() {
|
||||
@Override public String getName() { return "clone"; }
|
||||
@Override public IClass getReturnType() { return ReflectionIClass.this.iClassLoader.TYPE_java_lang_Object; } // SUPPRESS CHECKSTYLE LineLength
|
||||
@Override public boolean isAbstract() { return false; }
|
||||
@Override public boolean isStatic() { return false; }
|
||||
@Override public Access getAccess() { return Access.PUBLIC; }
|
||||
@Override public boolean isVarargs() { return false; }
|
||||
@Override public IClass[] getParameterTypes2() { return new IClass[0]; }
|
||||
@Override public IClass[] getThrownExceptions2() { return new IClass[0]; }
|
||||
@Override public Java.Annotation[] getAnnotations() { return new Java.Annotation[0]; }
|
||||
} };
|
||||
}
|
||||
|
||||
IMethod[] result = new IMethod[methods.length];
|
||||
for (int i = 0; i < result.length; i++) result[i] = new ReflectionIMethod(methods[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override protected IField[]
|
||||
getDeclaredIFields2() {
|
||||
Field[] fields = this.clazz.getDeclaredFields();
|
||||
IField[] result = new IField[fields.length];
|
||||
for (int i = 0; i < fields.length; ++i) {
|
||||
result[i] = new ReflectionIField(fields[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override protected IClass[]
|
||||
getDeclaredIClasses2() { return this.classesToIClasses(this.clazz.getDeclaredClasses()); }
|
||||
|
||||
@Override protected IClass
|
||||
getDeclaringIClass2() {
|
||||
Class declaringClass = this.clazz.getDeclaringClass();
|
||||
if (declaringClass == null) return null;
|
||||
return this.classToIClass(declaringClass);
|
||||
}
|
||||
|
||||
@Override protected IClass
|
||||
getOuterIClass2() throws CompileException {
|
||||
if (Modifier.isStatic(this.clazz.getModifiers())) return null;
|
||||
return this.getDeclaringIClass();
|
||||
}
|
||||
|
||||
@Override protected IClass
|
||||
getSuperclass2() {
|
||||
Class superclass = this.clazz.getSuperclass();
|
||||
return superclass == null ? null : this.classToIClass(superclass);
|
||||
}
|
||||
|
||||
@Override protected IClass[]
|
||||
getInterfaces2() {
|
||||
return this.classesToIClasses(this.clazz.getInterfaces());
|
||||
}
|
||||
|
||||
@Override protected String
|
||||
getDescriptor2() {
|
||||
return Descriptor.fromClassName(this.clazz.getName());
|
||||
}
|
||||
|
||||
@Override public Access getAccess() { return ReflectionIClass.modifiers2Access(this.clazz.getModifiers()); }
|
||||
@Override public boolean isFinal() { return Modifier.isFinal(this.clazz.getModifiers()); }
|
||||
@Override public boolean isInterface() { return this.clazz.isInterface(); }
|
||||
@Override public boolean isAbstract() { return Modifier.isAbstract(this.clazz.getModifiers()); }
|
||||
@Override public boolean isArray() { return this.clazz.isArray(); }
|
||||
|
||||
@Override protected IClass
|
||||
getComponentType2() {
|
||||
Class componentType = this.clazz.getComponentType();
|
||||
return componentType == null ? null : this.classToIClass(componentType);
|
||||
}
|
||||
|
||||
@Override public boolean
|
||||
isPrimitive() { return this.clazz.isPrimitive(); }
|
||||
|
||||
@Override public boolean
|
||||
isPrimitiveNumeric() {
|
||||
return (
|
||||
this.clazz == byte.class
|
||||
|| this.clazz == short.class
|
||||
|| this.clazz == int.class
|
||||
|| this.clazz == long.class
|
||||
|| this.clazz == char.class
|
||||
|| this.clazz == float.class
|
||||
|| this.clazz == double.class
|
||||
);
|
||||
}
|
||||
|
||||
/** @return The underlying {@link Class java.lang.Class} */
|
||||
public Class
|
||||
getClazz() { return this.clazz; }
|
||||
|
||||
/** @return E.g. "int", "int[][]", "pkg1.pkg2.Outer$Inner[]" */
|
||||
@Override public String
|
||||
toString() {
|
||||
int brackets = 0;
|
||||
Class c = this.clazz;
|
||||
while (c.isArray()) {
|
||||
++brackets;
|
||||
c = c.getComponentType();
|
||||
}
|
||||
String s = c.getName();
|
||||
while (brackets-- > 0) s += "[]";
|
||||
return s;
|
||||
}
|
||||
|
||||
private
|
||||
class ReflectionIConstructor extends IConstructor {
|
||||
|
||||
public
|
||||
ReflectionIConstructor(Constructor constructor) { this.constructor = constructor; }
|
||||
|
||||
// Implement IMember.
|
||||
@Override public Access
|
||||
getAccess() {
|
||||
int mod = this.constructor.getModifiers();
|
||||
return ReflectionIClass.modifiers2Access(mod);
|
||||
}
|
||||
|
||||
@Override public Java.Annotation[]
|
||||
getAnnotations() { return new Java.Annotation[0]; }
|
||||
|
||||
@Override public boolean
|
||||
isVarargs() {
|
||||
// TRANSIENT is identical with VARARGS.
|
||||
return Modifier.isTransient(this.constructor.getModifiers());
|
||||
}
|
||||
|
||||
// Implement "IConstructor".
|
||||
@Override public IClass[]
|
||||
getParameterTypes2() throws CompileException {
|
||||
IClass[] parameterTypes = ReflectionIClass.this.classesToIClasses(this.constructor.getParameterTypes());
|
||||
|
||||
// The JAVADOC of java.lang.reflect.Constructor does not document it, but
|
||||
// "getParameterTypes()" includes the synthetic "enclosing instance" parameter.
|
||||
IClass outerClass = ReflectionIClass.this.getOuterIClass();
|
||||
if (outerClass != null) {
|
||||
if (parameterTypes.length < 1) {
|
||||
throw new CompileException(
|
||||
"Constructor \"" + this.constructor + "\" lacks synthetic enclosing instance parameter",
|
||||
null
|
||||
);
|
||||
}
|
||||
if (parameterTypes[0] != outerClass) {
|
||||
throw new CompileException((
|
||||
"Enclosing instance parameter of constructor \""
|
||||
+ this.constructor
|
||||
+ "\" has wrong type -- \""
|
||||
+ parameterTypes[0]
|
||||
+ "\" vs. \""
|
||||
+ outerClass
|
||||
+ "\""
|
||||
), null);
|
||||
}
|
||||
IClass[] tmp = new IClass[parameterTypes.length - 1];
|
||||
System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
|
||||
parameterTypes = tmp;
|
||||
}
|
||||
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
@Override public String
|
||||
getDescriptor2() {
|
||||
Class[] parameterTypes = this.constructor.getParameterTypes();
|
||||
String[] parameterDescriptors = new String[parameterTypes.length];
|
||||
for (int i = 0; i < parameterDescriptors.length; ++i) {
|
||||
parameterDescriptors[i] = Descriptor.fromClassName(parameterTypes[i].getName());
|
||||
}
|
||||
return new MethodDescriptor(parameterDescriptors, Descriptor.VOID).toString();
|
||||
}
|
||||
|
||||
@Override public IClass[]
|
||||
getThrownExceptions2() {
|
||||
return ReflectionIClass.this.classesToIClasses(this.constructor.getExceptionTypes());
|
||||
}
|
||||
|
||||
final Constructor constructor;
|
||||
}
|
||||
public
|
||||
class ReflectionIMethod extends IMethod {
|
||||
|
||||
public
|
||||
ReflectionIMethod(Method method) { this.method = method; }
|
||||
|
||||
// Implement IMember.
|
||||
@Override public Access
|
||||
getAccess() { return ReflectionIClass.modifiers2Access(this.method.getModifiers()); }
|
||||
|
||||
@Override public Java.Annotation[]
|
||||
getAnnotations() { return new Java.Annotation[0]; }
|
||||
|
||||
// Implement "IMethod".
|
||||
@Override public String
|
||||
getName() { return this.method.getName(); }
|
||||
|
||||
@Override public boolean
|
||||
isVarargs() {
|
||||
|
||||
// VARARGS is identical with TRANSIENT.
|
||||
return Modifier.isTransient(this.method.getModifiers());
|
||||
}
|
||||
|
||||
@Override public IClass[]
|
||||
getParameterTypes2() { return ReflectionIClass.this.classesToIClasses(this.method.getParameterTypes()); }
|
||||
|
||||
@Override public boolean
|
||||
isStatic() { return Modifier.isStatic(this.method.getModifiers()); }
|
||||
|
||||
@Override public boolean
|
||||
isAbstract() { return Modifier.isAbstract(this.method.getModifiers()); }
|
||||
|
||||
@Override public IClass
|
||||
getReturnType() { return ReflectionIClass.this.classToIClass(this.method.getReturnType()); }
|
||||
|
||||
@Override public IClass[]
|
||||
getThrownExceptions2() { return ReflectionIClass.this.classesToIClasses(this.method.getExceptionTypes()); }
|
||||
|
||||
private final Method method;
|
||||
}
|
||||
|
||||
private
|
||||
class ReflectionIField extends IField {
|
||||
|
||||
public
|
||||
ReflectionIField(Field field) { this.field = field; }
|
||||
|
||||
// Implement IMember.
|
||||
@Override public Access
|
||||
getAccess() { return ReflectionIClass.modifiers2Access(this.field.getModifiers()); }
|
||||
|
||||
@Override public Java.Annotation[]
|
||||
getAnnotations() { return new Java.Annotation[0]; }
|
||||
|
||||
// Implement "IField".
|
||||
|
||||
@Override public String
|
||||
getName() { return this.field.getName(); }
|
||||
|
||||
@Override public boolean
|
||||
isStatic() { return Modifier.isStatic(this.field.getModifiers()); }
|
||||
|
||||
@Override public IClass
|
||||
getType() { return ReflectionIClass.this.classToIClass(this.field.getType()); }
|
||||
|
||||
@Override public String
|
||||
toString() {
|
||||
return Descriptor.toString(this.getDeclaringIClass().getDescriptor()) + "." + this.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation of {@link IClass.IField#getConstantValue()} is
|
||||
* not completely correct:
|
||||
* <ul>
|
||||
* <li>
|
||||
* It treats non-static fields as non-constant
|
||||
* <li>
|
||||
* Even fields with a <i>non-constant</i> initializer are identified
|
||||
* as constant. (The value of that field may be different in a
|
||||
* different JVM instance -- the classical example is
|
||||
* {@link java.io.File#separator}.)
|
||||
* </ul>
|
||||
*/
|
||||
@Override public Object
|
||||
getConstantValue() throws CompileException {
|
||||
int mod = this.field.getModifiers();
|
||||
Class clazz = this.field.getType();
|
||||
if (
|
||||
Modifier.isStatic(mod)
|
||||
&& Modifier.isFinal(mod)
|
||||
&& (clazz.isPrimitive() || clazz == String.class)
|
||||
) {
|
||||
try {
|
||||
return this.field.get(null);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new CompileException( // SUPPRESS CHECKSTYLE AvoidHidingCause
|
||||
"Field \"" + this.field.getName() + "\" is not accessible",
|
||||
(Location) null
|
||||
);
|
||||
}
|
||||
}
|
||||
return IClass.NOT_CONSTANT;
|
||||
}
|
||||
|
||||
final Field field;
|
||||
}
|
||||
|
||||
/** Loads {@link Class} through {@link IClassLoader} to ensure unique {@link IClass}es. */
|
||||
private IClass
|
||||
classToIClass(Class c) {
|
||||
IClass iClass;
|
||||
try {
|
||||
iClass = this.iClassLoader.loadIClass(Descriptor.fromClassName(c.getName()));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new JaninoRuntimeException("Loading IClass \"" + c.getName() + "\": " + ex);
|
||||
}
|
||||
if (iClass == null) {
|
||||
throw new JaninoRuntimeException("Cannot load class \"" + c.getName() + "\" through the given ClassLoader");
|
||||
}
|
||||
return iClass;
|
||||
}
|
||||
|
||||
/** @see #classToIClass(Class) */
|
||||
private IClass[]
|
||||
classesToIClasses(Class[] cs) {
|
||||
IClass[] result = new IClass[cs.length];
|
||||
for (int i = 0; i < cs.length; ++i) result[i] = this.classToIClass(cs[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Access
|
||||
modifiers2Access(int modifiers) {
|
||||
return (
|
||||
Modifier.isPrivate(modifiers) ? Access.PRIVATE :
|
||||
Modifier.isProtected(modifiers) ? Access.PROTECTED :
|
||||
Modifier.isPublic(modifiers) ? Access.PUBLIC :
|
||||
Access.DEFAULT
|
||||
);
|
||||
}
|
||||
}
|
82
src/org/codehaus/janino/ResourceFinderIClassLoader.java
Normal file
82
src/org/codehaus/janino/ResourceFinderIClassLoader.java
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.resource.Resource;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
|
||||
/**
|
||||
* This {@link org.codehaus.janino.IClassLoader} loads IClasses through a
|
||||
* a {@link org.codehaus.janino.util.resource.ResourceFinder} that designates
|
||||
* {@link org.codehaus.janino.util.ClassFile}s.
|
||||
*/
|
||||
public
|
||||
class ResourceFinderIClassLoader extends IClassLoader {
|
||||
private final ResourceFinder resourceFinder;
|
||||
|
||||
public
|
||||
ResourceFinderIClassLoader(ResourceFinder resourceFinder, IClassLoader optionalParentIClassLoader) {
|
||||
super(optionalParentIClassLoader);
|
||||
this.resourceFinder = resourceFinder;
|
||||
this.postConstruct();
|
||||
}
|
||||
|
||||
@Override protected IClass
|
||||
findIClass(String descriptor) throws ClassNotFoundException {
|
||||
String className = Descriptor.toClassName(descriptor);
|
||||
|
||||
// Find the class file resource.
|
||||
Resource classFileResource = this.resourceFinder.findResource(ClassFile.getClassFileResourceName(className));
|
||||
if (classFileResource == null) return null;
|
||||
|
||||
// Open the class file resource.
|
||||
InputStream is;
|
||||
try {
|
||||
is = classFileResource.open();
|
||||
} catch (IOException ex) {
|
||||
throw new ClassNotFoundException("Opening resource \"" + classFileResource.getFileName() + "\"", ex);
|
||||
}
|
||||
|
||||
// Load the IClass from the class file.
|
||||
ClassFile cf;
|
||||
try {
|
||||
cf = new ClassFile(is);
|
||||
} catch (IOException e) {
|
||||
throw new ClassNotFoundException("Reading resource \"" + classFileResource.getFileName() + "\"", e);
|
||||
} finally {
|
||||
try { is.close(); } catch (IOException e) {}
|
||||
}
|
||||
IClass iClass = new ClassFileIClass(cf, this);
|
||||
this.defineIClass(iClass);
|
||||
return iClass;
|
||||
}
|
||||
}
|
1026
src/org/codehaus/janino/Scanner.java
Normal file
1026
src/org/codehaus/janino/Scanner.java
Normal file
File diff suppressed because it is too large
Load Diff
993
src/org/codehaus/janino/ScriptEvaluator.java
Normal file
993
src/org/codehaus/janino/ScriptEvaluator.java
Normal file
|
@ -0,0 +1,993 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.Cookable;
|
||||
import org.codehaus.commons.compiler.IExpressionEvaluator;
|
||||
import org.codehaus.commons.compiler.IScriptEvaluator;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
import org.codehaus.janino.Java.VariableDeclarator;
|
||||
import org.codehaus.janino.util.Traverser;
|
||||
|
||||
/** A number of "convenience constructors" exist that execute the setup steps instantly. Their use is discouraged. */
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class ScriptEvaluator extends ClassBodyEvaluator implements IScriptEvaluator {
|
||||
|
||||
/** Whether methods override a method declared by a supertype; {@code null} means "none". */
|
||||
protected boolean[] optionalOverrideMethod;
|
||||
|
||||
/** Whether methods are static; {@code null} means "all". */
|
||||
protected boolean[] optionalStaticMethod;
|
||||
|
||||
/** The methods' return types; {@code null} means "none". */
|
||||
protected Class[] optionalReturnTypes;
|
||||
|
||||
private String[] optionalMethodNames;
|
||||
private String[][] optionalParameterNames;
|
||||
private Class[][] optionalParameterTypes;
|
||||
private Class[][] optionalThrownExceptions;
|
||||
|
||||
private Method[] result; // null=uncooked
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.cook(script);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(String script) throws CompileException {
|
||||
this.cook(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setReturnType(returnType);
|
||||
* se.cook(script);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see #setReturnType(Class)
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(String script, Class returnType) throws CompileException {
|
||||
this.setReturnType(returnType);
|
||||
this.cook(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setReturnType(returnType);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.cook(script);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(String script, Class returnType, String[] parameterNames, Class[] parameterTypes)
|
||||
throws CompileException {
|
||||
this.setReturnType(returnType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.cook(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setReturnType(returnType);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.setThrownExceptions(thrownExceptions);
|
||||
* se.cook(script);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see #setThrownExceptions(Class[])
|
||||
* @see Cookable#cook(String)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(
|
||||
String script,
|
||||
Class returnType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions
|
||||
) throws CompileException {
|
||||
this.setReturnType(returnType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.cook(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setReturnType(returnType);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.setThrownExceptions(thrownExceptions);
|
||||
* se.setParentClassLoader(optionalParentClassLoader);
|
||||
* se.cook(optionalFileName, is);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see #setThrownExceptions(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(String, InputStream)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(
|
||||
String optionalFileName,
|
||||
InputStream is,
|
||||
Class returnType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
|
||||
) throws CompileException, IOException {
|
||||
this.setReturnType(returnType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(optionalFileName, is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setReturnType(returnType);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.setThrownExceptions(thrownExceptions);
|
||||
* se.setParentClassLoader(optionalParentClassLoader);
|
||||
* se.cook(reader);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see #setThrownExceptions(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(String, Reader)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(
|
||||
String optionalFileName,
|
||||
Reader reader,
|
||||
Class returnType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
|
||||
) throws CompileException, IOException {
|
||||
this.setReturnType(returnType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(optionalFileName, reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setReturnType(returnType);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.setThrownExceptions(thrownExceptions);
|
||||
* se.setParentClassLoader(optionalParentClassLoader);
|
||||
* se.cook(scanner);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see #setThrownExceptions(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(Reader)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(
|
||||
Scanner scanner,
|
||||
Class returnType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
|
||||
) throws CompileException, IOException {
|
||||
this.setReturnType(returnType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(scanner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setExtendedType(optionalExtendedType);
|
||||
* se.setImplementedTypes(implementedTypes);
|
||||
* se.setReturnType(returnType);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.setThrownExceptions(thrownExceptions);
|
||||
* se.setParentClassLoader(optionalParentClassLoader);
|
||||
* se.cook(scanner);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see ClassBodyEvaluator#setExtendedClass(Class)
|
||||
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see #setThrownExceptions(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(Reader)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(
|
||||
Scanner scanner,
|
||||
Class optionalExtendedType,
|
||||
Class[] implementedTypes,
|
||||
Class returnType,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
|
||||
) throws CompileException, IOException {
|
||||
this.setExtendedClass(optionalExtendedType);
|
||||
this.setImplementedInterfaces(implementedTypes);
|
||||
this.setReturnType(returnType);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(scanner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* ScriptEvaluator se = new ScriptEvaluator();
|
||||
* se.setClassName(className);
|
||||
* se.setExtendedType(optionalExtendedType);
|
||||
* se.setImplementedTypes(implementedTypes);
|
||||
* se.setStaticMethod(staticMethod);
|
||||
* se.setReturnType(returnType);
|
||||
* se.setMethodName(methodName);
|
||||
* se.setParameters(parameterNames, parameterTypes);
|
||||
* se.setThrownExceptions(thrownExceptions);
|
||||
* se.setParentClassLoader(optionalParentClassLoader);
|
||||
* se.cook(scanner);</pre>
|
||||
*
|
||||
* @see #ScriptEvaluator()
|
||||
* @see ClassBodyEvaluator#setClassName(String)
|
||||
* @see ClassBodyEvaluator#setExtendedClass(Class)
|
||||
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
|
||||
* @see #setStaticMethod(boolean)
|
||||
* @see #setReturnType(Class)
|
||||
* @see #setMethodName(String)
|
||||
* @see #setParameters(String[], Class[])
|
||||
* @see #setThrownExceptions(Class[])
|
||||
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(Reader)
|
||||
*/
|
||||
public
|
||||
ScriptEvaluator(
|
||||
Scanner scanner,
|
||||
String className,
|
||||
Class optionalExtendedType,
|
||||
Class[] implementedTypes,
|
||||
boolean staticMethod,
|
||||
Class returnType,
|
||||
String methodName,
|
||||
String[] parameterNames,
|
||||
Class[] parameterTypes,
|
||||
Class[] thrownExceptions,
|
||||
ClassLoader optionalParentClassLoader // null = use current thread's context class loader
|
||||
) throws CompileException, IOException {
|
||||
this.setClassName(className);
|
||||
this.setExtendedClass(optionalExtendedType);
|
||||
this.setImplementedInterfaces(implementedTypes);
|
||||
this.setStaticMethod(staticMethod);
|
||||
this.setReturnType(returnType);
|
||||
this.setMethodName(methodName);
|
||||
this.setParameters(parameterNames, parameterTypes);
|
||||
this.setThrownExceptions(thrownExceptions);
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(scanner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a script evaluator with all the default settings (return type {@code void}
|
||||
*/
|
||||
public ScriptEvaluator() {}
|
||||
|
||||
@Override public void
|
||||
setOverrideMethod(boolean overrideMethod) {
|
||||
this.setOverrideMethod(new boolean[] { overrideMethod });
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setStaticMethod(boolean staticMethod) {
|
||||
this.setStaticMethod(new boolean[] { staticMethod });
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the return types of the generated methods.
|
||||
*
|
||||
* @param returnType The method's return type; {@code null} means the "default return type", which is the type
|
||||
* returned by {@link #getDefaultReturnType()} ({@code void.class} for {@link ScriptEvaluator}
|
||||
* and {@code Object.class} for {@link ExpressionEvaluator})
|
||||
* @see ScriptEvaluator#getDefaultReturnType()
|
||||
* @see ExpressionEvaluator#getDefaultReturnType()
|
||||
*/
|
||||
@Override public void
|
||||
setReturnType(Class returnType) {
|
||||
this.setReturnTypes(new Class[] { returnType });
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setMethodName(String methodName) {
|
||||
this.setMethodNames(new String[] { methodName });
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setParameters(String[] parameterNames, Class[] parameterTypes) {
|
||||
this.setParameters(new String[][] { parameterNames }, new Class[][] { parameterTypes });
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setThrownExceptions(Class[] thrownExceptions) {
|
||||
this.setThrownExceptions(new Class[][] { thrownExceptions });
|
||||
}
|
||||
|
||||
@Override public final void
|
||||
cook(Scanner scanner) throws CompileException, IOException {
|
||||
this.cook(new Scanner[] { scanner });
|
||||
}
|
||||
|
||||
@Override public Object
|
||||
evaluate(Object[] arguments) throws InvocationTargetException {
|
||||
return this.evaluate(0, arguments);
|
||||
}
|
||||
|
||||
@Override public Method
|
||||
getMethod() { return this.getMethod(0); }
|
||||
|
||||
@Override public void
|
||||
setOverrideMethod(boolean[] overrideMethod) {
|
||||
this.assertNotCooked();
|
||||
this.optionalOverrideMethod = overrideMethod.clone();
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setStaticMethod(boolean[] staticMethod) {
|
||||
this.assertNotCooked();
|
||||
this.optionalStaticMethod = staticMethod.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the return types of the generated methods.
|
||||
*
|
||||
* @param returnTypes The methods' return types; {@code null} elements mean the "default return type", which is the
|
||||
* type returned by {@link #getDefaultReturnType()} ({@code void.class} for {@link
|
||||
* ScriptEvaluator} and {@code Object.class} for {@link ExpressionEvaluator})
|
||||
* @see ScriptEvaluator#getDefaultReturnType()
|
||||
* @see ExpressionEvaluator#getDefaultReturnType()
|
||||
*/
|
||||
@Override public void
|
||||
setReturnTypes(Class[] returnTypes) {
|
||||
this.assertNotCooked();
|
||||
this.optionalReturnTypes = returnTypes.clone();
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setMethodNames(String[] methodNames) {
|
||||
this.assertNotCooked();
|
||||
this.optionalMethodNames = methodNames.clone();
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setParameters(String[][] parameterNames, Class[][] parameterTypes) {
|
||||
this.assertNotCooked();
|
||||
this.optionalParameterNames = parameterNames.clone();
|
||||
this.optionalParameterTypes = parameterTypes.clone();
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setThrownExceptions(Class[][] thrownExceptions) {
|
||||
this.assertNotCooked();
|
||||
this.optionalThrownExceptions = thrownExceptions.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #cook(Scanner)}, but cooks a <i>set</i> of scripts into one class. Notice that
|
||||
* if <i>any</i> of the scripts causes trouble, the entire compilation will fail. If you
|
||||
* need to report <i>which</i> of the scripts causes the exception, you may want to use the
|
||||
* <code>optionalFileName</code> argument of {@link Scanner#Scanner(String, Reader)} to
|
||||
* distinguish between the individual token sources.
|
||||
* <p>
|
||||
* On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling
|
||||
* 10000 expressions "a + b" (integer) takes about 4 seconds and 56 MB of main memory.
|
||||
* The generated class file is 639203 bytes large.
|
||||
* <p>
|
||||
* The number and the complexity of the scripts is restricted by the
|
||||
* <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88659">Limitations
|
||||
* of the Java Virtual Machine</a>, where the most limiting factor is the 64K entries limit
|
||||
* of the constant pool. Since every method with a distinct name requires one entry there,
|
||||
* you can define at best 32K (very simple) scripts.
|
||||
*
|
||||
* If and only if the number of scanners is one, then that single script may contain leading
|
||||
* IMPORT directives.
|
||||
*
|
||||
* @throws IllegalStateException Any of the preceeding <code>set...()</code> had an array size different from that
|
||||
* of <code>scanners</code>
|
||||
*/
|
||||
public final void
|
||||
cook(Scanner[] scanners) throws CompileException, IOException {
|
||||
if (scanners == null) throw new NullPointerException();
|
||||
|
||||
Parser[] parsers = new Parser[scanners.length];
|
||||
for (int i = 0; i < scanners.length; ++i) {
|
||||
parsers[i] = new Parser(scanners[i]);
|
||||
}
|
||||
this.cook(parsers);
|
||||
}
|
||||
|
||||
/** @see #cook(Scanner[]) */
|
||||
public final void
|
||||
cook(Parser[] parsers) throws CompileException, IOException {
|
||||
|
||||
// The "dimension" of this ScriptEvaluator, i.e. how many scripts are cooked at the same
|
||||
// time.
|
||||
int count = parsers.length;
|
||||
|
||||
// Check array sizes.
|
||||
if (this.optionalMethodNames != null && this.optionalMethodNames.length != count) {
|
||||
throw new IllegalStateException("methodName count");
|
||||
}
|
||||
if (this.optionalParameterNames != null && this.optionalParameterNames.length != count) {
|
||||
throw new IllegalStateException("parameterNames count");
|
||||
}
|
||||
if (this.optionalParameterTypes != null && this.optionalParameterTypes.length != count) {
|
||||
throw new IllegalStateException("parameterTypes count");
|
||||
}
|
||||
if (this.optionalOverrideMethod != null && this.optionalOverrideMethod.length != count) {
|
||||
throw new IllegalStateException("overrideMethod count");
|
||||
}
|
||||
if (this.optionalReturnTypes != null && this.optionalReturnTypes.length != count) {
|
||||
throw new IllegalStateException("returnTypes count");
|
||||
}
|
||||
if (this.optionalStaticMethod != null && this.optionalStaticMethod.length != count) {
|
||||
throw new IllegalStateException("staticMethod count");
|
||||
}
|
||||
if (this.optionalThrownExceptions != null && this.optionalThrownExceptions.length != count) {
|
||||
throw new IllegalStateException("thrownExceptions count");
|
||||
}
|
||||
|
||||
// Create compilation unit.
|
||||
Java.CompilationUnit compilationUnit = this.makeCompilationUnit(count == 1 ? parsers[0] : null);
|
||||
|
||||
// Create class declaration.
|
||||
Java.ClassDeclaration cd = this.addPackageMemberClassDeclaration(parsers[0].location(), compilationUnit);
|
||||
|
||||
// Determine method names.
|
||||
String[] methodNames;
|
||||
if (this.optionalMethodNames == null) {
|
||||
methodNames = new String[count];
|
||||
for (int i = 0; i < count; ++i) methodNames[i] = "eval" + i;
|
||||
} else
|
||||
{
|
||||
methodNames = this.optionalMethodNames;
|
||||
}
|
||||
|
||||
// Create methods with one block each.
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Parser parser = parsers[i];
|
||||
|
||||
List<Java.BlockStatement> statements = this.makeStatements(i, parser);
|
||||
|
||||
// Determine the following script properties AFTER the call to "makeBlock()",
|
||||
// because "makeBlock()" may modify these script properties on-the-fly.
|
||||
boolean staticMethod = this.optionalStaticMethod == null || this.optionalStaticMethod[i];
|
||||
boolean overrideMethod = this.optionalOverrideMethod != null && this.optionalOverrideMethod[i];
|
||||
|
||||
Class returnType = (
|
||||
this.optionalReturnTypes == null
|
||||
? this.getDefaultReturnType()
|
||||
: this.optionalReturnTypes[i]
|
||||
);
|
||||
String[] parameterNames = (
|
||||
this.optionalParameterNames == null
|
||||
? new String[0]
|
||||
: this.optionalParameterNames[i]
|
||||
);
|
||||
Class[] parameterTypes = (
|
||||
this.optionalParameterTypes == null
|
||||
? new Class[0]
|
||||
: this.optionalParameterTypes[i]
|
||||
);
|
||||
Class[] thrownExceptions = (
|
||||
this.optionalThrownExceptions == null
|
||||
? new Class[0]
|
||||
: this.optionalThrownExceptions[i]
|
||||
);
|
||||
|
||||
// If the method is non-static, assume that it overrides a method in a supertype.
|
||||
Location loc = parser.location();
|
||||
cd.addDeclaredMethod(this.makeMethodDeclaration(
|
||||
loc, // location
|
||||
( // annotations
|
||||
overrideMethod
|
||||
? new Java.Annotation[] { new Java.MarkerAnnotation(this.classToType(loc, Override.class)) }
|
||||
: new Java.Annotation[0]
|
||||
),
|
||||
staticMethod, // staticMethod
|
||||
returnType, // returnType
|
||||
methodNames[i], // methodName
|
||||
parameterTypes, // parameterTypes
|
||||
parameterNames, // parameterNames
|
||||
thrownExceptions, // thrownExceptions
|
||||
statements // statements
|
||||
));
|
||||
}
|
||||
|
||||
// Compile and load the compilation unit.
|
||||
Class c = this.compileToClass(compilationUnit);
|
||||
|
||||
// Find the script methods by name.
|
||||
this.result = new Method[count];
|
||||
if (count <= 10) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
try {
|
||||
this.result[i] = c.getDeclaredMethod(
|
||||
methodNames[i],
|
||||
this.optionalParameterTypes == null ? new Class[0] : this.optionalParameterTypes[i]
|
||||
);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new JaninoRuntimeException((
|
||||
"SNO: Loaded class does not declare method \""
|
||||
+ methodNames[i]
|
||||
+ "\""
|
||||
), ex);
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
class MethodWrapper {
|
||||
|
||||
private final String name;
|
||||
private final Class[] parameterTypes;
|
||||
|
||||
MethodWrapper(String name, Class[] parameterTypes) {
|
||||
this.name = name;
|
||||
this.parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
@Override public boolean
|
||||
equals(Object o) {
|
||||
if (!(o instanceof MethodWrapper)) return false;
|
||||
MethodWrapper that = (MethodWrapper) o;
|
||||
if (!this.name.equals(that.name)) return false;
|
||||
int cnt = this.parameterTypes.length;
|
||||
if (cnt != that.parameterTypes.length) return false;
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
if (!this.parameterTypes[i].equals(that.parameterTypes[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public int
|
||||
hashCode() {
|
||||
int hc = this.name.hashCode();
|
||||
for (Class parameterType : this.parameterTypes) hc ^= parameterType.hashCode();
|
||||
return hc;
|
||||
}
|
||||
}
|
||||
Method[] ma = c.getDeclaredMethods();
|
||||
Map<MethodWrapper, Method> dms = new HashMap(2 * count);
|
||||
for (Method m : ma) dms.put(new MethodWrapper(m.getName(), m.getParameterTypes()), m);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Method m = (Method) dms.get(new MethodWrapper(
|
||||
methodNames[i],
|
||||
this.optionalParameterTypes == null ? new Class[0] : this.optionalParameterTypes[i]
|
||||
));
|
||||
if (m == null) {
|
||||
throw new JaninoRuntimeException(
|
||||
"SNO: Loaded class does not declare method \""
|
||||
+ methodNames[i]
|
||||
+ "\""
|
||||
);
|
||||
}
|
||||
this.result[i] = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public final void
|
||||
cook(Reader[] readers) throws CompileException, IOException {
|
||||
this.cook(new String[readers.length], readers);
|
||||
}
|
||||
|
||||
/**
|
||||
* On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling
|
||||
* 10000 expressions "a + b" (integer) takes about 4 seconds and 56 MB of main memory.
|
||||
* The generated class file is 639203 bytes large.
|
||||
* <p>
|
||||
* The number and the complexity of the scripts is restricted by the
|
||||
* <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88659">Limitations
|
||||
* of the Java Virtual Machine</a>, where the most limiting factor is the 64K entries limit
|
||||
* of the constant pool. Since every method with a distinct name requires one entry there,
|
||||
* you can define at best 32K (very simple) scripts.
|
||||
*/
|
||||
@Override public final void
|
||||
cook(String[] optionalFileNames, Reader[] readers) throws CompileException, IOException {
|
||||
Scanner[] scanners = new Scanner[readers.length];
|
||||
for (int i = 0; i < readers.length; ++i) {
|
||||
scanners[i] = new Scanner(optionalFileNames == null ? null : optionalFileNames[i], readers[i]);
|
||||
}
|
||||
this.cook(scanners);
|
||||
}
|
||||
|
||||
@Override public final void
|
||||
cook(String[] strings) throws CompileException { this.cook(null, strings); }
|
||||
|
||||
@Override public final void
|
||||
cook(String[] optionalFileNames, String[] strings) throws CompileException {
|
||||
Reader[] readers = new Reader[strings.length];
|
||||
for (int i = 0; i < strings.length; ++i) readers[i] = new StringReader(strings[i]);
|
||||
try {
|
||||
this.cook(optionalFileNames, readers);
|
||||
} catch (IOException ex) {
|
||||
throw new JaninoRuntimeException("SNO: IOException despite StringReader", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code void.class}
|
||||
* @see #setReturnTypes(Class[])
|
||||
*/
|
||||
protected Class
|
||||
getDefaultReturnType() { return void.class; }
|
||||
|
||||
/** Fills the given <code>block</code> by parsing statements until EOF and adding them to the block. */
|
||||
protected List<Java.BlockStatement>
|
||||
makeStatements(int idx, Parser parser) throws CompileException, IOException {
|
||||
List<Java.BlockStatement> statements = new ArrayList();
|
||||
while (!parser.peekEof()) {
|
||||
statements.add(parser.parseBlockStatement());
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* To the given {@link Java.ClassDeclaration}, add
|
||||
* <ul>
|
||||
* <li>A public method declaration with the given return type, name, parameter
|
||||
* names and values and thrown exceptions
|
||||
* <li>A block
|
||||
* </ul>
|
||||
*
|
||||
* @param returnType Return type of the declared method
|
||||
*/
|
||||
protected Java.MethodDeclarator
|
||||
makeMethodDeclaration(
|
||||
Location location,
|
||||
Java.Annotation[] annotations,
|
||||
boolean staticMethod,
|
||||
Class returnType,
|
||||
String methodName,
|
||||
Class[] parameterTypes,
|
||||
String[] parameterNames,
|
||||
Class[] thrownExceptions,
|
||||
List<Java.BlockStatement> statements
|
||||
) {
|
||||
if (parameterNames.length != parameterTypes.length) {
|
||||
throw new JaninoRuntimeException(
|
||||
"Lengths of \"parameterNames\" ("
|
||||
+ parameterNames.length
|
||||
+ ") and \"parameterTypes\" ("
|
||||
+ parameterTypes.length
|
||||
+ ") do not match"
|
||||
);
|
||||
}
|
||||
|
||||
Java.FunctionDeclarator.FormalParameters fps = new Java.FunctionDeclarator.FormalParameters(
|
||||
location,
|
||||
new Java.FunctionDeclarator.FormalParameter[parameterNames.length],
|
||||
false
|
||||
);
|
||||
|
||||
for (int i = 0; i < fps.parameters.length; ++i) {
|
||||
fps.parameters[i] = new Java.FunctionDeclarator.FormalParameter(
|
||||
location, // location
|
||||
true, // finaL
|
||||
this.classToType(location, parameterTypes[i]), // type
|
||||
parameterNames[i] // name
|
||||
);
|
||||
}
|
||||
|
||||
return new Java.MethodDeclarator(
|
||||
location, // location
|
||||
null, // optionalDocComment
|
||||
new Java.Modifiers( // modifiers
|
||||
staticMethod ? (short) (Mod.PUBLIC | Mod.STATIC) : (short) Mod.PUBLIC,
|
||||
annotations
|
||||
),
|
||||
this.classToType(location, returnType), // type
|
||||
methodName, // name
|
||||
fps, // formalParameters
|
||||
this.classesToTypes(location, thrownExceptions), // thrownExceptions
|
||||
statements // optionalStatements
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createFastScriptEvaluator(Scanner, String[], String, Class, Class, String[],
|
||||
* ClassLoader)} instead
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastScriptEvaluator(String script, Class interfaceToImplement, String[] parameterNames)
|
||||
throws CompileException {
|
||||
ScriptEvaluator se = new ScriptEvaluator();
|
||||
return se.createFastEvaluator(script, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createFastScriptEvaluator(Scanner, String[], String, Class, Class, String[],
|
||||
* ClassLoader)} instead
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastScriptEvaluator(
|
||||
Scanner scanner,
|
||||
Class interfaceToImplement,
|
||||
String[] parameterNames,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException, IOException {
|
||||
ScriptEvaluator se = new ScriptEvaluator();
|
||||
se.setParentClassLoader(optionalParentClassLoader);
|
||||
return se.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createFastScriptEvaluator(Scanner, String[], String, Class, Class, String[],
|
||||
* ClassLoader)} instead
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastScriptEvaluator(
|
||||
Scanner scanner,
|
||||
String className,
|
||||
Class optionalExtendedType,
|
||||
Class interfaceToImplement,
|
||||
String[] parameterNames,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException, IOException {
|
||||
ScriptEvaluator se = new ScriptEvaluator();
|
||||
se.setClassName(className);
|
||||
se.setExtendedClass(optionalExtendedType);
|
||||
se.setParentClassLoader(optionalParentClassLoader);
|
||||
return se.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* {@link ScriptEvaluator} se = new {@link ScriptEvaluator#ScriptEvaluator() ScriptEvaluator}();
|
||||
* se.{@link #setDefaultImports(String[]) setDefaultImports}.(optionalDefaultImports);
|
||||
* se.{@link #setClassName(String) setClassName}.(className);
|
||||
* se.{@link #setExtendedClass(Class) setExtendedClass}.(optionalExtendedClass);
|
||||
* se.{@link #setParentClassLoader(ClassLoader) setParentClassLoader}(optionalParentClassLoader);
|
||||
* return se.{@link #createFastEvaluator(Scanner, Class, String[]) createFastEvaluator}(scanner,
|
||||
* interfaceToImplement, parameterNames);
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated Use {@link #createFastEvaluator(Scanner,Class,String[])} instead:
|
||||
*/
|
||||
@Deprecated public static Object
|
||||
createFastScriptEvaluator(
|
||||
Scanner scanner,
|
||||
String[] optionalDefaultImports,
|
||||
String className,
|
||||
Class optionalExtendedClass,
|
||||
Class interfaceToImplement,
|
||||
String[] parameterNames,
|
||||
ClassLoader optionalParentClassLoader
|
||||
) throws CompileException, IOException {
|
||||
ScriptEvaluator se = new ScriptEvaluator();
|
||||
se.setDefaultImports(optionalDefaultImports);
|
||||
se.setClassName(className);
|
||||
se.setExtendedClass(optionalExtendedClass);
|
||||
se.setParentClassLoader(optionalParentClassLoader);
|
||||
return se.createFastEvaluator(scanner, interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
/** Don't use. */
|
||||
@Override public final Object
|
||||
createInstance(Reader reader) {
|
||||
throw new UnsupportedOperationException("createInstance");
|
||||
}
|
||||
|
||||
@Override public Object
|
||||
createFastEvaluator(Reader reader, Class interfaceToImplement, String[] parameterNames)
|
||||
throws CompileException, IOException {
|
||||
return this.createFastEvaluator(new Scanner(null, reader), interfaceToImplement, parameterNames);
|
||||
}
|
||||
|
||||
@Override public Object
|
||||
createFastEvaluator(String script, Class interfaceToImplement, String[] parameterNames) throws CompileException {
|
||||
try {
|
||||
return this.createFastEvaluator(
|
||||
new StringReader(script),
|
||||
interfaceToImplement,
|
||||
parameterNames
|
||||
);
|
||||
} catch (IOException ex) {
|
||||
throw new JaninoRuntimeException("IOException despite StringReader", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice: This method is not declared in {@link IScriptEvaluator}, and is hence only available in <i>this</i>
|
||||
* implementation of <code>org.codehaus.commons.compiler</code>. To be independent from this particular
|
||||
* implementation, try to switch to {@link #createFastEvaluator(Reader, Class, String[])}.
|
||||
*
|
||||
* @param scanner Source of tokens to read
|
||||
* @see #createFastEvaluator(Reader, Class, String[])
|
||||
*/
|
||||
public Object
|
||||
createFastEvaluator(Scanner scanner, Class interfaceToImplement, String[] parameterNames)
|
||||
throws CompileException, IOException {
|
||||
if (!interfaceToImplement.isInterface()) {
|
||||
throw new JaninoRuntimeException("\"" + interfaceToImplement + "\" is not an interface");
|
||||
}
|
||||
|
||||
Method methodToImplement;
|
||||
{
|
||||
Method[] methods = interfaceToImplement.getDeclaredMethods();
|
||||
if (methods.length != 1) {
|
||||
throw new JaninoRuntimeException(
|
||||
"Interface \""
|
||||
+ interfaceToImplement
|
||||
+ "\" must declare exactly one method"
|
||||
);
|
||||
}
|
||||
methodToImplement = methods[0];
|
||||
}
|
||||
|
||||
this.setImplementedInterfaces(new Class[] { interfaceToImplement });
|
||||
this.setOverrideMethod(true);
|
||||
this.setStaticMethod(false);
|
||||
if (this instanceof IExpressionEvaluator) {
|
||||
|
||||
// Must not call "IExpressionEvaluator.setReturnType()".
|
||||
((IExpressionEvaluator) this).setExpressionType(methodToImplement.getReturnType());
|
||||
} else {
|
||||
this.setReturnType(methodToImplement.getReturnType());
|
||||
}
|
||||
this.setMethodName(methodToImplement.getName());
|
||||
this.setParameters(parameterNames, methodToImplement.getParameterTypes());
|
||||
this.setThrownExceptions(methodToImplement.getExceptionTypes());
|
||||
this.cook(scanner);
|
||||
Class c = this.getMethod().getDeclaringClass();
|
||||
try {
|
||||
return c.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
// SNO - Declared class is always non-abstract.
|
||||
throw new JaninoRuntimeException(e.toString(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
// SNO - interface methods are always PUBLIC.
|
||||
throw new JaninoRuntimeException(e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess the names of the parameters used in the given expression. The strategy is to look
|
||||
* at all "ambiguous names" in the expression (e.g. in "a.b.c.d()", the ambiguous name
|
||||
* is "a.b.c"), and then at the components of the ambiguous name.
|
||||
* <ul>
|
||||
* <li>If any component starts with an upper-case letter, then ambiguous name is assumed to
|
||||
* be a type name.
|
||||
* <li>Otherwise, if the first component of the ambiguous name matches the name of a
|
||||
* previously defined local variable, then the first component of the ambiguous name is
|
||||
* assumed to be a local variable name. (Notice that this strategy does not consider that
|
||||
* the scope of a local variable declaration may end before the end of the script.)
|
||||
* <li>Otherwise, the first component of the ambiguous name is assumed to be a parameter name.
|
||||
* </ul>
|
||||
*
|
||||
* @see Scanner#Scanner(String, Reader)
|
||||
*/
|
||||
public static String[]
|
||||
guessParameterNames(Scanner scanner) throws CompileException, IOException {
|
||||
Parser parser = new Parser(scanner);
|
||||
|
||||
// Eat optional leading import declarations.
|
||||
while (parser.peek("import")) parser.parseImportDeclaration();
|
||||
|
||||
// Parse the script statements into a block.
|
||||
Java.Block block = new Java.Block(scanner.location());
|
||||
while (!parser.peekEof()) block.addStatement(parser.parseBlockStatement());
|
||||
|
||||
// Traverse the block for ambiguous names and guess which of them are parameter names.
|
||||
final Set<String> localVariableNames = new HashSet();
|
||||
final Set<String> parameterNames = new HashSet();
|
||||
new Traverser() {
|
||||
|
||||
@Override public void
|
||||
traverseLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
|
||||
for (VariableDeclarator vd : lvds.variableDeclarators) localVariableNames.add(vd.name);
|
||||
super.traverseLocalVariableDeclarationStatement(lvds);
|
||||
}
|
||||
|
||||
@Override public void
|
||||
traverseAmbiguousName(Java.AmbiguousName an) {
|
||||
|
||||
// If any of the components starts with an upper-case letter, then the ambiguous
|
||||
// name is most probably a type name, e.g. "System.out" or "java.lang.System.out".
|
||||
for (int i = 0; i < an.identifiers.length; ++i) {
|
||||
if (Character.isUpperCase(an.identifiers[i].charAt(0))) return;
|
||||
}
|
||||
|
||||
// Is it a local variable's name?
|
||||
if (localVariableNames.contains(an.identifiers[0])) return;
|
||||
|
||||
// It's most probably a parameter name (although it could be a field name as well).
|
||||
parameterNames.add(an.identifiers[0]);
|
||||
}
|
||||
}.traverseBlock(block);
|
||||
|
||||
return (String[]) parameterNames.toArray(new String[parameterNames.size()]);
|
||||
}
|
||||
|
||||
@Override public Object
|
||||
evaluate(int idx, Object[] arguments) throws InvocationTargetException {
|
||||
if (this.result == null) throw new IllegalStateException("Must only be called after \"cook()\"");
|
||||
try {
|
||||
return this.result[idx].invoke(null, arguments);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new JaninoRuntimeException(ex.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Method
|
||||
getMethod(int idx) {
|
||||
if (this.result == null) throw new IllegalStateException("Must only be called after \"cook()\"");
|
||||
return this.result[idx];
|
||||
}
|
||||
}
|
425
src/org/codehaus/janino/SimpleCompiler.java
Normal file
425
src/org/codehaus/janino/SimpleCompiler.java
Normal file
|
@ -0,0 +1,425 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.Cookable;
|
||||
import org.codehaus.commons.compiler.ErrorHandler;
|
||||
import org.codehaus.commons.compiler.ICookable;
|
||||
import org.codehaus.commons.compiler.ISimpleCompiler;
|
||||
import org.codehaus.commons.compiler.Location;
|
||||
import org.codehaus.commons.compiler.WarningHandler;
|
||||
import org.codehaus.janino.Java.Type;
|
||||
import org.codehaus.janino.Visitor.AtomVisitor;
|
||||
import org.codehaus.janino.Visitor.TypeVisitor;
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
|
||||
/**
|
||||
* To set up a {@link SimpleCompiler} object, proceed as described for {@link ISimpleCompiler}.
|
||||
* Alternatively, a number of "convenience constructors" exist that execute the described steps
|
||||
* instantly.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class SimpleCompiler extends Cookable implements ISimpleCompiler {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
// Set when "cook()"ing.
|
||||
private ClassLoaderIClassLoader classLoaderIClassLoader;
|
||||
|
||||
private ClassLoader result;
|
||||
private ErrorHandler optionalCompileErrorHandler;
|
||||
private WarningHandler optionalWarningHandler;
|
||||
|
||||
private boolean debugSource = Boolean.getBoolean(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_ENABLE);
|
||||
private boolean debugLines = this.debugSource;
|
||||
private boolean debugVars = this.debugSource;
|
||||
|
||||
public static void // SUPPRESS CHECKSTYLE JavadocMethod
|
||||
main(String[] args) throws Exception {
|
||||
if (args.length >= 1 && "-help".equals(args[0])) {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" org.codehaus.janino.SimpleCompiler <source-file> <class-name> { <argument> }");
|
||||
System.out.println("Reads a compilation unit from the given <source-file> and invokes method");
|
||||
System.out.println("\"public static void main(String[])\" of class <class-name>, passing the");
|
||||
System.out.println("given <argument>s.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
System.err.println("Source file and/or class name missing; try \"-help\".");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Get source file.
|
||||
String sourceFileName = args[0];
|
||||
|
||||
// Get class name.
|
||||
String className = args[1];
|
||||
|
||||
// Get arguments.
|
||||
String[] arguments = new String[args.length - 2];
|
||||
System.arraycopy(args, 2, arguments, 0, arguments.length);
|
||||
|
||||
// Compile the source file.
|
||||
ClassLoader cl = new SimpleCompiler(sourceFileName, new FileInputStream(sourceFileName)).getClassLoader();
|
||||
|
||||
// Load the class.
|
||||
Class c = cl.loadClass(className);
|
||||
|
||||
// Invoke the "public static main(String[])" method.
|
||||
Method m = c.getMethod("main", new Class[] { String[].class });
|
||||
m.invoke(null, new Object[] { arguments });
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* SimpleCompiler sc = new SimpleCompiler();
|
||||
* sc.cook(optionalFileName, in);</pre>
|
||||
*
|
||||
* @see #SimpleCompiler()
|
||||
* @see Cookable#cook(String, Reader)
|
||||
*/
|
||||
public
|
||||
SimpleCompiler(String optionalFileName, Reader in) throws IOException, CompileException {
|
||||
this.cook(optionalFileName, in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* SimpleCompiler sc = new SimpleCompiler();
|
||||
* sc.cook(optionalFileName, is);</pre>
|
||||
*
|
||||
* @see #SimpleCompiler()
|
||||
* @see Cookable#cook(String, InputStream)
|
||||
*/
|
||||
public
|
||||
SimpleCompiler(String optionalFileName, InputStream is) throws IOException, CompileException {
|
||||
this.cook(optionalFileName, is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* SimpleCompiler sc = new SimpleCompiler();
|
||||
* sc.cook(fileName);</pre>
|
||||
*
|
||||
* @see #SimpleCompiler()
|
||||
* @see Cookable#cookFile(String)
|
||||
*/
|
||||
public
|
||||
SimpleCompiler(String fileName) throws IOException, CompileException {
|
||||
this.cookFile(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to<pre>
|
||||
* SimpleCompiler sc = new SimpleCompiler();
|
||||
* sc.setParentClassLoader(optionalParentClassLoader);
|
||||
* sc.cook(scanner);</pre>
|
||||
*
|
||||
* @see #SimpleCompiler()
|
||||
* @see #setParentClassLoader(ClassLoader)
|
||||
* @see Cookable#cook(Reader)
|
||||
*/
|
||||
public
|
||||
SimpleCompiler(Scanner scanner, ClassLoader optionalParentClassLoader) throws IOException, CompileException {
|
||||
this.setParentClassLoader(optionalParentClassLoader);
|
||||
this.cook(scanner);
|
||||
}
|
||||
|
||||
public SimpleCompiler() {}
|
||||
|
||||
@Override public void
|
||||
setParentClassLoader(ClassLoader optionalParentClassLoader) {
|
||||
this.assertNotCooked();
|
||||
this.parentClassLoader = (
|
||||
optionalParentClassLoader != null
|
||||
? optionalParentClassLoader
|
||||
: Thread.currentThread().getContextClassLoader()
|
||||
);
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setDebuggingInformation(boolean debugSource, boolean debugLines, boolean debugVars) {
|
||||
this.debugSource = debugSource;
|
||||
this.debugLines = debugLines;
|
||||
this.debugVars = debugVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans, parses and compiles a given compilation unit from the given {@link Reader}. After completion, {@link
|
||||
* #getClassLoader()} returns a {@link ClassLoader} that allows for access to the compiled classes.
|
||||
*/
|
||||
@Override public final void
|
||||
cook(String optionalFileName, Reader r) throws CompileException, IOException {
|
||||
this.cook(new Scanner(optionalFileName, r));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans, parses and ompiles a given compilation unit from the given scanner. After completion, {@link
|
||||
* #getClassLoader()} returns a {@link ClassLoader} that allows for access to the compiled classes.
|
||||
*/
|
||||
public void
|
||||
cook(Scanner scanner) throws CompileException, IOException {
|
||||
this.compileToClassLoader(new Parser(scanner).parseCompilationUnit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cooks this compilation unit directly.
|
||||
*
|
||||
* @see Cookable#cook(Reader)
|
||||
*/
|
||||
public void
|
||||
cook(Java.CompilationUnit compilationUnit) throws CompileException {
|
||||
|
||||
// Compile the classes and load them.
|
||||
this.compileToClassLoader(compilationUnit);
|
||||
}
|
||||
|
||||
@Override public ClassLoader
|
||||
getClassLoader() {
|
||||
if (this.getClass() != SimpleCompiler.class) {
|
||||
throw new IllegalStateException("Must not be called on derived instances");
|
||||
}
|
||||
if (this.result == null) throw new IllegalStateException("Must only be called after \"cook()\"");
|
||||
return this.result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Two {@link SimpleCompiler}s are regarded equal iff
|
||||
* <ul>
|
||||
* <li>Both are objects of the same class (e.g. both are {@link ScriptEvaluator}s)
|
||||
* <li>Both generated functionally equal classes as seen by {@link ByteArrayClassLoader#equals(Object)}
|
||||
* </ul>
|
||||
*/
|
||||
@Override public boolean
|
||||
equals(Object o) {
|
||||
if (!(o instanceof SimpleCompiler)) return false;
|
||||
SimpleCompiler that = (SimpleCompiler) o;
|
||||
if (this.getClass() != that.getClass()) return false;
|
||||
if (this.result == null || that.result == null) {
|
||||
throw new IllegalStateException("Equality can only be checked after cooking");
|
||||
}
|
||||
return this.result.equals(that.result);
|
||||
}
|
||||
|
||||
@Override public int
|
||||
hashCode() { return this.parentClassLoader.hashCode(); }
|
||||
|
||||
@Override public void
|
||||
setCompileErrorHandler(ErrorHandler optionalCompileErrorHandler) {
|
||||
this.optionalCompileErrorHandler = optionalCompileErrorHandler;
|
||||
}
|
||||
|
||||
@Override public void
|
||||
setWarningHandler(WarningHandler optionalWarningHandler) {
|
||||
this.optionalWarningHandler = optionalWarningHandler;
|
||||
}
|
||||
|
||||
/** Wraps a reflection {@link Class} in a {@link Java.Type} object. */
|
||||
protected Java.Type
|
||||
classToType(final Location location, final Class clazz) {
|
||||
if (clazz == null) return null;
|
||||
|
||||
// IClass iClass;
|
||||
// synchronized (this.classes) {
|
||||
// iClass = (IClass) this.classes.get(clazz);
|
||||
// if (iClass == null) {
|
||||
// if (clazz.isPrimitive()) {
|
||||
// if (clazz == byte.class) { iClass = IClass.BYTE; } else
|
||||
// if (clazz == short.class) { iClass = IClass.SHORT; } else
|
||||
// if (clazz == int.class) { iClass = IClass.INT; } else
|
||||
// if (clazz == long.class) { iClass = IClass.LONG; } else
|
||||
// if (clazz == float.class) { iClass = IClass.FLOAT; } else
|
||||
// if (clazz == double.class) { iClass = IClass.DOUBLE; } else
|
||||
// if (clazz == char.class) { iClass = IClass.CHAR; } else
|
||||
// if (clazz == boolean.class) { iClass = IClass.BOOLEAN; } else
|
||||
// if (clazz == void.class) { iClass = IClass.VOID; } else
|
||||
// { throw new AssertionError(clazz); }
|
||||
// } else {
|
||||
// iClass = new ReflectionIClass(clazz, null);
|
||||
// }
|
||||
// this.classes.put(clazz, iClass);
|
||||
// }
|
||||
// }
|
||||
// return new Java.SimpleType(location, iClass);
|
||||
|
||||
// Can't use a SimpleType here because the classLoaderIClassLoader is not yet set up. Instead, create a
|
||||
// Type that lazily creates a delegate Type at COMPILE TIME.
|
||||
return new Java.Type(location) {
|
||||
|
||||
private Java.SimpleType delegate;
|
||||
|
||||
@Override public String toString() { return this.getDelegate().toString(); }
|
||||
@Override public void accept(AtomVisitor visitor) { this.getDelegate().accept((TypeVisitor) visitor); }
|
||||
@Override public void accept(TypeVisitor visitor) { this.getDelegate().accept(visitor); }
|
||||
|
||||
private Type
|
||||
getDelegate() {
|
||||
if (this.delegate == null) {
|
||||
IClass iClass;
|
||||
try {
|
||||
iClass = SimpleCompiler.this.classLoaderIClassLoader.loadIClass(
|
||||
Descriptor.fromClassName(clazz.getName())
|
||||
);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new JaninoRuntimeException("Loading IClass \"" + clazz.getName() + "\": " + ex);
|
||||
}
|
||||
if (iClass == null) {
|
||||
throw new JaninoRuntimeException(
|
||||
"Cannot load class '"
|
||||
+ clazz.getName()
|
||||
+ "' through the parent loader"
|
||||
);
|
||||
}
|
||||
|
||||
// Verify that the class loaders match.
|
||||
IClass iClass2 = iClass;
|
||||
Class class2 = clazz;
|
||||
for (;;) {
|
||||
IClass ct = iClass2.getComponentType();
|
||||
if (ct == null) {
|
||||
if (class2.getComponentType() != null) {
|
||||
throw new JaninoRuntimeException("Array type/class inconsistency");
|
||||
}
|
||||
break;
|
||||
}
|
||||
iClass2 = ct;
|
||||
class2 = class2.getComponentType();
|
||||
if (class2 == null) throw new JaninoRuntimeException("Array type/class inconsistency");
|
||||
}
|
||||
if (class2.isPrimitive()) {
|
||||
if (!iClass2.isPrimitive()) {
|
||||
throw new JaninoRuntimeException("Primitive type/class inconsistency");
|
||||
}
|
||||
} else {
|
||||
if (iClass2.isPrimitive()) {
|
||||
throw new JaninoRuntimeException("Primitive type/class inconsistency");
|
||||
}
|
||||
if (((ReflectionIClass) iClass2).getClazz() != class2) {
|
||||
throw new JaninoRuntimeException(
|
||||
"Class '"
|
||||
+ class2.getName()
|
||||
+ "' was loaded through a different loader"
|
||||
);
|
||||
}
|
||||
}
|
||||
this.delegate = new Java.SimpleType(location, iClass);
|
||||
}
|
||||
|
||||
return this.delegate;
|
||||
}
|
||||
};
|
||||
}
|
||||
// private final Map<Class, IClass> classes = new HashMap();
|
||||
|
||||
/** Converts an array of {@link Class}es into an array of{@link Java.Type}s. */
|
||||
protected Java.Type[]
|
||||
classesToTypes(Location location, Class[] classes) {
|
||||
Java.Type[] types = new Java.Type[classes.length];
|
||||
for (int i = 0; i < classes.length; ++i) {
|
||||
types[i] = this.classToType(location, classes[i]);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the given compilation unit. (A "compilation unit" is typically the contents
|
||||
* of a Java™ 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");
|
||||
}
|
||||
}
|
12
src/org/codehaus/janino/TODO.txt
Normal file
12
src/org/codehaus/janino/TODO.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
The raw, inofficial list of TODOs:
|
||||
|
||||
* Implement '@SuppressWarnings'; supersede JANINO's old '-warn:...' feature
|
||||
* Implement non-SOURCE annotations
|
||||
* Implement annotation declarations
|
||||
* Implement ENUMs
|
||||
* Implement type arguments ('List<String> l;')
|
||||
* Implement type parameters ('class MyClass<T extends InputStream> { ... }')
|
||||
* Enhanced FOR loop
|
||||
|
||||
Recently implemented:
|
||||
* ASSERT (simplified, ASSERTions are ALWAYS enabled, as if '-ea' were set)
|
43
src/org/codehaus/janino/UnicodeUnescapeException.java
Normal file
43
src/org/codehaus/janino/UnicodeUnescapeException.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
/**
|
||||
* Represents a problem that occurred while unescaping a unicode escape
|
||||
* sequence through a {@link org.codehaus.janino.UnicodeUnescapeReader}.
|
||||
*/
|
||||
public
|
||||
class UnicodeUnescapeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -8965331941165671541L;
|
||||
|
||||
public
|
||||
UnicodeUnescapeException(String message) { super(message); }
|
||||
|
||||
public
|
||||
UnicodeUnescapeException(String message, Throwable cause) { super(message, cause); }
|
||||
}
|
110
src/org/codehaus/janino/UnicodeUnescapeReader.java
Normal file
110
src/org/codehaus/janino/UnicodeUnescapeReader.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
import java.io.FilterReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
/**
|
||||
* A {@link FilterReader} that unescapes the "Unicode Escapes" as described in JLS7 3.10.6.
|
||||
* <p>
|
||||
* Notice that it is possible to formulate invalid escape sequences, e.g. "\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;
|
||||
}
|
10542
src/org/codehaus/janino/UnitCompiler.java
Normal file
10542
src/org/codehaus/janino/UnitCompiler.java
Normal file
File diff suppressed because it is too large
Load Diff
1102
src/org/codehaus/janino/UnparseVisitor.java
Normal file
1102
src/org/codehaus/janino/UnparseVisitor.java
Normal file
File diff suppressed because it is too large
Load Diff
274
src/org/codehaus/janino/Visitor.java
Normal file
274
src/org/codehaus/janino/Visitor.java
Normal file
|
@ -0,0 +1,274 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino;
|
||||
|
||||
|
||||
/** Basis for the "visitor" pattern as described in "Gamma, Helm, Johnson, Vlissides: Design Patterns". */
|
||||
public
|
||||
class Visitor {
|
||||
|
||||
/**
|
||||
* The union of {@link ImportVisitor}, {@link TypeDeclarationVisitor}, {@link TypeBodyDeclarationVisitor} and
|
||||
* {@link AtomVisitor}.
|
||||
*/
|
||||
public
|
||||
interface ComprehensiveVisitor
|
||||
extends ImportVisitor, TypeDeclarationVisitor, TypeBodyDeclarationVisitor, BlockStatementVisitor, AtomVisitor,
|
||||
ElementValueVisitor { // SUPPRESS CHECKSTYLE WrapAndIndent
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.CompilationUnit.ImportDeclaration}s. */
|
||||
public
|
||||
interface ImportVisitor {
|
||||
/** Invoked by {@link Java.CompilationUnit.SingleTypeImportDeclaration#accept(Visitor.ImportVisitor)} */
|
||||
void visitSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid);
|
||||
/** Invoked by {@link Java.CompilationUnit.TypeImportOnDemandDeclaration#accept(Visitor.ImportVisitor)} */
|
||||
void visitTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd);
|
||||
/** Invoked by {@link Java.CompilationUnit.SingleStaticImportDeclaration#accept(Visitor.ImportVisitor)} */
|
||||
void visitSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration ssid);
|
||||
/** Invoked by {@link Java.CompilationUnit.StaticImportOnDemandDeclaration#accept(Visitor.ImportVisitor)} */
|
||||
void visitStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.TypeDeclaration}s. */
|
||||
public
|
||||
interface TypeDeclarationVisitor {
|
||||
/** Invoked by {@link Java.AnonymousClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
|
||||
void visitAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd);
|
||||
/** Invoked by {@link Java.LocalClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
|
||||
void visitLocalClassDeclaration(Java.LocalClassDeclaration lcd);
|
||||
/** Invoked by {@link Java.PackageMemberClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
|
||||
void visitPackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd);
|
||||
/** Invoked by {@link Java.MemberInterfaceDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
|
||||
void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid);
|
||||
/** Invoked by {@link Java.PackageMemberInterfaceDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
|
||||
void visitPackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid);
|
||||
/** Invoked by {@link Java.MemberClassDeclaration#accept(Visitor.TypeDeclarationVisitor)} */
|
||||
void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.FunctionDeclarator}s. */
|
||||
public
|
||||
interface FunctionDeclaratorVisitor {
|
||||
/** Invoked by {@link Java.ConstructorDeclarator#accept(Visitor.TypeBodyDeclarationVisitor)} */
|
||||
void visitConstructorDeclarator(Java.ConstructorDeclarator cd);
|
||||
/** Invoked by {@link Java.MethodDeclarator#accept(Visitor.TypeBodyDeclarationVisitor)} */
|
||||
void visitMethodDeclarator(Java.MethodDeclarator md);
|
||||
}
|
||||
|
||||
/**
|
||||
* The visitor for all kinds of {@link Java.TypeBodyDeclaration}s (declarations that may appear in the body of a
|
||||
* type declaration).
|
||||
*/
|
||||
public
|
||||
interface TypeBodyDeclarationVisitor extends FunctionDeclaratorVisitor {
|
||||
/** Invoked by {@link Java.MemberInterfaceDeclaration#accept(Visitor.TypeBodyDeclarationVisitor)} */
|
||||
void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid);
|
||||
/** Invoked by {@link Java.MemberClassDeclaration#accept(Visitor.TypeBodyDeclarationVisitor)} */
|
||||
void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd);
|
||||
/** Invoked by {@link Java.Initializer#accept(Visitor.TypeBodyDeclarationVisitor)} */
|
||||
void visitInitializer(Java.Initializer i);
|
||||
/** Invoked by {@link Java.FieldDeclaration#accept(Visitor.TypeBodyDeclarationVisitor)} */
|
||||
void visitFieldDeclaration(Java.FieldDeclaration fd);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.BlockStatement}s (statements that may appear with a block). */
|
||||
public
|
||||
interface BlockStatementVisitor {
|
||||
/** Invoked by {@link Java.Initializer#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitInitializer(Java.Initializer i);
|
||||
/** Invoked by {@link Java.FieldDeclaration#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitFieldDeclaration(Java.FieldDeclaration fd);
|
||||
/** Invoked by {@link Java.LabeledStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitLabeledStatement(Java.LabeledStatement ls);
|
||||
/** Invoked by {@link Java.Block#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitBlock(Java.Block b);
|
||||
/** Invoked by {@link Java.ExpressionStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitExpressionStatement(Java.ExpressionStatement es);
|
||||
/** Invoked by {@link Java.IfStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitIfStatement(Java.IfStatement is);
|
||||
/** Invoked by {@link Java.ForStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitForStatement(Java.ForStatement fs);
|
||||
/** Invoked by {@link Java.ForEachStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitForEachStatement(Java.ForEachStatement forEachStatement);
|
||||
/** Invoked by {@link Java.WhileStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitWhileStatement(Java.WhileStatement ws);
|
||||
/** Invoked by {@link Java.TryStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitTryStatement(Java.TryStatement ts);
|
||||
/** Invoked by {@link Java.SwitchStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitSwitchStatement(Java.SwitchStatement ss);
|
||||
/** Invoked by {@link Java.SynchronizedStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitSynchronizedStatement(Java.SynchronizedStatement ss);
|
||||
/** Invoked by {@link Java.DoStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitDoStatement(Java.DoStatement ds);
|
||||
/** Invoked by {@link Java.LocalVariableDeclarationStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds);
|
||||
/** Invoked by {@link Java.ReturnStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitReturnStatement(Java.ReturnStatement rs);
|
||||
/** Invoked by {@link Java.ThrowStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitThrowStatement(Java.ThrowStatement ts);
|
||||
/** Invoked by {@link Java.BreakStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitBreakStatement(Java.BreakStatement bs);
|
||||
/** Invoked by {@link Java.ContinueStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitContinueStatement(Java.ContinueStatement cs);
|
||||
/** Invoked by {@link Java.AssertStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitAssertStatement(Java.AssertStatement as);
|
||||
/** Invoked by {@link Java.EmptyStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitEmptyStatement(Java.EmptyStatement es);
|
||||
/** Invoked by {@link Java.LocalClassDeclarationStatement#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds);
|
||||
/** Invoked by {@link Java.AlternateConstructorInvocation#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci);
|
||||
/** Invoked by {@link Java.SuperConstructorInvocation#accept(Visitor.BlockStatementVisitor)} */
|
||||
void visitSuperConstructorInvocation(Java.SuperConstructorInvocation sci);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.Atom}s. */
|
||||
public
|
||||
interface AtomVisitor extends RvalueVisitor, TypeVisitor {
|
||||
/** Invoked by {@link Java.Package#accept(Visitor.AtomVisitor)}. */
|
||||
void visitPackage(Java.Package p);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.Type}s. */
|
||||
public
|
||||
interface TypeVisitor {
|
||||
/** Invoked by {@link Java.ArrayType#accept(Visitor.TypeVisitor)} */
|
||||
void visitArrayType(Java.ArrayType at);
|
||||
/** Invoked by {@link Java.BasicType#accept(Visitor.TypeVisitor)} */
|
||||
void visitBasicType(Java.BasicType bt);
|
||||
/** Invoked by {@link Java.ReferenceType#accept(Visitor.TypeVisitor)} */
|
||||
void visitReferenceType(Java.ReferenceType rt);
|
||||
/** Invoked by {@link Java.RvalueMemberType#accept(Visitor.TypeVisitor)} */
|
||||
void visitRvalueMemberType(Java.RvalueMemberType rmt);
|
||||
/** Invoked by {@link Java.SimpleType#accept(Visitor.TypeVisitor)} */
|
||||
void visitSimpleType(Java.SimpleType st);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.Rvalue}s. */
|
||||
public
|
||||
interface RvalueVisitor extends LvalueVisitor {
|
||||
/** Invoked by {@link Java.ArrayLength#accept(Visitor.RvalueVisitor)} */
|
||||
void visitArrayLength(Java.ArrayLength al);
|
||||
/** Invoked by {@link Java.Assignment#accept(Visitor.RvalueVisitor)} */
|
||||
void visitAssignment(Java.Assignment a);
|
||||
/** Invoked by {@link Java.UnaryOperation#accept(Visitor.RvalueVisitor)} */
|
||||
void visitUnaryOperation(Java.UnaryOperation uo);
|
||||
/** Invoked by {@link Java.BinaryOperation#accept(Visitor.RvalueVisitor)} */
|
||||
void visitBinaryOperation(Java.BinaryOperation bo);
|
||||
/** Invoked by {@link Java.Cast#accept(Visitor.RvalueVisitor)} */
|
||||
void visitCast(Java.Cast c);
|
||||
/** Invoked by {@link Java.ClassLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitClassLiteral(Java.ClassLiteral cl);
|
||||
/** Invoked by {@link Java.ConditionalExpression#accept(Visitor.RvalueVisitor)} */
|
||||
void visitConditionalExpression(Java.ConditionalExpression ce);
|
||||
/** Invoked by {@link Java.Crement#accept(Visitor.RvalueVisitor)} */
|
||||
void visitCrement(Java.Crement c);
|
||||
/** Invoked by {@link Java.Instanceof#accept(Visitor.RvalueVisitor)} */
|
||||
void visitInstanceof(Java.Instanceof io);
|
||||
/** Invoked by {@link Java.MethodInvocation#accept(Visitor.RvalueVisitor)} */
|
||||
void visitMethodInvocation(Java.MethodInvocation mi);
|
||||
/** Invoked by {@link Java.SuperclassMethodInvocation#accept(Visitor.RvalueVisitor)} */
|
||||
void visitSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi);
|
||||
/** Invoked by {@link Java.IntegerLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitIntegerLiteral(Java.IntegerLiteral il);
|
||||
/** Invoked by {@link Java.FloatingPointLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitFloatingPointLiteral(Java.FloatingPointLiteral fpl);
|
||||
/** Invoked by {@link Java.BooleanLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitBooleanLiteral(Java.BooleanLiteral bl);
|
||||
/** Invoked by {@link Java.CharacterLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitCharacterLiteral(Java.CharacterLiteral cl);
|
||||
/** Invoked by {@link Java.StringLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitStringLiteral(Java.StringLiteral sl);
|
||||
/** Invoked by {@link Java.NullLiteral#accept(Visitor.RvalueVisitor)} */
|
||||
void visitNullLiteral(Java.NullLiteral nl);
|
||||
/** Invoked by {@link Java.SimpleConstant#accept(Visitor.RvalueVisitor)} */
|
||||
void visitSimpleConstant(Java.SimpleConstant sl);
|
||||
/** Invoked by {@link Java.NewAnonymousClassInstance#accept(Visitor.RvalueVisitor)} */
|
||||
void visitNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci);
|
||||
/** Invoked by {@link Java.NewArray#accept(Visitor.RvalueVisitor)} */
|
||||
void visitNewArray(Java.NewArray na);
|
||||
/** Invoked by {@link Java.NewInitializedArray#accept(Visitor.RvalueVisitor)} */
|
||||
void visitNewInitializedArray(Java.NewInitializedArray nia);
|
||||
/** Invoked by {@link Java.NewClassInstance#accept(Visitor.RvalueVisitor)} */
|
||||
void visitNewClassInstance(Java.NewClassInstance nci);
|
||||
/** Invoked by {@link Java.ParameterAccess#accept(Visitor.RvalueVisitor)} */
|
||||
void visitParameterAccess(Java.ParameterAccess pa);
|
||||
/** Invoked by {@link Java.QualifiedThisReference#accept(Visitor.RvalueVisitor)} */
|
||||
void visitQualifiedThisReference(Java.QualifiedThisReference qtr);
|
||||
/** Invoked by {@link Java.ArrayLength#accept(Visitor.RvalueVisitor)} */
|
||||
void visitThisReference(Java.ThisReference tr);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.Lvalue}s. */
|
||||
public
|
||||
interface LvalueVisitor {
|
||||
/** Invoked by {@link Java.AmbiguousName#accept(Visitor.LvalueVisitor)} */
|
||||
void visitAmbiguousName(Java.AmbiguousName an);
|
||||
/** Invoked by {@link Java.ArrayAccessExpression#accept(Visitor.LvalueVisitor)} */
|
||||
void visitArrayAccessExpression(Java.ArrayAccessExpression aae);
|
||||
/** Invoked by {@link Java.FieldAccess#accept(Visitor.LvalueVisitor)} */
|
||||
void visitFieldAccess(Java.FieldAccess fa);
|
||||
/** Invoked by {@link Java.FieldAccessExpression#accept(Visitor.LvalueVisitor)} */
|
||||
void visitFieldAccessExpression(Java.FieldAccessExpression fae);
|
||||
/** Invoked by {@link Java.SuperclassFieldAccessExpression#accept(Visitor.LvalueVisitor)} */
|
||||
void visitSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae);
|
||||
/** Invoked by {@link Java.LocalVariableAccess#accept(Visitor.LvalueVisitor)} */
|
||||
void visitLocalVariableAccess(Java.LocalVariableAccess lva);
|
||||
/** Invoked by {@link Java.ParenthesizedExpression#accept(Visitor.LvalueVisitor)} */
|
||||
void visitParenthesizedExpression(Java.ParenthesizedExpression pe);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.Annotation}s. */
|
||||
public
|
||||
interface AnnotationVisitor {
|
||||
/** Invoked by {@link Java.MarkerAnnotation#accept(Visitor.AnnotationVisitor)} */
|
||||
void visitMarkerAnnotation(Java.MarkerAnnotation ma);
|
||||
/** Invoked by {@link Java.NormalAnnotation#accept(Visitor.AnnotationVisitor)} */
|
||||
void visitNormalAnnotation(Java.NormalAnnotation na);
|
||||
/** Invoked by {@link Java.SingleElementAnnotation#accept(Visitor.AnnotationVisitor)} */
|
||||
void visitSingleElementAnnotation(Java.SingleElementAnnotation sea);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.ElementValue}s. */
|
||||
public
|
||||
interface ElementValueVisitor extends RvalueVisitor, AnnotationVisitor {
|
||||
/** Invoked by {@link Java.ElementValueArrayInitializer#accept(Visitor.ElementValueVisitor)} */
|
||||
void visitElementValueArrayInitializer(Java.ElementValueArrayInitializer evai);
|
||||
}
|
||||
|
||||
/** The visitor for all kinds of {@link Java.TypeArgument}s. */
|
||||
public
|
||||
interface TypeArgumentVisitor {
|
||||
/** Invoked by {@link Java.Wildcard#accept(Visitor.TypeArgumentVisitor)} */
|
||||
void visitWildcard(Java.Wildcard w);
|
||||
/** Invoked by {@link Java.ReferenceType#accept(Visitor.TypeArgumentVisitor)} */
|
||||
void visitReferenceType(Java.ReferenceType rt);
|
||||
/** Invoked by {@link Java.ArrayType#accept(Visitor.TypeArgumentVisitor)} */
|
||||
void visitArrayType(Java.ArrayType arrayType);
|
||||
}
|
||||
}
|
35
src/org/codehaus/janino/package-info.java
Normal file
35
src/org/codehaus/janino/package-info.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2013, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The classes in this package pose the core of the Janino Java<sup>TM</sup> compiler.
|
||||
* <p>
|
||||
* The package comprises a scanner ({@link org.codehaus.janino.Scanner}, a parser ({@link org.codehaus.janino.Parser})
|
||||
* and a class file library. The parser builds a syntax tree from the "Java.*" classes that represents the parsed code.
|
||||
* The {@link org.codehaus.janino.UnitCompiler#compileUnit} method compiles this syntax tree into a {@link
|
||||
* org.codehaus.janino.util.ClassFile} object, which can write Java<sup>TM</sup> bytecode to an "OutputStream".
|
||||
*/
|
||||
package org.codehaus.janino;
|
101
src/org/codehaus/janino/samples/DeclarationCounter.java
Normal file
101
src/org/codehaus/janino/samples/DeclarationCounter.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.samples;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.janino.Java;
|
||||
import org.codehaus.janino.Parser;
|
||||
import org.codehaus.janino.Scanner;
|
||||
import org.codehaus.janino.util.Traverser;
|
||||
|
||||
/**
|
||||
* An example application for the {@link org.codehaus.janino.util.Traverser}:
|
||||
* Reads, scans and parses the files named on the command line and counts
|
||||
* several kinds of declarations.
|
||||
*/
|
||||
public
|
||||
class DeclarationCounter extends Traverser {
|
||||
|
||||
public static void // SUPPRESS CHECKSTYLE JavadocMethod
|
||||
main(String[] args) throws CompileException, IOException {
|
||||
DeclarationCounter dc = new DeclarationCounter();
|
||||
for (String fileName : args) {
|
||||
|
||||
// Parse each compilation unit.
|
||||
FileReader r = new FileReader(fileName);
|
||||
Java.CompilationUnit cu;
|
||||
try {
|
||||
cu = new Parser(new Scanner(fileName, r)).parseCompilationUnit();
|
||||
} finally {
|
||||
r.close();
|
||||
}
|
||||
|
||||
// Traverse it and count declarations.
|
||||
dc.traverseCompilationUnit(cu);
|
||||
}
|
||||
|
||||
System.out.println("Class declarations: " + dc.classDeclarationCount);
|
||||
System.out.println("Interface declarations: " + dc.interfaceDeclarationCount);
|
||||
System.out.println("Fields: " + dc.fieldCount);
|
||||
System.out.println("Local variables: " + dc.localVariableCount);
|
||||
}
|
||||
|
||||
// Count class declarations.
|
||||
@Override public void
|
||||
traverseClassDeclaration(Java.ClassDeclaration cd) {
|
||||
++this.classDeclarationCount;
|
||||
super.traverseClassDeclaration(cd);
|
||||
}
|
||||
private int classDeclarationCount;
|
||||
|
||||
// Count interface declarations.
|
||||
@Override public void
|
||||
traverseInterfaceDeclaration(Java.InterfaceDeclaration id) {
|
||||
++this.interfaceDeclarationCount;
|
||||
super.traverseInterfaceDeclaration(id);
|
||||
}
|
||||
private int interfaceDeclarationCount;
|
||||
|
||||
// Count fields.
|
||||
@Override public void
|
||||
traverseFieldDeclaration(Java.FieldDeclaration fd) {
|
||||
this.fieldCount += fd.variableDeclarators.length;
|
||||
super.traverseFieldDeclaration(fd);
|
||||
}
|
||||
private int fieldCount;
|
||||
|
||||
// Count local variables.
|
||||
@Override public void
|
||||
traverseLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
|
||||
this.localVariableCount += lvds.variableDeclarators.length;
|
||||
super.traverseLocalVariableDeclarationStatement(lvds);
|
||||
}
|
||||
private int localVariableCount;
|
||||
}
|
28
src/org/codehaus/janino/samples/package-info.java
Normal file
28
src/org/codehaus/janino/samples/package-info.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2013, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** Sample applications for the Janino Java<sup>TM</sup> compiler. */
|
||||
package org.codehaus.janino.samples;
|
257
src/org/codehaus/janino/tools/HprofScrubber.java
Normal file
257
src/org/codehaus/janino/tools/HprofScrubber.java
Normal file
|
@ -0,0 +1,257 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.tools;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Example for object allocation statistics:
|
||||
*
|
||||
* java -Xrunhprof:heap=sites,monitor=n,cutoff=0,depth=4 MyClass
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public final
|
||||
class HprofScrubber {
|
||||
private HprofScrubber() {}
|
||||
|
||||
private static
|
||||
class Site {
|
||||
public final int allocatedBytes;
|
||||
public final int allocatedObjects;
|
||||
public final int traceNumber;
|
||||
public final String className;
|
||||
|
||||
public
|
||||
Site(int allocatedBytes, int allocatedObjects, int traceNumber, String className) {
|
||||
this.allocatedBytes = allocatedBytes;
|
||||
this.allocatedObjects = allocatedObjects;
|
||||
this.traceNumber = traceNumber;
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
|
||||
private static
|
||||
class Sample {
|
||||
public final int count;
|
||||
public final int traceNumber;
|
||||
|
||||
public
|
||||
Sample(int count, int traceNumber) {
|
||||
this.count = count;
|
||||
this.traceNumber = traceNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public static void // SUPPRESS CHECKSTYLE JavadocMethod
|
||||
main(String[] args) throws Exception {
|
||||
String fileName = args.length == 0 ? "java.hprof.txt" : args[0];
|
||||
|
||||
BufferedReader br = new BufferedReader(new FileReader(fileName));
|
||||
try {
|
||||
Map<Integer /*number*/, String[] /*stackFrames*/> traces = new HashMap();
|
||||
List<Site> sites = new ArrayList();
|
||||
List<Sample> samples = new ArrayList();
|
||||
|
||||
String s = br.readLine();
|
||||
while (s != null) {
|
||||
if (s.startsWith("SITES BEGIN")) {
|
||||
br.readLine();
|
||||
br.readLine();
|
||||
for (;;) {
|
||||
s = br.readLine();
|
||||
if (s.startsWith("SITES END")) break;
|
||||
StringTokenizer st = new StringTokenizer(s);
|
||||
st.nextToken(); // rank
|
||||
st.nextToken(); // percent self
|
||||
st.nextToken(); // percent accum
|
||||
st.nextToken(); // live bytes
|
||||
st.nextToken(); // live objects
|
||||
sites.add(new Site(
|
||||
Integer.parseInt(st.nextToken()), // allocatedBytes
|
||||
Integer.parseInt(st.nextToken()), // allocatedObjects
|
||||
Integer.parseInt(st.nextToken()), // traceNumber
|
||||
st.nextToken() // className
|
||||
));
|
||||
}
|
||||
} else
|
||||
if (s.startsWith("TRACE ") && s.endsWith(":")) {
|
||||
int traceNumber = Integer.parseInt(s.substring(6, s.length() - 1));
|
||||
List<String> l = new ArrayList();
|
||||
for (;;) {
|
||||
s = br.readLine();
|
||||
if (!s.startsWith("\t")) break;
|
||||
l.add(s.substring(1));
|
||||
}
|
||||
traces.put(
|
||||
new Integer(traceNumber),
|
||||
(String[]) l.toArray(new String[l.size()])
|
||||
);
|
||||
} else
|
||||
if (s.startsWith("CPU SAMPLES BEGIN")) {
|
||||
br.readLine();
|
||||
for (;;) {
|
||||
s = br.readLine();
|
||||
if (s.startsWith("CPU SAMPLES END")) break;
|
||||
StringTokenizer st = new StringTokenizer(s);
|
||||
st.nextToken(); // rank
|
||||
st.nextToken(); // percent self
|
||||
st.nextToken(); // percent accum
|
||||
int count = Integer.parseInt(st.nextToken());
|
||||
if (count == 0) continue;
|
||||
int trace = Integer.parseInt(st.nextToken());
|
||||
samples.add(new Sample(count, trace));
|
||||
}
|
||||
} else {
|
||||
s = br.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
HprofScrubber.dumpSites((Site[]) sites.toArray(new Site[sites.size()]), traces);
|
||||
|
||||
HprofScrubber.dumpSamples((Sample[]) samples.toArray(new Sample[samples.size()]), traces);
|
||||
|
||||
} finally {
|
||||
try { br.close(); } catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
private static void
|
||||
dumpSites(Site[] ss, Map<Integer, String[]> traces) {
|
||||
Arrays.sort(ss, new Comparator() {
|
||||
|
||||
@Override public int
|
||||
compare(Object o1, Object o2) { return ((Site) o2).allocatedBytes - ((Site) o1).allocatedBytes; }
|
||||
});
|
||||
|
||||
int totalAllocatedBytes = 0, totalAllocatedObjects = 0;
|
||||
for (Site site : ss) {
|
||||
totalAllocatedBytes += site.allocatedBytes;
|
||||
totalAllocatedObjects += site.allocatedObjects;
|
||||
}
|
||||
|
||||
System.out.println(" percent alloc'ed");
|
||||
System.out.println("rank self accum bytes objects class name");
|
||||
System.out.println("Total: " + totalAllocatedBytes + " " + totalAllocatedObjects);
|
||||
|
||||
double accumulatedPercentage = 0.0;
|
||||
MessageFormat mf = new MessageFormat(
|
||||
"{0,number,00000} {1,number,00.00}% {2,number,00.00}% {3,number,000000000} {4,number,000000000} {5}"
|
||||
);
|
||||
for (int i = 0; i < ss.length; ++i) {
|
||||
Site site = ss[i];
|
||||
double selfPercentage = 100.0 * ((double) site.allocatedBytes / (double) totalAllocatedBytes);
|
||||
accumulatedPercentage += selfPercentage;
|
||||
// System.out.println(
|
||||
// (i + 1)
|
||||
// + " "
|
||||
// + selfPercentage
|
||||
// + "% "
|
||||
// + accumulatedPercentage
|
||||
// + "% "
|
||||
// + site.allocatedBytes
|
||||
// + " "
|
||||
// + site.allocatedObjects
|
||||
// + " "
|
||||
// + site.className
|
||||
// );
|
||||
System.out.println(mf.format(
|
||||
new Object[] {
|
||||
new Integer(i + 1),
|
||||
new Double(selfPercentage),
|
||||
new Double(accumulatedPercentage),
|
||||
new Integer(site.allocatedBytes),
|
||||
new Integer(site.allocatedObjects),
|
||||
site.className
|
||||
},
|
||||
new StringBuffer(),
|
||||
new FieldPosition(0)
|
||||
));
|
||||
String[] stackFrames = (String[]) traces.get(new Integer(site.traceNumber));
|
||||
if (stackFrames != null) {
|
||||
for (String stackFrame : stackFrames) {
|
||||
System.out.println(" " + stackFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void
|
||||
dumpSamples(Sample[] ss, Map<Integer, String[]> traces) {
|
||||
int totalCount = 0;
|
||||
for (Sample s : ss) totalCount += s.count;
|
||||
|
||||
System.out.println(" percent");
|
||||
System.out.println("rank self accum count");
|
||||
System.out.println("Total: " + totalCount);
|
||||
|
||||
double accumulatedPercentage = 0.0;
|
||||
|
||||
MessageFormat mf = new MessageFormat(
|
||||
"{0,number,00000} {1,number,00.00}% {2,number,00.00}% {3,number,000000000}"
|
||||
);
|
||||
for (int i = 0; i < ss.length; ++i) {
|
||||
Sample sample = ss[i];
|
||||
double selfPercentage = 100.0 * ((double) sample.count / (double) totalCount);
|
||||
accumulatedPercentage += selfPercentage;
|
||||
// System.out.println(
|
||||
// (i + 1)
|
||||
// + " "
|
||||
// + selfPercentage
|
||||
// + "% "
|
||||
// + accumulatedPercentage
|
||||
// + "% "
|
||||
// + sample.count
|
||||
// + " "
|
||||
// + sample.traceNumber
|
||||
// );
|
||||
System.out.println(mf.format(
|
||||
new Object[] {
|
||||
new Integer(i + 1),
|
||||
new Double(selfPercentage),
|
||||
new Double(accumulatedPercentage),
|
||||
new Integer(sample.count)
|
||||
},
|
||||
new StringBuffer(),
|
||||
new FieldPosition(0)
|
||||
));
|
||||
String[] stackFrames = (String[]) traces.get(new Integer(sample.traceNumber));
|
||||
if (stackFrames != null) {
|
||||
for (String stackFrame : stackFrames) System.out.println(" " + stackFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
714
src/org/codehaus/janino/tools/JGrep.java
Normal file
714
src/org/codehaus/janino/tools/JGrep.java
Normal file
|
@ -0,0 +1,714 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.tools;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.commons.compiler.CompileException;
|
||||
import org.codehaus.commons.compiler.CompilerFactoryFactory;
|
||||
import org.codehaus.commons.compiler.ICompilerFactory;
|
||||
import org.codehaus.commons.compiler.IExpressionEvaluator;
|
||||
import org.codehaus.commons.compiler.UncheckedCompileException;
|
||||
import org.codehaus.janino.Descriptor;
|
||||
import org.codehaus.janino.ExpressionEvaluator;
|
||||
import org.codehaus.janino.IClass;
|
||||
import org.codehaus.janino.IClassLoader;
|
||||
import org.codehaus.janino.Java;
|
||||
import org.codehaus.janino.Java.CompilationUnit;
|
||||
import org.codehaus.janino.Parser;
|
||||
import org.codehaus.janino.Scanner;
|
||||
import org.codehaus.janino.UnitCompiler;
|
||||
import org.codehaus.janino.util.Benchmark;
|
||||
import org.codehaus.janino.util.ClassFile;
|
||||
import org.codehaus.janino.util.StringPattern;
|
||||
import org.codehaus.janino.util.Traverser;
|
||||
import org.codehaus.janino.util.enumerator.Enumerator;
|
||||
import org.codehaus.janino.util.iterator.DirectoryIterator;
|
||||
import org.codehaus.janino.util.resource.PathResourceFinder;
|
||||
|
||||
|
||||
/**
|
||||
* Reads a set of compilation units from the file system and searches it for specific
|
||||
* Java™ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
28
src/org/codehaus/janino/tools/package-info.java
Normal file
28
src/org/codehaus/janino/tools/package-info.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2013, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** Auxiliary command line tools related to JANINO. */
|
||||
package org.codehaus.janino.tools;
|
251
src/org/codehaus/janino/util/AutoIndentWriter.java
Normal file
251
src/org/codehaus/janino/util/AutoIndentWriter.java
Normal file
|
@ -0,0 +1,251 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import java.io.FilterWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link java.io.FilterWriter} that automatically indents lines by looking at
|
||||
* trailing opening braces ('{') and leading closing braces ('}').
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class AutoIndentWriter extends FilterWriter {
|
||||
|
||||
/** Special character indicating a tabular layout of the following text. */
|
||||
public static final char TABULATOR = 0xffff;
|
||||
|
||||
/** Special character indicating to clear all tabluar layout that was configured through {@link #TABULATOR}. */
|
||||
public static final char CLEAR_TABULATORS = 0xfffe;
|
||||
|
||||
/** Special character that inserts a line break and indents the following text by one position. */
|
||||
public static final char INDENT = 0xfffd;
|
||||
|
||||
/** Special character that inserts a line break and unindents the following text by one position. */
|
||||
public static final char UNINDENT = 0xfffc;
|
||||
|
||||
private final StringBuilder lineBuffer = new StringBuilder();
|
||||
private int indentation;
|
||||
private List<StringBuilder> tabulatorBuffer;
|
||||
private int tabulatorIndentation;
|
||||
|
||||
public
|
||||
AutoIndentWriter(Writer out) { super(out); }
|
||||
|
||||
@Override public void
|
||||
write(char[] cbuf, int off, int len) throws IOException {
|
||||
for (; len > 0; --len) this.write(cbuf[off++]);
|
||||
}
|
||||
|
||||
@Override public void
|
||||
write(String str, int off, int len) throws IOException {
|
||||
for (; len > 0; --len) this.write(str.charAt(off++));
|
||||
}
|
||||
|
||||
@Override public void
|
||||
write(int c) throws IOException {
|
||||
if (c == '\n') {
|
||||
this.lineBuffer.append('\n');
|
||||
this.line(this.lineBuffer.toString());
|
||||
this.lineBuffer.setLength(0);
|
||||
return;
|
||||
}
|
||||
if (this.lineBuffer.length() > 0 && this.lineBuffer.charAt(this.lineBuffer.length() - 1) == '\r') {
|
||||
this.line(this.lineBuffer.toString());
|
||||
this.lineBuffer.setCharAt(0, (char) c);
|
||||
this.lineBuffer.setLength(1);
|
||||
return;
|
||||
}
|
||||
this.lineBuffer.append((char) c);
|
||||
}
|
||||
|
||||
private void
|
||||
line(String line) throws IOException {
|
||||
if (this.tabulatorBuffer != null) {
|
||||
this.tabulatorBuffer.add(new StringBuilder(line.length()).append(line));
|
||||
if (line.charAt(0) == AutoIndentWriter.INDENT) { ++this.indentation; line = line.substring(1); }
|
||||
if (line.charAt(0) == AutoIndentWriter.UNINDENT && --this.indentation < this.tabulatorIndentation) {
|
||||
this.flushTabulatorBuffer();
|
||||
}
|
||||
} else
|
||||
if (line.indexOf(AutoIndentWriter.TABULATOR) != -1) {
|
||||
if (line.charAt(0) == AutoIndentWriter.INDENT) { ++this.indentation; line = line.substring(1); }
|
||||
if (line.charAt(0) == AutoIndentWriter.UNINDENT) { --this.indentation; line = line.substring(1); }
|
||||
|
||||
this.tabulatorBuffer = new ArrayList<StringBuilder>();
|
||||
this.tabulatorBuffer.add(new StringBuilder(line.length()).append(line));
|
||||
this.tabulatorIndentation = this.indentation;
|
||||
} else
|
||||
{
|
||||
if (line.charAt(0) == AutoIndentWriter.CLEAR_TABULATORS) line = line.substring(1);
|
||||
if (line.charAt(0) == AutoIndentWriter.INDENT) { ++this.indentation; line = line.substring(1); }
|
||||
if (line.charAt(0) == AutoIndentWriter.UNINDENT) { --this.indentation; line = line.substring(1); }
|
||||
if ("\r\n".indexOf(line.charAt(0)) == -1) {
|
||||
for (int i = 0; i < this.indentation; ++i) this.out.write(" ");
|
||||
}
|
||||
this.out.write(line);
|
||||
}
|
||||
}
|
||||
|
||||
private void
|
||||
flushTabulatorBuffer() throws IOException {
|
||||
List<List<StringBuilder>> lineGroups = new ArrayList();
|
||||
lineGroups.add(new ArrayList<StringBuilder>());
|
||||
|
||||
for (StringBuilder line : this.tabulatorBuffer) {
|
||||
|
||||
int idx = 0;
|
||||
if (line.charAt(0) == AutoIndentWriter.INDENT) {
|
||||
lineGroups.add(new ArrayList<StringBuilder>());
|
||||
++idx;
|
||||
}
|
||||
if (line.charAt(idx) == AutoIndentWriter.UNINDENT) {
|
||||
AutoIndentWriter.resolveTabs(lineGroups.remove(lineGroups.size() - 1));
|
||||
++idx;
|
||||
}
|
||||
if (line.charAt(idx) == AutoIndentWriter.CLEAR_TABULATORS) {
|
||||
List<StringBuilder> lg = lineGroups.get(lineGroups.size() - 1);
|
||||
AutoIndentWriter.resolveTabs(lg);
|
||||
lg.clear();
|
||||
line.deleteCharAt(idx);
|
||||
}
|
||||
for (int i = 0; i < line.length(); ++i) {
|
||||
if (line.charAt(i) == AutoIndentWriter.TABULATOR) {
|
||||
((List<StringBuilder>) lineGroups.get(lineGroups.size() - 1)).add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (List<StringBuilder> lg : lineGroups) AutoIndentWriter.resolveTabs(lg);
|
||||
int ind = this.tabulatorIndentation;
|
||||
for (StringBuilder sb : this.tabulatorBuffer) {
|
||||
String line = sb.toString();
|
||||
if (line.charAt(0) == AutoIndentWriter.INDENT) {
|
||||
++ind;
|
||||
line = line.substring(1);
|
||||
}
|
||||
if (line.charAt(0) == AutoIndentWriter.UNINDENT) {
|
||||
--ind;
|
||||
line = line.substring(1);
|
||||
}
|
||||
if ("\r\n".indexOf(line.charAt(0)) == -1) {
|
||||
for (int i = 0; i < ind; ++i) this.out.write(" ");
|
||||
}
|
||||
this.out.write(line.toString());
|
||||
}
|
||||
this.tabulatorBuffer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands all {@link #TABULATOR}s in the given {@link List} of {@link StringBuilder}s with
|
||||
* spaces, so that the characters immediately following the {@link #TABULATOR}s are vertically
|
||||
* aligned, like this:
|
||||
* <p>
|
||||
* Input:<pre>
|
||||
* a @b @c\r\n
|
||||
* aa @bb @cc\r\n
|
||||
* aaa @bbb @ccc\r\n</pre>Output:<pre>
|
||||
* a b c\r\n
|
||||
* aa bb cc\r\n
|
||||
* aaa bbb ccc\r\n</pre>
|
||||
*/
|
||||
private static void
|
||||
resolveTabs(List<StringBuilder> lineGroup) {
|
||||
|
||||
// Determine the tabulator offsets for this line group.
|
||||
List<Integer> tabulatorOffsets = new ArrayList<Integer>(); // 4, 4
|
||||
for (StringBuilder line : lineGroup) {
|
||||
int previousTab = 0;
|
||||
if (line.charAt(previousTab) == AutoIndentWriter.INDENT) ++previousTab;
|
||||
if (line.charAt(previousTab) == AutoIndentWriter.UNINDENT) ++previousTab;
|
||||
int tabCount = 0;
|
||||
for (int i = previousTab; i < line.length(); ++i) {
|
||||
if (line.charAt(i) == AutoIndentWriter.TABULATOR) {
|
||||
int tabOffset = i - previousTab;
|
||||
previousTab = i;
|
||||
if (tabCount >= tabulatorOffsets.size()) {
|
||||
tabulatorOffsets.add(new Integer(tabOffset));
|
||||
} else
|
||||
{
|
||||
if (tabOffset > ((Integer) tabulatorOffsets.get(tabCount)).intValue()) {
|
||||
tabulatorOffsets.set(tabCount, new Integer(tabOffset));
|
||||
}
|
||||
}
|
||||
++tabCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace tabulators with spaces.
|
||||
for (Iterator<StringBuilder> it = lineGroup.iterator(); it.hasNext();) {
|
||||
StringBuilder line = (StringBuilder) it.next();
|
||||
int tabCount = 0;
|
||||
int previousTab = 0;
|
||||
if (line.charAt(previousTab) == AutoIndentWriter.INDENT) ++previousTab;
|
||||
if (line.charAt(previousTab) == AutoIndentWriter.UNINDENT) ++previousTab;
|
||||
for (int i = previousTab; i < line.length(); ++i) {
|
||||
if (line.charAt(i) == AutoIndentWriter.TABULATOR) {
|
||||
int tabOffset = i - previousTab;
|
||||
int n = ((Integer) tabulatorOffsets.get(tabCount++)).intValue() - tabOffset;
|
||||
line.replace(i, i + 1, AutoIndentWriter.spaces(n));
|
||||
i += n - 1;
|
||||
previousTab = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return a {@link String} of <code>n</code> spaces */
|
||||
private static String
|
||||
spaces(int n) {
|
||||
if (n < 30) return " ".substring(0, n);
|
||||
char[] data = new char[n];
|
||||
Arrays.fill(data, ' ');
|
||||
return String.valueOf(data);
|
||||
}
|
||||
|
||||
@Override public void
|
||||
close() throws IOException {
|
||||
if (this.tabulatorBuffer != null) this.flushTabulatorBuffer();
|
||||
if (this.lineBuffer.length() > 0) this.line(this.lineBuffer.toString());
|
||||
this.out.close();
|
||||
}
|
||||
|
||||
@Override public void
|
||||
flush() throws IOException {
|
||||
if (this.tabulatorBuffer != null) this.flushTabulatorBuffer();
|
||||
if (this.lineBuffer.length() > 0) {
|
||||
this.line(this.lineBuffer.toString());
|
||||
this.lineBuffer.setLength(0);
|
||||
}
|
||||
this.out.flush();
|
||||
}
|
||||
}
|
197
src/org/codehaus/janino/util/Benchmark.java
Normal file
197
src/org/codehaus/janino/util/Benchmark.java
Normal file
|
@ -0,0 +1,197 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Implements a scheme for benchmarking, i.e. for determining and/or reporting the time elapsed
|
||||
* between the beginning and the end of an activity.
|
||||
* <p>
|
||||
* The measurement is done by invoking {@link #begin()} and later calling {@link #end()} whichs
|
||||
* returns the time elapsed since the call to {@link #begin()}.
|
||||
* <p>
|
||||
* Notice that calls to {@link #begin()} and {@link #end()} can be nested, and each call to
|
||||
* {@link #end()} refers to the matching {@link #begin()} call. To ensure that all calls match,
|
||||
* the preferred way to write a benchmark is
|
||||
* <pre>
|
||||
* ...
|
||||
* Benchmark b = new Benchmark();
|
||||
* ...
|
||||
* b.begin();
|
||||
* try {
|
||||
* ....
|
||||
* } finally {
|
||||
* long ms = b.end();
|
||||
* }
|
||||
* </pre>
|
||||
* This code layout also makes it visually easy to write correct pairs of {@link #begin()} /
|
||||
* {@link #end()} pairs.
|
||||
* <p>
|
||||
* The pair {@link #beginReporting()} and {@link #endReporting()} do basically the same, but
|
||||
* report the benchmarking information through an internal {@link Reporter} object. The default
|
||||
* {@link Reporter} prints its messages by <code>System.out.println()</code>.
|
||||
* <p>
|
||||
* Reporting is only enabled if the Benchmark object was created through {@link #Benchmark(boolean)}
|
||||
* with a <code>true</code> argument.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class Benchmark {
|
||||
private final Stack beginTimes = new Stack(); // Long
|
||||
|
||||
public
|
||||
Benchmark() {
|
||||
this.reportingEnabled = false;
|
||||
this.reporter = null;
|
||||
}
|
||||
|
||||
/** @see Benchmark */
|
||||
public void
|
||||
begin() { this.beginTimes.push(new Long(System.currentTimeMillis())); }
|
||||
|
||||
/** @see Benchmark */
|
||||
public long
|
||||
end() { return System.currentTimeMillis() - ((Long) this.beginTimes.pop()).longValue(); }
|
||||
|
||||
// Reporting-related methods and fields.
|
||||
|
||||
/** Sets up a {@link Benchmark} with a default {@link Reporter} that reports to {@code System.out}. */
|
||||
public
|
||||
Benchmark(boolean reportingEnabled) {
|
||||
this.reportingEnabled = reportingEnabled;
|
||||
this.reporter = new Reporter() {
|
||||
@Override public void report(String message) { System.out.println(message); }
|
||||
};
|
||||
}
|
||||
|
||||
/** Set up a {@link Benchmark} with a custom {@link Reporter}. */
|
||||
public
|
||||
Benchmark(boolean reportingEnabled, Reporter reporter) {
|
||||
this.reportingEnabled = reportingEnabled;
|
||||
this.reporter = reporter;
|
||||
}
|
||||
|
||||
private final boolean reportingEnabled;
|
||||
private final Reporter reporter;
|
||||
|
||||
/** Interface used to report messages. */
|
||||
public
|
||||
interface Reporter {
|
||||
|
||||
/** Reports the given {@code message}. */
|
||||
void report(String message);
|
||||
}
|
||||
|
||||
/** Begin a benchmark (see {@link #begin()}) and report the fact. */
|
||||
public void
|
||||
beginReporting() {
|
||||
if (!this.reportingEnabled) return;
|
||||
|
||||
this.reportIndented("Beginning...");
|
||||
this.begin();
|
||||
}
|
||||
|
||||
/** Begin a benchmark (see {@link #begin()}) and report the fact. */
|
||||
public void
|
||||
beginReporting(String message) {
|
||||
if (!this.reportingEnabled) return;
|
||||
this.reportIndented(message + "...");
|
||||
this.begin();
|
||||
}
|
||||
|
||||
/** End a benchmark (see {@link #end()}) and report the fact. */
|
||||
public void
|
||||
endReporting() {
|
||||
if (!this.reportingEnabled) return;
|
||||
this.reportIndented("... took " + this.end() + " ms");
|
||||
}
|
||||
|
||||
/** End a benchmark (see {@link #begin()}) and report the fact. */
|
||||
public void
|
||||
endReporting(String message) {
|
||||
if (!this.reportingEnabled) return;
|
||||
this.reportIndented("... took " + this.end() + " ms: " + message);
|
||||
}
|
||||
|
||||
/** Report the given message. */
|
||||
public void
|
||||
report(String message) {
|
||||
if (!this.reportingEnabled) return;
|
||||
this.reportIndented(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the <code>title</code>, a colon, a space, and the pretty-printed
|
||||
* {@link Object}.
|
||||
* @param optionalTitle
|
||||
* @param o
|
||||
*/
|
||||
public void
|
||||
report(String optionalTitle, Object o) {
|
||||
if (!this.reportingEnabled) return;
|
||||
|
||||
String prefix = optionalTitle == null ? "" : (
|
||||
optionalTitle
|
||||
+ ": "
|
||||
+ (optionalTitle.length() < Benchmark.PAD.length() ? Benchmark.PAD.substring(optionalTitle.length()) : "")
|
||||
);
|
||||
|
||||
if (o == null) {
|
||||
this.reportIndented(prefix + "(undefined)");
|
||||
} else
|
||||
if (o.getClass().isArray()) {
|
||||
Object[] oa = (Object[]) o;
|
||||
if (oa.length == 0) {
|
||||
this.reportIndented(prefix + "(empty)");
|
||||
} else
|
||||
if (oa.length == 1) {
|
||||
this.reportIndented(prefix + oa[0].toString());
|
||||
} else {
|
||||
this.reportIndented(optionalTitle == null ? "Array:" : optionalTitle + ':');
|
||||
this.begin();
|
||||
try {
|
||||
for (Object o2 : oa) this.report(null, o2);
|
||||
} finally {
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
this.reportIndented(prefix + o.toString());
|
||||
}
|
||||
}
|
||||
private static final String PAD = " ";
|
||||
|
||||
/** Report a message through {@link #reporter}, indent by N spaces where N is the current benchmark stack depth. */
|
||||
private void
|
||||
reportIndented(String message) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = this.beginTimes.size(); i > 0; --i) sb.append(" ");
|
||||
sb.append(message);
|
||||
this.reporter.report(sb.toString());
|
||||
}
|
||||
}
|
1838
src/org/codehaus/janino/util/ClassFile.java
Normal file
1838
src/org/codehaus/janino/util/ClassFile.java
Normal file
File diff suppressed because it is too large
Load Diff
144
src/org/codehaus/janino/util/MultiIterator.java
Normal file
144
src/org/codehaus/janino/util/MultiIterator.java
Normal file
|
@ -0,0 +1,144 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.codehaus.janino.JaninoRuntimeException;
|
||||
|
||||
/**
|
||||
* An {@link java.util.Iterator} that traverses a {@link java.util.Collection} of {@link java.util.Iterator}s.
|
||||
*
|
||||
* @param <T> The element type of the iterator
|
||||
*/
|
||||
@SuppressWarnings("unchecked") public
|
||||
class MultiIterator<T> implements Iterator<T> {
|
||||
|
||||
private static final Iterator<?> AT_END = new Iterator<Object>() {
|
||||
@Override public boolean hasNext() { return false; }
|
||||
@Override public Object next() { throw new NoSuchElementException(); }
|
||||
@Override public void remove() { throw new UnsupportedOperationException(); }
|
||||
};
|
||||
|
||||
private final Iterator<?> outer; // Over Iterators, Collections or arrays
|
||||
private Iterator<T> inner = (Iterator<T>) MultiIterator.AT_END;
|
||||
|
||||
/** @param iterators An array of {@link Iterator}s */
|
||||
public
|
||||
MultiIterator(Iterator<T>[] iterators) { this.outer = Arrays.asList(iterators).iterator(); }
|
||||
|
||||
/** @param collections An array of {@link Collection}s */
|
||||
public
|
||||
MultiIterator(Collection<T>[] collections) { this.outer = Arrays.asList(collections).iterator(); }
|
||||
|
||||
/** @param arrays An array of arrays */
|
||||
public
|
||||
MultiIterator(Object/*T*/[][] arrays) { this.outer = Arrays.asList(arrays).iterator(); }
|
||||
|
||||
/** @param collection A {@link Collection} of {@link Collection}s, {@link Iterator}s and/or arrays */
|
||||
public
|
||||
MultiIterator(Collection<?> collection) { this.outer = collection.iterator(); }
|
||||
|
||||
/** @param iterator An iterator over {@link Collection}s, {@link Iterator}s and/or arrays */
|
||||
public
|
||||
MultiIterator(Iterator<?> iterator) { this.outer = iterator; }
|
||||
|
||||
/** @param array An array of {@link Collection}s, {@link Iterator}s and/or arrays */
|
||||
public
|
||||
MultiIterator(Object[] array) { this.outer = Arrays.asList(array).iterator(); }
|
||||
|
||||
/** Iterates over the given {@link Collection}, prepended with the given {@link Object}. */
|
||||
public
|
||||
MultiIterator(Object/*T*/ object, Collection<T> collection) {
|
||||
this.outer = Arrays.asList(new Object[] {
|
||||
new Object[] { object },
|
||||
collection
|
||||
}).iterator();
|
||||
}
|
||||
|
||||
/** Iterates over the given {@link Collection}, appended with the given {@link Object}. */
|
||||
public
|
||||
MultiIterator(Collection<T> collection, Object/*T*/ object) {
|
||||
this.outer = Arrays.asList(new Object[] {
|
||||
collection,
|
||||
new Object[] { object }
|
||||
}).iterator();
|
||||
}
|
||||
|
||||
/** Iterates over the given {@link Iterator}, prepended with the given {@code prefix}. */
|
||||
public
|
||||
MultiIterator(Object/*T*/ prefix, Iterator<T> iterator) {
|
||||
this.outer = Arrays.asList(new Object[] {
|
||||
new Object[] { prefix },
|
||||
iterator
|
||||
}).iterator();
|
||||
}
|
||||
|
||||
/** Iterates over the given {@link Iterator}, appended with the given <code>suffix</code>. */
|
||||
public
|
||||
MultiIterator(Iterator<T> iterator, Object/*T*/ suffix) {
|
||||
this.outer = Arrays.asList(new Object[] {
|
||||
iterator,
|
||||
new Object[] { suffix }
|
||||
}).iterator();
|
||||
}
|
||||
|
||||
@Override public boolean
|
||||
hasNext() {
|
||||
for (;;) {
|
||||
if (this.inner.hasNext()) return true;
|
||||
if (!this.outer.hasNext()) return false;
|
||||
Object o = this.outer.next();
|
||||
if (o instanceof Iterator) {
|
||||
this.inner = (Iterator<T>) o;
|
||||
} else
|
||||
if (o instanceof Collection) {
|
||||
this.inner = ((Collection<T>) o).iterator();
|
||||
} else
|
||||
if (o instanceof Object[]) {
|
||||
this.inner = Arrays.asList((T[]) o).iterator();
|
||||
} else
|
||||
{
|
||||
throw new JaninoRuntimeException("Unexpected element type \"" + o.getClass().getName() + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public T
|
||||
next() {
|
||||
if (this.hasNext()) return this.inner.next();
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override public void
|
||||
remove() {
|
||||
this.inner.remove();
|
||||
}
|
||||
}
|
51
src/org/codehaus/janino/util/Producer.java
Normal file
51
src/org/codehaus/janino/util/Producer.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
/**
|
||||
* An object that produces some {@link java.lang.Object} each time the
|
||||
* {@link #produce()} method is invoked. This behavior is similar to the
|
||||
* {@link java.util.Iterator}, but is represented by one single
|
||||
* {@link #produce()} method as opposed to {@link java.util.Iterator}'s
|
||||
* two methods {@link java.util.Iterator#hasNext()} and
|
||||
* {@link java.util.Iterator#next()}. This simplifies the implementation of
|
||||
* certain complex iterations.
|
||||
*
|
||||
* @param <T> The type of the products
|
||||
* @see org.codehaus.janino.util.iterator.DirectoryIterator
|
||||
* @see org.codehaus.janino.util.iterator.ProducerIterator
|
||||
*/
|
||||
public
|
||||
interface Producer<T> {
|
||||
|
||||
/**
|
||||
* Produce the next object.
|
||||
*
|
||||
* @return the next object or <code>null</code> to indicate that no more objects can be produced
|
||||
*/
|
||||
T produce();
|
||||
}
|
107
src/org/codehaus/janino/util/ResourceFinderClassLoader.java
Normal file
107
src/org/codehaus/janino/util/ResourceFinderClassLoader.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.codehaus.janino.JaninoRuntimeException;
|
||||
import org.codehaus.janino.util.resource.Resource;
|
||||
import org.codehaus.janino.util.resource.ResourceFinder;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link ClassLoader} that uses a {@link org.codehaus.janino.util.resource.ResourceFinder} to find ".class" files.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class ResourceFinderClassLoader extends ClassLoader {
|
||||
|
||||
private final ResourceFinder resourceFinder;
|
||||
|
||||
public
|
||||
ResourceFinderClassLoader(ResourceFinder resourceFinder, ClassLoader parent) {
|
||||
super(parent);
|
||||
this.resourceFinder = resourceFinder;
|
||||
}
|
||||
|
||||
/** @return The underlying {@link ResourceFinder} */
|
||||
public ResourceFinder
|
||||
getResourceFinder() { return this.resourceFinder; }
|
||||
|
||||
@Override protected Class
|
||||
findClass(String className) throws ClassNotFoundException {
|
||||
|
||||
// Find the resource containing the class bytecode.
|
||||
Resource classFileResource = this.resourceFinder.findResource(ClassFile.getClassFileResourceName(className));
|
||||
if (classFileResource == null) throw new ClassNotFoundException(className);
|
||||
|
||||
// Open the class file resource.
|
||||
InputStream is;
|
||||
try {
|
||||
is = classFileResource.open();
|
||||
} catch (IOException ex) {
|
||||
throw new JaninoRuntimeException((
|
||||
"Opening class file resource \""
|
||||
+ classFileResource.getFileName()
|
||||
+ "\": "
|
||||
+ ex.getMessage()
|
||||
), ex);
|
||||
}
|
||||
|
||||
// Read bytecode from the resource into a byte array.
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
byte[] buffer = new byte[4096];
|
||||
for (;;) {
|
||||
int bytesRead = is.read(buffer);
|
||||
if (bytesRead == -1) break;
|
||||
baos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new ClassNotFoundException("Reading class file from \"" + classFileResource + "\"", ex);
|
||||
} finally {
|
||||
try { is.close(); } catch (IOException ex) {}
|
||||
}
|
||||
byte[] ba = baos.toByteArray();
|
||||
|
||||
// Define the class in this ClassLoader.
|
||||
Class clazz = super.defineClass(null, ba, 0, ba.length);
|
||||
|
||||
if (!clazz.getName().equals(className)) {
|
||||
|
||||
// This is a really complicated case: We may find a class file on
|
||||
// the class path that seemingly defines the class we are looking
|
||||
// for, but doesn't. This is possible if the underlying file system
|
||||
// has case-insensitive file names and/or file names that are
|
||||
// limited in length (e.g. DOS 8.3).
|
||||
throw new ClassNotFoundException(className);
|
||||
}
|
||||
|
||||
return clazz;
|
||||
}
|
||||
}
|
195
src/org/codehaus/janino/util/StringPattern.java
Normal file
195
src/org/codehaus/janino/util/StringPattern.java
Normal file
|
@ -0,0 +1,195 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of a UNIX shell-like string pattern algorithm.
|
||||
* <p>
|
||||
* Additionally, the concept of the "combined pattern" is supported (see
|
||||
* {@link #matches(StringPattern[], String)}.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class StringPattern {
|
||||
|
||||
/** @see #matches(StringPattern[], String) */
|
||||
public static final int INCLUDE = 0;
|
||||
|
||||
/** @see #matches(StringPattern[], String) */
|
||||
public static final int EXCLUDE = 1;
|
||||
|
||||
private final int mode;
|
||||
private final String pattern;
|
||||
|
||||
/** @param mode {@link #INCLUDE} or {@link #EXCLUDE} */
|
||||
public
|
||||
StringPattern(int mode, String pattern) {
|
||||
this.mode = mode;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public
|
||||
StringPattern(String pattern) {
|
||||
this.mode = StringPattern.INCLUDE;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this {@link StringPattern} represents <i>inclusion</i> ({@link #INCLUDE}) or <i>exclusion</i>
|
||||
* exclusion ({@link #EXCLUDE}) of subjects
|
||||
*/
|
||||
public int
|
||||
getMode() { return this.mode; }
|
||||
|
||||
/**
|
||||
* Match the given <code>text</code> against the pattern represented by the current instance,
|
||||
* as follows:
|
||||
* <ul>
|
||||
* <li>
|
||||
* A <code>*</code> in the pattern matches any sequence of zero or more characters in the
|
||||
* <code>text</code>
|
||||
* </li>
|
||||
* <li>
|
||||
* A <code>?</code> in the pattern matches exactly one character in the <code>text</code>
|
||||
* </li>
|
||||
* <li>
|
||||
* Any other character in the pattern must appear exactly as it is in the <code>text</code>
|
||||
* </ul>
|
||||
* Notice: The <code>mode</code> flag of the current instance does not take any effect here.
|
||||
*/
|
||||
public boolean
|
||||
matches(String text) { return StringPattern.wildmatch(this.pattern, text); }
|
||||
|
||||
/**
|
||||
* Parse a "combined pattern" into an array of {@link StringPattern}s. A combined pattern
|
||||
* string is structured as follows:
|
||||
* <pre>
|
||||
* combined-pattern :=
|
||||
* [ '+' | '-' ] pattern
|
||||
* { ( '+' | '-' ) pattern }
|
||||
* </pre>
|
||||
* If a pattern is preceeded with a '-', then the {@link StringPattern} is created with mode
|
||||
* {@link #EXCLUDE}, otherwise with mode {@link #INCLUDE}.
|
||||
*/
|
||||
public static StringPattern[]
|
||||
parseCombinedPattern(String combinedPattern) {
|
||||
List<StringPattern> al = new ArrayList();
|
||||
for (int k = 0, l; k < combinedPattern.length(); k = l) {
|
||||
int patternMode;
|
||||
char c = combinedPattern.charAt(k);
|
||||
if (c == '+') {
|
||||
patternMode = StringPattern.INCLUDE;
|
||||
++k;
|
||||
} else
|
||||
if (c == '-') {
|
||||
patternMode = StringPattern.EXCLUDE;
|
||||
++k;
|
||||
} else {
|
||||
patternMode = StringPattern.INCLUDE;
|
||||
}
|
||||
for (l = k; l < combinedPattern.length(); ++l) {
|
||||
c = combinedPattern.charAt(l);
|
||||
if (c == '+' || c == '-') break;
|
||||
}
|
||||
al.add(new StringPattern(patternMode, combinedPattern.substring(k, l)));
|
||||
}
|
||||
return (StringPattern[]) al.toArray(new StringPattern[al.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a given <code>text</code> against an array of {@link StringPattern}s (which was
|
||||
* typically created by {@link #parseCombinedPattern(String)}.
|
||||
* <p>
|
||||
* The last matching pattern takes effect; if its mode is {@link #INCLUDE}, then
|
||||
* <code>true</code> is returned, if its mode is {@link #EXCLUDE}, then <code>false</code> is
|
||||
* returned.
|
||||
* <p>
|
||||
* If <code>patterns</code> is {@link #PATTERNS_NONE}, or empty, or none of its patterns
|
||||
* matches, then <code>false</code> is returned.
|
||||
* <p>
|
||||
* If <code>patterns</code> is {@link #PATTERNS_ALL}, then <code>true</code> is
|
||||
* returned.
|
||||
* <p>
|
||||
* For backwards compatibility, <code>null</code> patterns are treated like
|
||||
* {@link #PATTERNS_NONE}.
|
||||
*/
|
||||
public static boolean
|
||||
matches(StringPattern[] patterns, String text) {
|
||||
if (patterns == null) return false; // Backwards compatibility -- previously, "null" was officially documented.
|
||||
|
||||
for (int i = patterns.length - 1; i >= 0; --i) {
|
||||
if (patterns[i].matches(text)) {
|
||||
return patterns[i].getMode() == StringPattern.INCLUDE;
|
||||
}
|
||||
}
|
||||
return false; // No patterns defined or no pattern matches.
|
||||
}
|
||||
|
||||
/** A {@link StringPattern} that matches any subject. */
|
||||
public static final StringPattern[] PATTERNS_ALL = new StringPattern[] { new StringPattern("*") };
|
||||
/** A {@link StringPattern} that matches no subject whatsoever. */
|
||||
public static final StringPattern[] PATTERNS_NONE = new StringPattern[0];
|
||||
|
||||
@Override public String
|
||||
toString() {
|
||||
return (
|
||||
this.mode == StringPattern.INCLUDE ? '+' :
|
||||
this.mode == StringPattern.EXCLUDE ? '-' :
|
||||
'?'
|
||||
) + this.pattern;
|
||||
}
|
||||
|
||||
private static boolean
|
||||
wildmatch(String pattern, String text) {
|
||||
int i;
|
||||
for (i = 0; i < pattern.length(); ++i) {
|
||||
char c = pattern.charAt(i);
|
||||
switch (c) {
|
||||
|
||||
case '?':
|
||||
if (i == text.length()) return false;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (pattern.length() == i + 1) return true; // Optimization for trailing '*'.
|
||||
pattern = pattern.substring(i + 1);
|
||||
for (; i <= text.length(); ++i) {
|
||||
if (StringPattern.wildmatch(pattern, text.substring(i))) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (i == text.length()) return false;
|
||||
if (text.charAt(i) != c) return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return text.length() == i;
|
||||
}
|
||||
}
|
85
src/org/codehaus/janino/util/TeeReader.java
Normal file
85
src/org/codehaus/janino/util/TeeReader.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import java.io.FilterReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* A {@link java.io.FilterReader} that copies the bytes being passed through
|
||||
* to a given {@link java.io.Writer}. This is in analogy with the UNIX "tee" command.
|
||||
*/
|
||||
public
|
||||
class TeeReader extends FilterReader {
|
||||
private final Writer out;
|
||||
private final boolean closeWriterOnEOF;
|
||||
|
||||
public
|
||||
TeeReader(Reader in, Writer out, boolean closeWriterOnEof) {
|
||||
super(in);
|
||||
this.out = out;
|
||||
this.closeWriterOnEOF = closeWriterOnEof;
|
||||
}
|
||||
|
||||
@Override public void
|
||||
close() throws IOException {
|
||||
this.in.close();
|
||||
this.out.close();
|
||||
}
|
||||
|
||||
@Override public int
|
||||
read() throws IOException {
|
||||
int c = this.in.read();
|
||||
if (c == -1) {
|
||||
if (this.closeWriterOnEOF) {
|
||||
this.out.close();
|
||||
} else {
|
||||
this.out.flush();
|
||||
}
|
||||
} else {
|
||||
this.out.write(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override public int
|
||||
read(char[] cbuf, int off, int len) throws IOException {
|
||||
int bytesRead = this.in.read(cbuf, off, len);
|
||||
if (bytesRead == -1) {
|
||||
if (this.closeWriterOnEOF) {
|
||||
this.out.close();
|
||||
} else {
|
||||
this.out.flush();
|
||||
}
|
||||
} else {
|
||||
this.out.write(cbuf, off, bytesRead);
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
798
src/org/codehaus/janino/util/Traverser.java
Normal file
798
src/org/codehaus/janino/util/Traverser.java
Normal file
|
@ -0,0 +1,798 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util;
|
||||
|
||||
import org.codehaus.janino.JaninoRuntimeException;
|
||||
import org.codehaus.janino.Java;
|
||||
import org.codehaus.janino.Java.Rvalue;
|
||||
import org.codehaus.janino.Visitor;
|
||||
import org.codehaus.janino.Visitor.ComprehensiveVisitor;
|
||||
|
||||
/**
|
||||
* This class traverses the subnodes of an AST. Derived classes may override
|
||||
* individual methods to process specific nodes, e.g.:<pre>
|
||||
* LocalClassDeclaration lcd = ...;
|
||||
* lcd.accept(new Traverser() {
|
||||
* int n = 0;
|
||||
* public void traverseMethodDeclarator(Java.MethodDeclarator md) {
|
||||
* ++this.n;
|
||||
* super.traverseMethodDeclarator(md);
|
||||
* }
|
||||
* }.comprehensiveVisitor());</pre>
|
||||
*/
|
||||
public
|
||||
class Traverser {
|
||||
|
||||
private final Visitor.ComprehensiveVisitor cv = new Visitor.ComprehensiveVisitor() {
|
||||
// CHECKSTYLE LineLengthCheck:OFF
|
||||
@Override public void visitSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid) { Traverser.this.traverseSingleTypeImportDeclaration(stid); }
|
||||
@Override public void visitTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd) { Traverser.this.traverseTypeImportOnDemandDeclaration(tiodd); }
|
||||
@Override public void visitSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration ssid) { Traverser.this.traverseSingleStaticImportDeclaration(ssid); }
|
||||
@Override public void visitStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd) { Traverser.this.traverseStaticImportOnDemandDeclaration(siodd); }
|
||||
@Override public void visitAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) { Traverser.this.traverseAnonymousClassDeclaration(acd); }
|
||||
@Override public void visitLocalClassDeclaration(Java.LocalClassDeclaration lcd) { Traverser.this.traverseLocalClassDeclaration(lcd); }
|
||||
@Override public void visitPackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd) { Traverser.this.traversePackageMemberClassDeclaration(pmcd); }
|
||||
@Override public void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid) { Traverser.this.traverseMemberInterfaceDeclaration(mid); }
|
||||
@Override public void visitPackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid) { Traverser.this.traversePackageMemberInterfaceDeclaration(pmid); }
|
||||
@Override public void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd) { Traverser.this.traverseMemberClassDeclaration(mcd); }
|
||||
@Override public void visitConstructorDeclarator(Java.ConstructorDeclarator cd) { Traverser.this.traverseConstructorDeclarator(cd); }
|
||||
@Override public void visitInitializer(Java.Initializer i) { Traverser.this.traverseInitializer(i); }
|
||||
@Override public void visitMethodDeclarator(Java.MethodDeclarator md) { Traverser.this.traverseMethodDeclarator(md); }
|
||||
@Override public void visitFieldDeclaration(Java.FieldDeclaration fd) { Traverser.this.traverseFieldDeclaration(fd); }
|
||||
@Override public void visitLabeledStatement(Java.LabeledStatement ls) { Traverser.this.traverseLabeledStatement(ls); }
|
||||
@Override public void visitBlock(Java.Block b) { Traverser.this.traverseBlock(b); }
|
||||
@Override public void visitExpressionStatement(Java.ExpressionStatement es) { Traverser.this.traverseExpressionStatement(es); }
|
||||
@Override public void visitIfStatement(Java.IfStatement is) { Traverser.this.traverseIfStatement(is); }
|
||||
@Override public void visitForStatement(Java.ForStatement fs) { Traverser.this.traverseForStatement(fs); }
|
||||
@Override public void visitForEachStatement(Java.ForEachStatement fes) { Traverser.this.traverseForEachStatement(fes); }
|
||||
@Override public void visitWhileStatement(Java.WhileStatement ws) { Traverser.this.traverseWhileStatement(ws); }
|
||||
@Override public void visitTryStatement(Java.TryStatement ts) { Traverser.this.traverseTryStatement(ts); }
|
||||
@Override public void visitSwitchStatement(Java.SwitchStatement ss) { Traverser.this.traverseSwitchStatement(ss); }
|
||||
@Override public void visitSynchronizedStatement(Java.SynchronizedStatement ss) { Traverser.this.traverseSynchronizedStatement(ss); }
|
||||
@Override public void visitDoStatement(Java.DoStatement ds) { Traverser.this.traverseDoStatement(ds); }
|
||||
@Override public void visitLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) { Traverser.this.traverseLocalVariableDeclarationStatement(lvds); }
|
||||
@Override public void visitReturnStatement(Java.ReturnStatement rs) { Traverser.this.traverseReturnStatement(rs); }
|
||||
@Override public void visitThrowStatement(Java.ThrowStatement ts) { Traverser.this.traverseThrowStatement(ts); }
|
||||
@Override public void visitBreakStatement(Java.BreakStatement bs) { Traverser.this.traverseBreakStatement(bs); }
|
||||
@Override public void visitContinueStatement(Java.ContinueStatement cs) { Traverser.this.traverseContinueStatement(cs); }
|
||||
@Override public void visitAssertStatement(Java.AssertStatement as) { Traverser.this.traverseAssertStatement(as); }
|
||||
@Override public void visitEmptyStatement(Java.EmptyStatement es) { Traverser.this.traverseEmptyStatement(es); }
|
||||
@Override public void visitLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds) { Traverser.this.traverseLocalClassDeclarationStatement(lcds); }
|
||||
@Override public void visitPackage(Java.Package p) { Traverser.this.traversePackage(p); }
|
||||
@Override public void visitArrayLength(Java.ArrayLength al) { Traverser.this.traverseArrayLength(al); }
|
||||
@Override public void visitAssignment(Java.Assignment a) { Traverser.this.traverseAssignment(a); }
|
||||
@Override public void visitUnaryOperation(Java.UnaryOperation uo) { Traverser.this.traverseUnaryOperation(uo); }
|
||||
@Override public void visitBinaryOperation(Java.BinaryOperation bo) { Traverser.this.traverseBinaryOperation(bo); }
|
||||
@Override public void visitCast(Java.Cast c) { Traverser.this.traverseCast(c); }
|
||||
@Override public void visitClassLiteral(Java.ClassLiteral cl) { Traverser.this.traverseClassLiteral(cl); }
|
||||
@Override public void visitConditionalExpression(Java.ConditionalExpression ce) { Traverser.this.traverseConditionalExpression(ce); }
|
||||
@Override public void visitCrement(Java.Crement c) { Traverser.this.traverseCrement(c); }
|
||||
@Override public void visitInstanceof(Java.Instanceof io) { Traverser.this.traverseInstanceof(io); }
|
||||
@Override public void visitMethodInvocation(Java.MethodInvocation mi) { Traverser.this.traverseMethodInvocation(mi); }
|
||||
@Override public void visitSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi) { Traverser.this.traverseSuperclassMethodInvocation(smi); }
|
||||
@Override public void visitIntegerLiteral(Java.IntegerLiteral il) { Traverser.this.traverseIntegerLiteral(il); }
|
||||
@Override public void visitFloatingPointLiteral(Java.FloatingPointLiteral fpl) { Traverser.this.traverseFloatingPointLiteral(fpl); }
|
||||
@Override public void visitBooleanLiteral(Java.BooleanLiteral bl) { Traverser.this.traverseBooleanLiteral(bl); }
|
||||
@Override public void visitCharacterLiteral(Java.CharacterLiteral cl) { Traverser.this.traverseCharacterLiteral(cl); }
|
||||
@Override public void visitStringLiteral(Java.StringLiteral sl) { Traverser.this.traverseStringLiteral(sl); }
|
||||
@Override public void visitNullLiteral(Java.NullLiteral nl) { Traverser.this.traverseNullLiteral(nl); }
|
||||
@Override public void visitSimpleConstant(Java.SimpleConstant sl) { Traverser.this.traverseSimpleLiteral(sl); }
|
||||
@Override public void visitNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci) { Traverser.this.traverseNewAnonymousClassInstance(naci); }
|
||||
@Override public void visitNewArray(Java.NewArray na) { Traverser.this.traverseNewArray(na); }
|
||||
@Override public void visitNewInitializedArray(Java.NewInitializedArray nia) { Traverser.this.traverseNewInitializedArray(nia); }
|
||||
@Override public void visitNewClassInstance(Java.NewClassInstance nci) { Traverser.this.traverseNewClassInstance(nci); }
|
||||
@Override public void visitParameterAccess(Java.ParameterAccess pa) { Traverser.this.traverseParameterAccess(pa); }
|
||||
@Override public void visitQualifiedThisReference(Java.QualifiedThisReference qtr) { Traverser.this.traverseQualifiedThisReference(qtr); }
|
||||
@Override public void visitThisReference(Java.ThisReference tr) { Traverser.this.traverseThisReference(tr); }
|
||||
@Override public void visitArrayType(Java.ArrayType at) { Traverser.this.traverseArrayType(at); }
|
||||
@Override public void visitBasicType(Java.BasicType bt) { Traverser.this.traverseBasicType(bt); }
|
||||
@Override public void visitReferenceType(Java.ReferenceType rt) { Traverser.this.traverseReferenceType(rt); }
|
||||
@Override public void visitRvalueMemberType(Java.RvalueMemberType rmt) { Traverser.this.traverseRvalueMemberType(rmt); }
|
||||
@Override public void visitSimpleType(Java.SimpleType st) { Traverser.this.traverseSimpleType(st); }
|
||||
@Override public void visitAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci) { Traverser.this.traverseAlternateConstructorInvocation(aci); }
|
||||
@Override public void visitSuperConstructorInvocation(Java.SuperConstructorInvocation sci) { Traverser.this.traverseSuperConstructorInvocation(sci); }
|
||||
@Override public void visitAmbiguousName(Java.AmbiguousName an) { Traverser.this.traverseAmbiguousName(an); }
|
||||
@Override public void visitArrayAccessExpression(Java.ArrayAccessExpression aae) { Traverser.this.traverseArrayAccessExpression(aae); }
|
||||
@Override public void visitFieldAccess(Java.FieldAccess fa) { Traverser.this.traverseFieldAccess(fa); }
|
||||
@Override public void visitFieldAccessExpression(Java.FieldAccessExpression fae) { Traverser.this.traverseFieldAccessExpression(fae); }
|
||||
@Override public void visitSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae) { Traverser.this.traverseSuperclassFieldAccessExpression(scfae); }
|
||||
@Override public void visitLocalVariableAccess(Java.LocalVariableAccess lva) { Traverser.this.traverseLocalVariableAccess(lva); }
|
||||
@Override public void visitParenthesizedExpression(Java.ParenthesizedExpression pe) { Traverser.this.traverseParenthesizedExpression(pe); }
|
||||
@Override public void visitMarkerAnnotation(Java.MarkerAnnotation ma) { Traverser.this.traverseMarkerAnnotation(ma); }
|
||||
@Override public void visitNormalAnnotation(Java.NormalAnnotation na) { Traverser.this.traverseNormalAnnotation(na); }
|
||||
@Override public void visitSingleElementAnnotation(Java.SingleElementAnnotation sea) { Traverser.this.traverseSingleElementAnnotation(sea); }
|
||||
@Override public void visitElementValueArrayInitializer(Java.ElementValueArrayInitializer evai) { Traverser.this.traverseElementValueArrayInitializer(evai); }
|
||||
// CHECKSTYLE LineLengthCheck:ON
|
||||
};
|
||||
|
||||
/** @see Traverser */
|
||||
public ComprehensiveVisitor
|
||||
comprehensiveVisitor() { return this.cv; }
|
||||
|
||||
// These may be overridden by derived classes.
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseCompilationUnit(Java.CompilationUnit cu) {
|
||||
|
||||
// The optionalPackageDeclaration is considered an integral part of
|
||||
// the compilation unit and is thus not traversed.
|
||||
|
||||
for (Java.CompilationUnit.ImportDeclaration id : cu.importDeclarations) id.accept(this.cv);
|
||||
for (Java.PackageMemberTypeDeclaration pmtd : cu.packageMemberTypeDeclarations) pmtd.accept(this.cv);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid) {
|
||||
this.traverseImportDeclaration(stid);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd) {
|
||||
this.traverseImportDeclaration(tiodd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration stid) {
|
||||
this.traverseImportDeclaration(stid);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd) {
|
||||
this.traverseImportDeclaration(siodd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseImportDeclaration(Java.CompilationUnit.ImportDeclaration id) { this.traverseLocated(id); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) {
|
||||
acd.baseType.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseClassDeclaration(acd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLocalClassDeclaration(Java.LocalClassDeclaration lcd) { this.traverseNamedClassDeclaration(lcd); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traversePackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd) {
|
||||
this.traverseNamedClassDeclaration(pmcd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid) { this.traverseInterfaceDeclaration(mid); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traversePackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid) {
|
||||
this.traverseInterfaceDeclaration(pmid);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseMemberClassDeclaration(Java.MemberClassDeclaration mcd) { this.traverseNamedClassDeclaration(mcd); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseConstructorDeclarator(Java.ConstructorDeclarator cd) {
|
||||
if (cd.optionalConstructorInvocation != null) {
|
||||
cd.optionalConstructorInvocation.accept((Visitor.BlockStatementVisitor) this.cv);
|
||||
}
|
||||
this.traverseFunctionDeclarator(cd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseInitializer(Java.Initializer i) {
|
||||
i.block.accept(this.cv);
|
||||
this.traverseAbstractTypeBodyDeclaration(i);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseMethodDeclarator(Java.MethodDeclarator md) { this.traverseFunctionDeclarator(md); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFieldDeclaration(Java.FieldDeclaration fd) {
|
||||
fd.type.accept((Visitor.TypeVisitor) this.cv);
|
||||
for (Java.VariableDeclarator vd : fd.variableDeclarators) {
|
||||
Java.ArrayInitializerOrRvalue optionalInitializer = vd.optionalInitializer;
|
||||
if (optionalInitializer != null) this.traverseArrayInitializerOrRvalue(optionalInitializer);
|
||||
}
|
||||
this.traverseStatement(fd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLabeledStatement(Java.LabeledStatement ls) {
|
||||
ls.body.accept(this.cv);
|
||||
this.traverseBreakableStatement(ls);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBlock(Java.Block b) {
|
||||
for (Java.BlockStatement bs : b.statements) bs.accept(this.cv);
|
||||
this.traverseStatement(b);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseExpressionStatement(Java.ExpressionStatement es) {
|
||||
es.rvalue.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseStatement(es);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseIfStatement(Java.IfStatement is) {
|
||||
is.condition.accept((Visitor.RvalueVisitor) this.cv);
|
||||
is.thenStatement.accept(this.cv);
|
||||
if (is.optionalElseStatement != null) is.optionalElseStatement.accept(this.cv);
|
||||
this.traverseStatement(is);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseForStatement(Java.ForStatement fs) {
|
||||
if (fs.optionalInit != null) fs.optionalInit.accept(this.cv);
|
||||
if (fs.optionalCondition != null) fs.optionalCondition.accept((Visitor.RvalueVisitor) this.cv);
|
||||
if (fs.optionalUpdate != null) {
|
||||
for (Java.Rvalue rv : fs.optionalUpdate) rv.accept((Visitor.RvalueVisitor) this.cv);
|
||||
}
|
||||
fs.body.accept(this.cv);
|
||||
this.traverseContinuableStatement(fs);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseForEachStatement(Java.ForEachStatement fes) {
|
||||
this.traverseFormalParameter(fes.currentElement);
|
||||
fes.expression.accept((Visitor.RvalueVisitor) this.cv);
|
||||
fes.body.accept(this.cv);
|
||||
this.traverseContinuableStatement(fes);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseWhileStatement(Java.WhileStatement ws) {
|
||||
ws.condition.accept((Visitor.RvalueVisitor) this.cv);
|
||||
ws.body.accept(this.cv);
|
||||
this.traverseContinuableStatement(ws);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseTryStatement(Java.TryStatement ts) {
|
||||
ts.body.accept(this.cv);
|
||||
for (Java.CatchClause cc : ts.catchClauses) cc.body.accept(this.cv);
|
||||
if (ts.optionalFinally != null) ts.optionalFinally.accept(this.cv);
|
||||
this.traverseStatement(ts);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSwitchStatement(Java.SwitchStatement ss) {
|
||||
ss.condition.accept((Visitor.RvalueVisitor) this.cv);
|
||||
for (Java.SwitchStatement.SwitchBlockStatementGroup sbsg : ss.sbsgs) {
|
||||
for (Java.Rvalue cl : sbsg.caseLabels) cl.accept((Visitor.RvalueVisitor) this.cv);
|
||||
for (Java.BlockStatement bs : sbsg.blockStatements) bs.accept(this.cv);
|
||||
this.traverseLocated(sbsg);
|
||||
}
|
||||
this.traverseBreakableStatement(ss);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSynchronizedStatement(Java.SynchronizedStatement ss) {
|
||||
ss.expression.accept((Visitor.RvalueVisitor) this.cv);
|
||||
ss.body.accept(this.cv);
|
||||
this.traverseStatement(ss);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseDoStatement(Java.DoStatement ds) {
|
||||
ds.body.accept(this.cv);
|
||||
ds.condition.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseContinuableStatement(ds);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
|
||||
lvds.type.accept((Visitor.TypeVisitor) this.cv);
|
||||
for (Java.VariableDeclarator vd : lvds.variableDeclarators) {
|
||||
Java.ArrayInitializerOrRvalue optionalInitializer = vd.optionalInitializer;
|
||||
if (optionalInitializer != null) this.traverseArrayInitializerOrRvalue(optionalInitializer);
|
||||
}
|
||||
this.traverseStatement(lvds);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseReturnStatement(Java.ReturnStatement rs) {
|
||||
if (rs.optionalReturnValue != null) rs.optionalReturnValue.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseStatement(rs);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseThrowStatement(Java.ThrowStatement ts) {
|
||||
ts.expression.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseStatement(ts);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBreakStatement(Java.BreakStatement bs) { this.traverseStatement(bs); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseContinueStatement(Java.ContinueStatement cs) { this.traverseStatement(cs); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAssertStatement(Java.AssertStatement as) {
|
||||
as.expression1.accept((Visitor.RvalueVisitor) this.cv);
|
||||
if (as.optionalExpression2 != null) as.optionalExpression2.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseStatement(as);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseEmptyStatement(Java.EmptyStatement es) { this.traverseStatement(es); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds) {
|
||||
lcds.lcd.accept(this.cv);
|
||||
this.traverseStatement(lcds);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traversePackage(Java.Package p) { this.traverseAtom(p); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseArrayLength(Java.ArrayLength al) {
|
||||
al.lhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(al);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAssignment(Java.Assignment a) {
|
||||
a.lhs.accept((Visitor.LvalueVisitor) this.cv);
|
||||
a.rhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(a);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseUnaryOperation(Java.UnaryOperation uo) {
|
||||
uo.operand.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseBooleanRvalue(uo);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBinaryOperation(Java.BinaryOperation bo) {
|
||||
bo.lhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
bo.rhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseBooleanRvalue(bo);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseCast(Java.Cast c) {
|
||||
c.targetType.accept((Visitor.TypeVisitor) this.cv);
|
||||
c.value.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(c);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseClassLiteral(Java.ClassLiteral cl) {
|
||||
cl.type.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseRvalue(cl);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseConditionalExpression(Java.ConditionalExpression ce) {
|
||||
ce.lhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
ce.mhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
ce.rhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(ce);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseCrement(Java.Crement c) {
|
||||
c.operand.accept((Visitor.LvalueVisitor) this.cv);
|
||||
this.traverseRvalue(c);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseInstanceof(Java.Instanceof io) {
|
||||
io.lhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
io.rhs.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseRvalue(io);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseMethodInvocation(Java.MethodInvocation mi) {
|
||||
if (mi.optionalTarget != null) mi.optionalTarget.accept(this.cv);
|
||||
this.traverseInvocation(mi);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi) { this.traverseInvocation(smi); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLiteral(Java.Literal l) { this.traverseRvalue(l); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseIntegerLiteral(Java.IntegerLiteral il) { this.traverseLiteral(il); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFloatingPointLiteral(Java.FloatingPointLiteral fpl) { this.traverseLiteral(fpl); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBooleanLiteral(Java.BooleanLiteral bl) { this.traverseLiteral(bl); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseCharacterLiteral(Java.CharacterLiteral cl) { this.traverseLiteral(cl); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseStringLiteral(Java.StringLiteral sl) { this.traverseLiteral(sl); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNullLiteral(Java.NullLiteral nl) { this.traverseLiteral(nl); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSimpleLiteral(Java.SimpleConstant sl) { this.traverseRvalue(sl); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci) {
|
||||
if (naci.optionalQualification != null) naci.optionalQualification.accept((Visitor.RvalueVisitor) this.cv);
|
||||
naci.anonymousClassDeclaration.accept(this.cv);
|
||||
for (Java.Rvalue argument : naci.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(naci);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNewArray(Java.NewArray na) {
|
||||
na.type.accept((Visitor.TypeVisitor) this.cv);
|
||||
for (Rvalue dimExpr : na.dimExprs) dimExpr.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(na);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNewInitializedArray(Java.NewInitializedArray nia) {
|
||||
nia.arrayType.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseArrayInitializerOrRvalue(nia.arrayInitializer);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseArrayInitializerOrRvalue(Java.ArrayInitializerOrRvalue aiorv) {
|
||||
if (aiorv instanceof Java.Rvalue) {
|
||||
((Java.Atom) aiorv).accept(this.cv);
|
||||
} else
|
||||
if (aiorv instanceof Java.ArrayInitializer) {
|
||||
Java.ArrayInitializerOrRvalue[] values = ((Java.ArrayInitializer) aiorv).values;
|
||||
for (Java.ArrayInitializerOrRvalue value : values) this.traverseArrayInitializerOrRvalue(value);
|
||||
} else
|
||||
{
|
||||
throw new JaninoRuntimeException(
|
||||
"Unexpected array initializer or rvalue class "
|
||||
+ aiorv.getClass().getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNewClassInstance(Java.NewClassInstance nci) {
|
||||
if (nci.optionalQualification != null) nci.optionalQualification.accept((Visitor.RvalueVisitor) this.cv);
|
||||
if (nci.type != null) nci.type.accept((Visitor.TypeVisitor) this.cv);
|
||||
for (Java.Rvalue argument : nci.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(nci);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseParameterAccess(Java.ParameterAccess pa) { this.traverseRvalue(pa); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseQualifiedThisReference(Java.QualifiedThisReference qtr) {
|
||||
qtr.qualification.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseRvalue(qtr);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseThisReference(Java.ThisReference tr) { this.traverseRvalue(tr); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseArrayType(Java.ArrayType at) {
|
||||
at.componentType.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseType(at);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBasicType(Java.BasicType bt) { this.traverseType(bt); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseReferenceType(Java.ReferenceType rt) { this.traverseType(rt); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseRvalueMemberType(Java.RvalueMemberType rmt) {
|
||||
rmt.rvalue.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseType(rmt);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSimpleType(Java.SimpleType st) { this.traverseType(st); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci) {
|
||||
this.traverseConstructorInvocation(aci);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSuperConstructorInvocation(Java.SuperConstructorInvocation sci) {
|
||||
if (sci.optionalQualification != null) sci.optionalQualification.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseConstructorInvocation(sci);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAmbiguousName(Java.AmbiguousName an) { this.traverseLvalue(an); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseArrayAccessExpression(Java.ArrayAccessExpression aae) {
|
||||
aae.lhs.accept((Visitor.RvalueVisitor) this.cv);
|
||||
((Java.Atom) aae.index).accept(this.cv);
|
||||
this.traverseLvalue(aae);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFieldAccess(Java.FieldAccess fa) {
|
||||
fa.lhs.accept(this.cv);
|
||||
this.traverseLvalue(fa);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFieldAccessExpression(Java.FieldAccessExpression fae) {
|
||||
fae.lhs.accept(this.cv);
|
||||
this.traverseLvalue(fae);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae) {
|
||||
if (scfae.optionalQualification != null) scfae.optionalQualification.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseLvalue(scfae);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLocalVariableAccess(Java.LocalVariableAccess lva) { this.traverseLvalue(lva); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseParenthesizedExpression(Java.ParenthesizedExpression pe) {
|
||||
pe.value.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseLvalue(pe);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseElementValueArrayInitializer(Java.ElementValueArrayInitializer evai) {
|
||||
for (Java.ElementValue elementValue : evai.elementValues) elementValue.accept(this.cv);
|
||||
this.traverseElementValue(evai);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseElementValue(Java.ElementValue ev) {}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseSingleElementAnnotation(Java.SingleElementAnnotation sea) {
|
||||
sea.type.accept(this.cv);
|
||||
sea.elementValue.accept(this.cv);
|
||||
this.traverseAnnotation(sea);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAnnotation(Java.Annotation a) {}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNormalAnnotation(Java.NormalAnnotation na) {
|
||||
na.type.accept(this.cv);
|
||||
for (Java.ElementValuePair elementValuePair : na.elementValuePairs) {
|
||||
elementValuePair.elementValue.accept(this.cv);
|
||||
}
|
||||
this.traverseAnnotation(na);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseMarkerAnnotation(Java.MarkerAnnotation ma) {
|
||||
ma.type.accept(this.cv);
|
||||
this.traverseAnnotation(ma);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseClassDeclaration(Java.ClassDeclaration cd) {
|
||||
for (Java.ConstructorDeclarator ctord : cd.constructors) ctord.accept(this.cv);
|
||||
for (Java.BlockStatement vdoi : cd.variableDeclaratorsAndInitializers) vdoi.accept(this.cv);
|
||||
this.traverseAbstractTypeDeclaration(cd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAbstractTypeDeclaration(Java.AbstractTypeDeclaration atd) {
|
||||
for (Java.NamedTypeDeclaration mtd : atd.getMemberTypeDeclarations()) mtd.accept(this.cv);
|
||||
for (Java.MethodDeclarator md : atd.getMethodDeclarations()) this.traverseMethodDeclarator(md);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseNamedClassDeclaration(Java.NamedClassDeclaration ncd) {
|
||||
for (Java.Type implementedType : ncd.implementedTypes) implementedType.accept((Visitor.TypeVisitor) this.cv);
|
||||
if (ncd.optionalExtendedType != null) ncd.optionalExtendedType.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseClassDeclaration(ncd);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseInterfaceDeclaration(Java.InterfaceDeclaration id) {
|
||||
for (Java.TypeBodyDeclaration cd : id.constantDeclarations) cd.accept(this.cv);
|
||||
for (Java.Type extendedType : id.extendedTypes) extendedType.accept((Visitor.TypeVisitor) this.cv);
|
||||
this.traverseAbstractTypeDeclaration(id);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFunctionDeclarator(Java.FunctionDeclarator fd) {
|
||||
this.traverseFormalParameters(fd.formalParameters);
|
||||
if (fd.optionalStatements != null) {
|
||||
for (Java.BlockStatement bs : fd.optionalStatements) bs.accept(this.cv);
|
||||
}
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFormalParameters(Java.FunctionDeclarator.FormalParameters formalParameters) {
|
||||
for (Java.FunctionDeclarator.FormalParameter formalParameter : formalParameters.parameters) {
|
||||
this.traverseFormalParameter(formalParameter);
|
||||
}
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseFormalParameter(Java.FunctionDeclarator.FormalParameter formalParameter) {
|
||||
formalParameter.type.accept((Visitor.TypeVisitor) this.cv);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAbstractTypeBodyDeclaration(Java.AbstractTypeBodyDeclaration atbd) { this.traverseLocated(atbd); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseStatement(Java.Statement s) { this.traverseLocated(s); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBreakableStatement(Java.BreakableStatement bs) { this.traverseStatement(bs); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseContinuableStatement(Java.ContinuableStatement cs) { this.traverseBreakableStatement(cs); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseRvalue(Java.Rvalue rv) { this.traverseAtom(rv); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseBooleanRvalue(Java.BooleanRvalue brv) { this.traverseRvalue(brv); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseInvocation(Java.Invocation i) {
|
||||
for (Java.Rvalue argument : i.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseRvalue(i);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseConstructorInvocation(Java.ConstructorInvocation ci) {
|
||||
for (Java.Rvalue argument : ci.arguments) argument.accept((Visitor.RvalueVisitor) this.cv);
|
||||
this.traverseAtom(ci);
|
||||
}
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLvalue(Java.Lvalue lv) { this.traverseRvalue(lv); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseType(Java.Type t) { this.traverseAtom(t); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseAtom(Java.Atom a) { this.traverseLocated(a); }
|
||||
|
||||
/** @see Traverser */
|
||||
public void
|
||||
traverseLocated(Java.Located l) {}
|
||||
}
|
126
src/org/codehaus/janino/util/enumerator/Enumerator.java
Normal file
126
src/org/codehaus/janino/util/enumerator/Enumerator.java
Normal file
|
@ -0,0 +1,126 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.enumerator;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class that represents an enumerated value. Its main features are its {@link #toString()} and
|
||||
* {@link #fromString(String, Class)} method, which map names to values and vice versa.
|
||||
* <p>
|
||||
* To use this class, derive from it and define one or more
|
||||
* <code>public static final</code> fields, as follows:
|
||||
* <pre>
|
||||
* public final class Suit extends Enumerator {
|
||||
*
|
||||
* // Exactly N instances of "Suit" exist to represent the N possible values.
|
||||
* public static final Suit CLUBS = new Suit("clubs");
|
||||
* public static final Suit DIAMONDS = new Suit("diamonds");
|
||||
* public static final Suit HEARTS = new Suit("hearts");
|
||||
* public static final Suit SPADES = new Suit("spades");
|
||||
*
|
||||
* // Optional, if you want to use EumeratorSet arithmetics.
|
||||
* public static final EnumeratorSet NONE = new EnumeratorSet(Suit.class ).setName("none");
|
||||
* public static final EnumeratorSet ALL = new EnumeratorSet(Suit.class, true).setName("all");
|
||||
*
|
||||
* // These MUST be declared exactly like this:
|
||||
* private Suit(String name) { super(name); }
|
||||
* public static Suit fromString(String name) throws EnumeratorFormatException {
|
||||
* return (Suit) Enumerator.fromString(name, Suit.class);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="http://java.sun.com/developer/Books/effectivejava/Chapter5.pdf">Effective Java, Item 21</a>
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public abstract
|
||||
class Enumerator {
|
||||
|
||||
private final String name;
|
||||
|
||||
private static final Map<Class /*enumeratorClass*/, Map<String /*name*/, Enumerator>>
|
||||
INSTANCES = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
/** Initialize the enumerator to the given value. */
|
||||
protected
|
||||
Enumerator(String name) {
|
||||
if (name == null) throw new NullPointerException();
|
||||
this.name = name;
|
||||
|
||||
((Map<String /*name*/, Enumerator>) Enumerator.getInstances(this.getClass())).put(name, this);
|
||||
}
|
||||
|
||||
/** Equality is reference identity. */
|
||||
@Override public final boolean
|
||||
equals(Object that) { return this == that; }
|
||||
|
||||
/** Enforce {@link Object}'s notion of {@link Object#hashCode()}. */
|
||||
@Override public final int
|
||||
hashCode() { return super.hashCode(); }
|
||||
|
||||
/** Returns a mapping of name to Enumerator for the given enumeratorClass. */
|
||||
static Map<String /*name*/, Enumerator>
|
||||
getInstances(Class enumeratorClass) {
|
||||
Map<String /*name*/, Enumerator> m = (Map) Enumerator.INSTANCES.get(enumeratorClass);
|
||||
if (m != null) return m;
|
||||
|
||||
// The map need not be synchronized because it is modified only during initialization
|
||||
// of the Enumerator.
|
||||
m = new HashMap();
|
||||
Enumerator.INSTANCES.put(enumeratorClass, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize an {@link Enumerator} from a string.
|
||||
* <p>
|
||||
* The given string is converted into a value by looking at all instances of the given type
|
||||
* created so far.
|
||||
* <p>
|
||||
* Derived classes should invoke this method as follows:<pre>
|
||||
* public class Suit extends Enumerator {
|
||||
* ...
|
||||
* public static Suit fromString(String name) throws EnumeratorFormatException {
|
||||
* return (Suit) Enumerator.fromString(name, Suit.class);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @throws EnumeratorFormatException if the string cannot be identified
|
||||
*/
|
||||
protected static final Enumerator
|
||||
fromString(String name, Class enumeratorClass) throws EnumeratorFormatException {
|
||||
Enumerator value = (Enumerator) Enumerator.getInstances(enumeratorClass).get(name);
|
||||
if (value == null) throw new EnumeratorFormatException(name);
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Returns the <code>name</code> passed to {@link #Enumerator(String)}. */
|
||||
@Override public String
|
||||
toString() { return this.name; }
|
||||
}
|
|
@ -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); }
|
||||
}
|
28
src/org/codehaus/janino/util/enumerator/package-info.java
Normal file
28
src/org/codehaus/janino/util/enumerator/package-info.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2013, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** {@link org.codehaus.janino.util.enumerator.Enumerator}-related utility classes. */
|
||||
package org.codehaus.janino.util.enumerator;
|
133
src/org/codehaus/janino/util/iterator/DirectoryIterator.java
Normal file
133
src/org/codehaus/janino/util/iterator/DirectoryIterator.java
Normal file
|
@ -0,0 +1,133 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.iterator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.janino.JaninoRuntimeException;
|
||||
import org.codehaus.janino.util.Producer;
|
||||
|
||||
/**
|
||||
* An {@link Iterator} that finds the normal {@link File}s who's names are
|
||||
* {@link FilenameFilter#accept(java.io.File, java.lang.String) accepted} by the
|
||||
* <code>fileNameFilter</code> and
|
||||
* <ul>
|
||||
* <li>
|
||||
* that exist in the given <code>rootDirectory</code>,
|
||||
* </li>
|
||||
* <li>
|
||||
* and those that exist in all subdirectories of the
|
||||
* <code>rootDirectory</code> who's names are
|
||||
* {@link FilenameFilter#accept(java.io.File, java.lang.String)}ed by the
|
||||
* <code>directoryNameFilter</code>
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class DirectoryIterator extends ProducerIterator<File> {
|
||||
public
|
||||
DirectoryIterator(
|
||||
final File rootDirectory,
|
||||
final FilenameFilter directoryNameFilter,
|
||||
final FilenameFilter fileNameFilter
|
||||
) {
|
||||
super(new Producer() {
|
||||
private final List<State> stateStack = DirectoryIterator.newArrayList(new State(rootDirectory));
|
||||
|
||||
@Override public Object
|
||||
produce() {
|
||||
while (!this.stateStack.isEmpty()) {
|
||||
State state = (State) this.stateStack.get(this.stateStack.size() - 1);
|
||||
if (state.directories.hasNext()) {
|
||||
this.stateStack.add(new State((File) state.directories.next()));
|
||||
} else
|
||||
if (state.files.hasNext()) {
|
||||
File file = (File) state.files.next();
|
||||
return file;
|
||||
} else
|
||||
{
|
||||
this.stateStack.remove(this.stateStack.size() - 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class State {
|
||||
State(File dir) {
|
||||
File[] entries = dir.listFiles();
|
||||
if (entries == null) {
|
||||
throw new JaninoRuntimeException("Directory \"" + dir + "\" could not be read");
|
||||
}
|
||||
List<File> directoryList = new ArrayList();
|
||||
List<File> fileList = new ArrayList();
|
||||
for (File entry : entries) {
|
||||
if (entry.isDirectory()) {
|
||||
if (directoryNameFilter.accept(dir, entry.getName())) directoryList.add(entry);
|
||||
} else
|
||||
if (entry.isFile()) {
|
||||
if (fileNameFilter.accept(dir, entry.getName())) fileList.add(entry);
|
||||
}
|
||||
}
|
||||
this.directories = directoryList.iterator();
|
||||
this.files = fileList.iterator();
|
||||
}
|
||||
final Iterator<File> directories;
|
||||
final Iterator<File> files;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link Iterator} that returns all matching {@link File}s locatable in a <i>set</i> of root
|
||||
* directories.
|
||||
*
|
||||
* @see #DirectoryIterator(File, FilenameFilter, FilenameFilter)
|
||||
*/
|
||||
public static Iterator<File>
|
||||
traverseDirectories(
|
||||
File[] rootDirectories,
|
||||
FilenameFilter directoryNameFilter,
|
||||
FilenameFilter fileNameFilter
|
||||
) {
|
||||
List<Iterator<File>> result = new ArrayList();
|
||||
for (File rootDirectory : rootDirectories) {
|
||||
result.add(new DirectoryIterator(rootDirectory, directoryNameFilter, fileNameFilter));
|
||||
}
|
||||
return new MultiDimensionalIterator(result.iterator(), 2);
|
||||
}
|
||||
|
||||
private static ArrayList
|
||||
newArrayList(Object initialElement) {
|
||||
ArrayList result = new ArrayList();
|
||||
result.add(initialElement);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -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"); }
|
||||
}
|
48
src/org/codehaus/janino/util/iterator/FilterIterator.java
Normal file
48
src/org/codehaus/janino/util/iterator/FilterIterator.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.iterator;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An {@link java.util.Iterator} that retrieves its elements from a delegate {@link java.util.Iterator}. The default
|
||||
* implementation simply passes all method invocations to the delegate.
|
||||
*
|
||||
* @param <T> The element type of the iterator
|
||||
*/
|
||||
public abstract
|
||||
class FilterIterator<T> implements Iterator<T> {
|
||||
|
||||
/** @see FilterIterator */
|
||||
protected final Iterator<T> delegate;
|
||||
|
||||
public FilterIterator(Iterator<T> delegate) { this.delegate = delegate; }
|
||||
|
||||
@Override public boolean hasNext() { return this.delegate.hasNext(); }
|
||||
@Override public T next() { return this.delegate.next(); }
|
||||
@Override public void remove() { this.delegate.remove(); }
|
||||
}
|
|
@ -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"); }
|
||||
}
|
69
src/org/codehaus/janino/util/iterator/ProducerIterator.java
Normal file
69
src/org/codehaus/janino/util/iterator/ProducerIterator.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.iterator;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.codehaus.janino.util.Producer;
|
||||
|
||||
/**
|
||||
* An {@link Iterator} that iterates over all the objects produced by a delegate {@link Producer}.
|
||||
*
|
||||
* @param <T> The type of the products and the iterator elements
|
||||
* @see Producer
|
||||
*/
|
||||
public
|
||||
class ProducerIterator<T> implements Iterator<T> {
|
||||
|
||||
private final Producer<T> producer;
|
||||
|
||||
private static final Object UNKNOWN = new Object();
|
||||
private static final Object AT_END = null;
|
||||
private Object nextElement = ProducerIterator.UNKNOWN;
|
||||
|
||||
public
|
||||
ProducerIterator(Producer<T> producer) { this.producer = producer; }
|
||||
|
||||
@Override public boolean
|
||||
hasNext() {
|
||||
if (this.nextElement == ProducerIterator.UNKNOWN) this.nextElement = this.producer.produce();
|
||||
return this.nextElement != ProducerIterator.AT_END;
|
||||
}
|
||||
|
||||
@Override public T
|
||||
next() {
|
||||
if (this.nextElement == ProducerIterator.UNKNOWN) this.nextElement = this.producer.produce();
|
||||
if (this.nextElement == ProducerIterator.AT_END) throw new NoSuchElementException();
|
||||
@SuppressWarnings("unchecked") T result = (T) this.nextElement;
|
||||
this.nextElement = ProducerIterator.UNKNOWN;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public void
|
||||
remove() { throw new UnsupportedOperationException("remove"); }
|
||||
}
|
|
@ -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);
|
||||
}
|
103
src/org/codehaus/janino/util/iterator/TraversingIterator.java
Normal file
103
src/org/codehaus/janino/util/iterator/TraversingIterator.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.iterator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* An {@link java.util.Iterator} that iterates over a delegate, and while it encounters an array, a {@link
|
||||
* java.util.Collection}, an {@link java.util.Enumeration} or a {@link java.util.Iterator} element, it iterates over it
|
||||
* recursively.
|
||||
* <p>
|
||||
* Be aware that {@link #hasNext()} must read ahead one element.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class TraversingIterator implements Iterator {
|
||||
private final Stack nest = new Stack(); // Iterator
|
||||
private Object nextElement;
|
||||
private boolean nextElementRead; // Have we read ahead?
|
||||
|
||||
public
|
||||
TraversingIterator(Iterator delegate) { this.nest.push(delegate); }
|
||||
|
||||
@Override public boolean
|
||||
hasNext() { return this.nextElementRead || this.readNext(); }
|
||||
|
||||
@Override public Object
|
||||
next() {
|
||||
if (!this.nextElementRead && !this.readNext()) throw new NoSuchElementException();
|
||||
this.nextElementRead = false;
|
||||
return this.nextElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next element and stores it in {@link #nextElement}.
|
||||
* @return <code>false</code> if no more element can be read.
|
||||
*/
|
||||
private boolean
|
||||
readNext() {
|
||||
while (!this.nest.empty()) {
|
||||
Iterator it = (Iterator) this.nest.peek();
|
||||
if (!it.hasNext()) {
|
||||
this.nest.pop();
|
||||
continue;
|
||||
}
|
||||
Object o = it.next();
|
||||
if (o instanceof Iterator) {
|
||||
this.nest.push(o);
|
||||
} else
|
||||
if (o instanceof Object[]) {
|
||||
this.nest.push(Arrays.asList((Object[]) o).iterator());
|
||||
} else
|
||||
if (o instanceof Collection) {
|
||||
this.nest.push(((Collection) o).iterator());
|
||||
} else
|
||||
if (o instanceof Enumeration) {
|
||||
this.nest.push(new EnumerationIterator((Enumeration) o));
|
||||
} else
|
||||
{
|
||||
this.nextElement = o;
|
||||
this.nextElementRead = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException iff the {@link Iterator} currently being
|
||||
* traversed doesn't support element removal
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
@Override public void
|
||||
remove() { ((Iterator) this.nest.peek()).remove(); }
|
||||
}
|
|
@ -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() {}
|
||||
}
|
28
src/org/codehaus/janino/util/iterator/package-info.java
Normal file
28
src/org/codehaus/janino/util/iterator/package-info.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2013, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** Some generic {@link java.util.Iterator}-related helper classes. */
|
||||
package org.codehaus.janino.util.iterator;
|
28
src/org/codehaus/janino/util/package-info.java
Normal file
28
src/org/codehaus/janino/util/package-info.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2013, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** Application-independent helper classes. */
|
||||
package org.codehaus.janino.util;
|
|
@ -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;
|
||||
}
|
||||
}
|
50
src/org/codehaus/janino/util/resource/FileResource.java
Normal file
50
src/org/codehaus/janino/util/resource/FileResource.java
Normal 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; }
|
||||
}
|
60
src/org/codehaus/janino/util/resource/MapResourceFinder.java
Normal file
60
src/org/codehaus/janino/util/resource/MapResourceFinder.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.resource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@link org.codehaus.janino.util.resource.ResourceFinder} that provides access
|
||||
* to resource stored as byte arrays in a {@link java.util.Map}.
|
||||
*/
|
||||
public
|
||||
class MapResourceFinder extends ResourceFinder {
|
||||
private final Map<String, byte[]> map;
|
||||
private long lastModified;
|
||||
|
||||
public
|
||||
MapResourceFinder(Map<String, byte[]> map) { this.map = map; }
|
||||
|
||||
/** @param lastModified The return value of {@link Resource#lastModified()} for the next resources found */
|
||||
public final void
|
||||
setLastModified(long lastModified) { this.lastModified = lastModified; }
|
||||
|
||||
@Override public final Resource
|
||||
findResource(final String resourceName) {
|
||||
final byte[] ba = (byte[]) this.map.get(resourceName);
|
||||
if (ba == null) return null;
|
||||
|
||||
return new Resource() {
|
||||
@Override public InputStream open() { return new ByteArrayInputStream(ba); }
|
||||
@Override public String getFileName() { return resourceName; }
|
||||
@Override public long lastModified() { return MapResourceFinder.this.lastModified; }
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
136
src/org/codehaus/janino/util/resource/PathResourceFinder.java
Normal file
136
src/org/codehaus/janino/util/resource/PathResourceFinder.java
Normal file
|
@ -0,0 +1,136 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.codehaus.janino.util.iterator.TransformingIterator;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link org.codehaus.janino.util.resource.ResourceFinder} that finds its resources along a "path"
|
||||
* consisting of JAR file names, ZIP file names, and directory names.
|
||||
* @see org.codehaus.janino.util.resource.ZipFileResourceFinder
|
||||
* @see org.codehaus.janino.util.resource.DirectoryResourceFinder
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) public
|
||||
class PathResourceFinder extends LazyMultiResourceFinder {
|
||||
|
||||
/** @param entries The entries of the "path" */
|
||||
public
|
||||
PathResourceFinder(final File[] entries) {
|
||||
super(PathResourceFinder.createIterator(Arrays.asList(entries).iterator()));
|
||||
}
|
||||
|
||||
/** @param entries The entries of the "path" (type must be {@link File}) */
|
||||
public
|
||||
PathResourceFinder(Iterator<ResourceFinder> entries) { super(entries); }
|
||||
|
||||
/** @param path A java-like path, i.e. a "path separator"-separated list of entries. */
|
||||
public
|
||||
PathResourceFinder(String path) { this(PathResourceFinder.parsePath(path)); }
|
||||
|
||||
private static Iterator<ResourceFinder>
|
||||
createIterator(final Iterator<File> entries) {
|
||||
return new TransformingIterator/*<File, ResourceFinder>*/(entries) {
|
||||
@Override protected Object transform(Object o) { return PathResourceFinder.createResourceFinder((File) o); }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a given string up by the system-dependent path-separator character (on UNIX systems,
|
||||
* this character is ':'; on Microsoft Windows systems it is ';'). Empty components are
|
||||
* ignored.
|
||||
* <p>
|
||||
* UNIX Examples:
|
||||
* <dl>
|
||||
* <dt>A:B:C <dd>A, B, C
|
||||
* <dt>::B: <dd>B
|
||||
* <dt>:A <dd>A
|
||||
* <dt>(Empty string) <dd>(Zero components)
|
||||
* </dl>
|
||||
*
|
||||
* @see File#pathSeparatorChar
|
||||
*/
|
||||
public static File[]
|
||||
parsePath(String s) {
|
||||
int from = 0;
|
||||
List<File> l = new ArrayList();
|
||||
for (;;) {
|
||||
int to = s.indexOf(File.pathSeparatorChar, from);
|
||||
if (to == -1) {
|
||||
if (from != s.length()) l.add(new File(s.substring(from)));
|
||||
break;
|
||||
}
|
||||
if (to != from) l.add(new File(s.substring(from, to)));
|
||||
from = to + 1;
|
||||
}
|
||||
return (File[]) l.toArray(new File[l.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory method that creates a Java classpath-style ResourceFinder as
|
||||
* follows:
|
||||
* <table>
|
||||
* <tr><th><code>entry</code></th><th>Returned {@link ResourceFinder}</th></tr>
|
||||
* <tr><td>"*.jar" file</td><td>{@link ZipFileResourceFinder}</td></tr>
|
||||
* <tr><td>"*.zip" file</td><td>{@link ZipFileResourceFinder}</td></tr>
|
||||
* <tr><td>directory</td><td>{@link DirectoryResourceFinder}</td></tr>
|
||||
* <tr><td>any other</td><td>A {@link ResourceFinder} that never finds a resource</td></tr>
|
||||
* </table>
|
||||
* @return a valid {@link ResourceFinder}
|
||||
*/
|
||||
private static ResourceFinder
|
||||
createResourceFinder(final File entry) {
|
||||
|
||||
// ZIP file or JAR file.
|
||||
if (
|
||||
(entry.getName().endsWith(".jar") || entry.getName().endsWith(".zip"))
|
||||
&& entry.isFile()
|
||||
) {
|
||||
try {
|
||||
return new ZipFileResourceFinder(new ZipFile(entry));
|
||||
} catch (IOException e) {
|
||||
return ResourceFinder.EMPTY_RESOURCE_FINDER;
|
||||
}
|
||||
}
|
||||
|
||||
// Directory.
|
||||
if (entry.isDirectory()) {
|
||||
return new DirectoryResourceFinder(entry);
|
||||
}
|
||||
|
||||
// Invalid entry.
|
||||
return ResourceFinder.EMPTY_RESOURCE_FINDER;
|
||||
}
|
||||
}
|
64
src/org/codehaus/janino/util/resource/Resource.java
Normal file
64
src/org/codehaus/janino/util/resource/Resource.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link Resource} is "something" that is typically found by a
|
||||
* {@link org.codehaus.janino.util.resource.ResourceFinder}, can be {@link #open()}ed for
|
||||
* reading, and optionally has a {@link #lastModified()} property.
|
||||
* <p>
|
||||
* There also exists a {@link org.codehaus.janino.util.resource.ResourceCreator} concept which
|
||||
* opens a resource for writing, but that happens directly and not through an intermediate
|
||||
* {@link Resource} object.
|
||||
*
|
||||
* @see org.codehaus.janino.util.resource.ResourceFinder
|
||||
* @see org.codehaus.janino.util.resource.ResourceCreator
|
||||
*/
|
||||
public
|
||||
interface Resource {
|
||||
|
||||
/** Opens the resource. The caller is responsible for closing the {@link java.io.InputStream}. */
|
||||
InputStream open() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a decorative "file name" that can be used for reporting
|
||||
* errors and the like. It does not necessarily map to a file in the
|
||||
* local file system!
|
||||
*/
|
||||
String getFileName();
|
||||
|
||||
/**
|
||||
* Returns the time of the last modification, in milliseconds since
|
||||
* 1970, or <code>0L</code> if the time of the last modification cannot
|
||||
* be determined.
|
||||
*/
|
||||
long lastModified();
|
||||
}
|
59
src/org/codehaus/janino/util/resource/ResourceCreator.java
Normal file
59
src/org/codehaus/janino/util/resource/ResourceCreator.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
/*
|
||||
* Janino - An embedded Java[TM] compiler
|
||||
*
|
||||
* Copyright (c) 2001-2010, Arno Unkrig
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.codehaus.janino.util.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Opens a resource, characterized by a name, for writing.
|
||||
* <p>
|
||||
* There also exists a concept {@link org.codehaus.janino.util.resource.ResourceFinder} that
|
||||
* finds {@link org.codehaus.janino.util.resource.Resource}s for reading.
|
||||
*
|
||||
* @see org.codehaus.janino.util.resource.ResourceFinder
|
||||
*/
|
||||
public
|
||||
interface ResourceCreator {
|
||||
|
||||
/**
|
||||
* Create the designated resource.
|
||||
*
|
||||
* @param resourceName Designates the resource; typically structured by slashes ("/") like
|
||||
* "<code>com/foo/pkg/Bar.class</code>"
|
||||
* @return Bytes written to this {@link OutputStream} are stored in the resource
|
||||
* @throws IOException Problems creating the resource
|
||||
*/
|
||||
OutputStream createResource(String resourceName) throws IOException;
|
||||
|
||||
/**
|
||||
* Deletes the resource with the given name.
|
||||
*
|
||||
* @return <code>false</code> if the resource could not be deleted
|
||||
*/
|
||||
boolean deleteResource(String resourceName);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user